Jython "enhance contrast" function does not apply

Hi,

I am currently writting a Jython script using the enhance contrast function. However this function does not apply on my pictures. I also simply tried to use this function on my picture using simple macro language, and still it does not work. It changes pixel vallues but does not properly enhance contrast as I want.
The goal is to get the same enhancement as Image-> Adjust -> Brightness/Contrast -> Auto.

Do some of you have ideas about how to make it work or if you have alternatives to spread my gray value on the whole gray scale ?

Here is the beginning of my script :

import os
import sys
from ij.io import DirectoryChooser
from loci.plugins.in import ImagePlusReader,ImporterOptions,ImportProcess
from ij.gui import WaitForUserDialog
from ij.plugin.frame import RoiManager
from ij.plugin import ImageCalculator, ChannelSplitter
from ij.gui import Roi, GenericDialog
from ij.process import ImageStatistics as IS  
from ij import IJ, ImagePlus, WindowManager as WM


def getOptions():  
  gd = GenericDialog("Intensity Ratio Green/Red")  
  gd.addNumericField("Ratio", 0.25, 2)  # show 2 decimals  
  gd.showDialog()  
  if gd.wasCanceled():  
    print "User canceled dialog!"  
    return  
  # Read out the options  
  ratio = gd.getNextNumber()  
  return ratio  
options = getOptions()  
if options is not None:
	ratio=options

waitFLIM = WaitForUserDialog ("Waiting", "Select FLIM picture")
waitFLIM.show()
impflimwmi = WM.getCurrentWindow()
impflimi = WM.getCurrentImage() 
waitCA = WaitForUserDialog ("Waiting", "Select C1 picture")
waitCA.show()
impca = WM.getCurrentImage()
waitCB = WaitForUserDialog ("Waiting", "Select C2 picture")
waitCB.show()
impcb =  WM.getCurrentImage()


impflims=ChannelSplitter.split(impflimi)
impflims[0].show()
impflim=WM.getCurrentImage()
impflimwm=WM.getCurrentWindow()
impflimwmi.close()
impflim.setSlice(1)
IJ.run(impflim, "Delete Slice", "delete=stack")
impflim.setSlice(2)
IJ.run(impflim, "Delete Slice", "delete=stack")
impflim.setSlice(2)
IJ.run(impflim, "Delete Slice", "delete=stack")
impflim.setSlice(2)
IJ.run(impflim, "Delete Slice", "delete=stack")
impflim.setSlice(1)
IJ.run(impflim, "Enhance Contrast...", "saturated=0.35")

Thank you !
Yours
Virgile

Hello Virgile -

IJ.run(imp, "Enhance Contrast...", "saturated=0.35")

works for me.

One point to note is that “Enhance…” and “Adjust…” work
a little bit differently. “Enhance…” changes the display
range of the ImagePlus, while “Adjust…” changes the
values of the pixels stored in the ImagePlus's
ImageProcessor. So if you’re expecting “Enhance…” to
change the actual pixels values, it won’t do that (without
further processing).

This jython script illustrates the behavior of “Enhance…”
and how it differs from that of “Adjust…”:

from ij import IJ
from ij.gui import WaitForUserDialog

# open blobs sample image
IJ.run ('Blobs (25K)')
imp = IJ.getImage()

# and reduce its contrast
ip = imp.getProcessor()
ip.multiply (0.5)
imp.setTitle ('blobs_div2')

# make a duplicate
impenh = imp.duplicate()
impenh.setTitle ('blobs_div2_enh')
impenh.show()

# run "Enhance Contrast..."
IJ.run(impenh, "Enhance Contrast...", "saturated=0.35")

# for comparison, make another duplicate
impadj = imp.duplicate()
impadj.setTitle ('blobs_div2_adj')
impadj.show()

# and run "Adjust Brightness/Contrast" -- needs some user clicks
IJ.selectWindow ('blobs_div2_adj')
IJ.run ('Brightness/Contrast...')
WaitForUserDialog ('Mouse clicks needed!', 'Click "Auto" and "Apply" in "B&C" window').show()
IJ.selectWindow ('B&C')
IJ.run ('Close')

# compare pixel values
print 'imp: getPixel (65, 40) =', imp.getProcessor().getPixel (65, 40)
print 'enh: getPixel (65, 40) =', impenh.getProcessor().getPixel (65, 40)
print 'adj: getPixel (65, 40) =', impadj.getProcessor().getPixel (65, 40)

# compare display ranges
print 'imp: getDisplayRangeMin,Max() =', imp.getDisplayRangeMin(), imp.getDisplayRangeMax()
print 'enh: getDisplayRangeMin,Max() =', impenh.getDisplayRangeMin(), impenh.getDisplayRangeMax()
print 'adj: getDisplayRangeMin,Max() =', impadj.getDisplayRangeMin(), impadj.getDisplayRangeMax()

# save as .tifs
IJ.saveAsTiff (imp, 'blobs_div2')
IJ.saveAsTiff (impenh, 'blobs_div2_enh')
IJ.saveAsTiff (impadj, 'blobs_div2_adj')

You see that the value of the x = 65, y = 40 pixel of the
original blobs_div2 image is 104. Running “Enhance…”
doesn’t change this pixel value, but reduces the display range
to [8, 124] (from [0, 255]). In contrast, running “Adjust…”
changes that pixel value to 213, but leaves the display range
at [0, 255].

Here are the resulting images, saved as .tifs to preserve the
display-range information:

blobs_div2.tif (65.2 KB)

blobs_div2_enh.tif (65.2 KB)

blobs_div2_adj.tif (65.2 KB)

Note that when you open the “Enhance…” image, blobs_div2_enh.tif,
with Fiji / ImageJ, the display range is taken into account, and
the image will be displayed with the expected enhanced contrast.
Other image viewers may or may not use the display range and
show the enhanced contrast.

(Fun Fiji Fact: If you use Fiji to open blobs_div2_enh.tif,
save it as a .png, and then reopen the .png file, the .png
image will have the original pixel values, a display range
of [0, 255], but with the enhanced contrast being implemented
with a non-default LUT.)

Thanks, mm

Thanks a lot ! It helped me a lot and finally I think I’m going to use the auto treshold function i found. But may I request some of your help ?
I found this script for the auto brightness contrast, that is very relevant in my case :

autoThreshold = 0
AUTO_THRESHOLD = 5000
 
imp = IJ.getImage()
cal = imp.getCalibration()
imp.setCalibration(None)
stats = imp.getStatistics() # get uncalibrated stats
imp.setCalibration(cal)
limit = int(stats.pixelCount/10)
histogram = stats.histogram #int[]
if autoThreshold<10:
	autoThreshold = AUTO_THRESHOLD
else:
	autoThreshold /= 2
threshold = int(stats.pixelCount/autoThreshold)	#int
print "pixelCount", stats.pixelCount
print "threshold", threshold
print "limit", limit
i = -1
found = False
count = 0 # int
while True:
   i += 1
   count = histogram[i]
   if count>limit:
      count = 0
   found = count> threshold
   if found or i>=255:
#   if 0 not in (!found, i<255) :
      break
hmin = i #int
i = 256
while True:
   i -= 1
   count = histogram[i]
   if count>limit:
      count = 0
   found = count> threshold
   if found or i<1:
#   if 0 not in (!found, i<255) :
      break
hmax = i #int
 
print "minimum", hmin
print "maximum", hmax

They also posted the macro code that properly works. But the Jython code makes and error at histogram[i] saying “TypeError: ‘instancemethod’ object is unsubscriptable”. I would like to use the hmin and hmax value to analyse my picture without changing my values. Do you have some ideas about how can I make this script work ?

Thanks a lot !

Hello Virgile -

I haven’t tried running your code so I’m guessing a little bit here.
(And maybe a jython expert could chime in with some accurate information.)

According to the ImageStatistics documentation, the
ImageStatistics class has both a histogram data
member (int[]) and a histogram() method (function).
I’m guessing that jython can’t figure this out, and when you
execute histogram = stats.histogram you get (a
reference to) the method, rather than the array. So you get
the error message. (You can’t “subscript” into a method.)

So you could either change the code to actually call the method:
histogram = stats.histogram(), noting that histogram is
now a double[] (so you might have to tweak some other code),
or call histogram = stats.getHistogram(), which returns
a long[] (which still isn’t an int[], so you still might have to
tweak some code, but it’s closer).

Thanks, mm

1 Like