Interactive threshold method in python

Hi All,

In my script I would like that the user can choose a threshold method in a specific list (not the complete one that you can find in the menu Threshold… ) and instead of waiting for the user to push the OK button, I would like that the image is updated dynamically, in response to user input. It is quite similar to the Threshold window but without the histogram and with a shorter list of threshold method. For that I have created a class as follow:

from ij import WindowManager as WM 
from ij.process import ImageProcessor, ImageStatistics, AutoThresholder
from ij.gui import GenericDialog
from java.awt.event import ItemListener 
       
class ThresholdPreviewer(ItemListener):  
	def __init__(self, imp, choice):  
		self.imp = imp   
		self.ip = imp.getProcessor()
                self.choice = choice   
		

	def itemStateChanged(self, event):  
		if event.getStateChange() == event.SELECTED:  
			print "Threshold method", event.getItem()
			self.threshold()  
			
	def reset(self):  
		self.imp.setProcessor(self.ip)  
		
	def threshold(self):   
		new_ip = self.ip.duplicate()
		stats = new_ip.getStatistics() 
		thresholder = AutoThresholder()
		threshold = thresholder.getThreshold(self.choice, stats.histogram)
		new_ip.setThreshold(threshold, True, ImageProcessor.RED_LUT) 
		self.imp.setProcessor(new_ip)   


thresholdingMethod = ["MaxEntropy","Intermodes", "RenyiEntropy", "Yen"]
imp = WM.getCurrentImage() 

gd = GenericDialog("Threshold")
gd.addChoice("Choose your desired threshold", thresholdingMethod, thresholdingMethod[0])
choice = gd.getChoices().get(0)
previewer = ThresholdPreviewer(imp,choice)  
choice.addItemListener(previewer)  

gd.showDialog()  

if gd.wasCanceled():  
	previewer.reset()  
	print "User canceled dialog!"  
else:  
	previewer.threshold()

But it is not updating anything. I have missed something but I do not see what … Could you help me with that…

thanks by advance

Hi all,

I found a solution and I have noticed that for a stack I cannot have access to the slider that controls the # of Slice. For this reason I have decide to add a slider in the dialog.
Here is my solution. Tell me if there is a simplest way to do it.

from ij import WindowManager as WM  
from ij import IJ, ImagePlus
from ij.process import ImageProcessor, AutoThresholder
from ij.gui import GenericDialog, NonBlockingGenericDialog, WaitForUserDialog
from java.awt.event import AdjustmentListener, ItemListener  
  

## threshold class
class ThresholdPreviewer(AdjustmentListener, ItemListener):  
	def __init__(self, imp, slider, choice):  
		self.imp = imp   
		self.currentSlice = imp.getCurrentSlice()
		self.slider = slider 
		self.choice = choice   
		
	def adjustmentValueChanged(self, event):   
		slice =  event.getValue()
		if not slice == self.currentSlice:
			self.threshold()   

	def itemStateChanged(self, event):  
		if event.getStateChange() == event.SELECTED:  
			self.threshold()  
			
	def reset(self):  
		IJ.resetThreshold(self.imp)
		
	def threshold(self):   
		self.imp.setSlice(self.slider.getValue())
		IJ.setAutoThreshold(self.imp, self.choice.getSelectedItem() +" dark")


thresholdingMethod = ["MaxEntropy","Intermodes", "RenyiEntropy", "Yen"]
imp = WM.getCurrentImage() 

gd = GenericDialog("Threshold")
gd.addSlider("Slice", 1, imp.getStackSize(), 1)    
gd.addChoice("Choose your desired threshold", thresholdingMethod, thresholdingMethod[0])
slider = gd.getSliders().get(0) 
choice = gd.getChoices().get(0)
previewer = ThresholdPreviewer(imp, slider, choice)  
slider.addAdjustmentListener(previewer)  
choice.addItemListener(previewer)  

gd.showDialog()  

cheers

1 Like

Hi all,

in fact I have decided not to choose a threshold method but to let the user to select the min threshold. Here is the code

from ij import WindowManager as WM  
from ij import IJ, ImagePlus, ImageStack
from ij.process import ImageProcessor, ImageStatistics
from ij.gui import GenericDialog
from java.awt.event import AdjustmentListener

#### Class
class ThresholdPreviewer(AdjustmentListener):  
	def __init__(self, imp, sliders):  
		self.imp = imp   
		self.currentSlice = imp.getCurrentSlice()
		self.sliders = sliders  
		self.threshold()
		
	def adjustmentValueChanged(self, event):  
		self.threshold()   
			
	def reset(self):  
		IJ.resetThreshold(self.imp) 
		
	def threshold(self):
		slice =  self.sliders.get(0).getValue()  
		self.imp.setSlice(slice)
		IJ.setThreshold(self.imp, self.sliders.get(1).getValue() ,self.stack.getProcessor(slice).getMax())
	
	def getMinThreshold(self) :
		return self.sliders.get(1).getValue()
##### End of Class

### Functions
def Threshold_Cumsum(imp_, perc_):
	val_ =1-perc_/100
	stack_ = imp_.getStack()
	threshArray = []
	for i in range(imp_.getStackSize()):
		ip_ = stack_.getProcessor(i+1)
		ipStat_ = ip_.getStatistics() 
		hist_ = ipStat_.getHistogram() 
		#find culmulative sum
		cumSum = []
		cumSum.append(hist_[0])
		for j in range(1,len(hist_)) :
 			cumSum.append(hist_[j]+cumSum[j-1])
 		j=0
 		while (cumSum[j]<val_*cumSum[len(hist_)-1]) : 
			j+=1
		threshArray.append(int(round(j*ipStat_.binSize +ipStat_.min)))
	return sum(threshArray)/len(threshArray)

# Generic Dialog for threshold method
def thresholdImageUI(imp_,perc_):  
	upper = Threshold_Cumsum(imp_,perc_)
	gd = GenericDialog("Threshold")
	gd.addSlider("Slice", 1, imp_.getStackSize(), int(imp_.getStackSize()/2))
	gd.addSlider("Threshold", 0, 1.2 * upper, upper)
	sliders = gd.getSliders()
	previewer = ThresholdPreviewer(imp_, sliders)  
	for slider in sliders :
		slider.addAdjustmentListener(previewer)  

	gd.showDialog()  

	if gd.wasOKed():  
		minThreshold = previewer.getMinThreshold()
		IJ.setRawThreshold(imp_, minThreshold, 1e30, None)
	IJ.run(imp_, "NaN Background", "stack")	
	return

### End of Functions

imp = WM.getCurrentImage()
thresholdImageUI(imp, 0.04)	

I hope this code can help someone… This code works for a 32 bit image and “upper” is an estimation of the min threshold based on cumulative distribution.

regards

1 Like