Question

Implementing image thresholding (Otsu's method) with PythonCaller

  • 14 December 2022
  • 1 reply
  • 31 views

Hello!  I'm trying to implement Otsu's method of image thresholding on an incoming raster, using the PythonCaller transformer.  I  have the following code block in the PythonCaller parameters, although my Python isn't great, so there may well be issues with it:

import fme
import fmeobjects
import numpy as np
class OtsuThreshold(object):
    def __init__(self):
        pass
    def input(self, feature):
        #implement Otsu thresholding in native Python with numpy
        #get the image from the feature
        image = feature.getAttribute('image')
        #compute the histogram of the image, then find the peak of the histogram
 
        hist = np.histogram(image, bins=256, range=(0, 256))
        
        maxVal = np.max(hist[0])
        maxLoc = np.argmax(hist[0])
        #perform Otsu thresholding
        T = maxLoc
        thresh = np.where(image > T, 255, 0)
        #set the attribute value
        feature.setAttribute('image', thresh)
        #pass the feature on to the next transformer
        self.pyoutput(feature)

I am getting this error, seemingly within histograms.py within numpy itself:

Python Exception <TypeError>: '>=' not supported between instances of 'NoneType' and 'int'

A little digging hints that this may indicate that the raster is being read as None values, which I can seemingly confirm by inserting the following before the "hist" array:

        if image is None or len(image) == 0:
            # handle empty image
            # for example, you could return an empty feature
            return

This is where I hit a dead end though. 

Ideally I would like to return the actual Otsu threshold pixel value itself as an attribute, although I don't think my script it currently capable of that.

Thank you!

 


1 reply

Userlevel 3
Badge +26

I don't have any experience working with raster data in python, so take this with a grain of salt....

 

It appears your raster is stored on an attribute, so it's possible that you are attempting the raster calculations on binary data instead of the actual raster. I would consider using a RasterReplacer prior to the PythonCaller to extract the raster from the attribute as the feature geometry, and then perform the Otsu processing on that.  

Reply