I'm looking through a dataset set of images in ImageJ (a stack of .tif images, about 130 frames), and I have a problem with the dataset. It's a series of microscope images, with each frame being a plane about 3-4 micrometers above/below the previous one. As I go deeper into the dataset, light scattering makes for a brighter background, so the main features of the specimen are dimmer.
However, ImageJ's brightness and contrast feature uses a histogram that represents the entire stack of images. When I click "Auto" and "Reset" on an image deep in the stack, the resulting contrast is perfect: all the features light up really well. However, then, back at the start of the stack, most of the features have become saturated.
I've tried manually extracting a few images from various points in the stack and performing Auto->Reset in Brightness & Contrast on each one individually and re-converting them to a stack afterwards, and it looks really solid. How can I do this programmatically (e.g. with a plugin) for the entire stack? What are the relevant API calls?
A good way to start to write such a script is to use ImageJ's macro recorder - you can start this with Plugins > Macros > Record ...
. For this example, I'm assuming that you've switched the Record:
option box to JavaScript
, but if you're more familiar with the ImageJ macro language or writing plugins in Java one of the others might be a better choice. If you then open your image and use Image > Stacks > Set Slice ...
and select (say) slice 20, you should see:
imp.setSlice(20);
... appear in the recorder. Now if you run Image > Adjust > Brightness/Contrast...
and select Auto
, you should see in the recorder that that's the equivalent of running Enhance Contrast
keeping 0.35% saturated pixels. The problem with this, as you've noted, is that this adjusts the minimum and maximum values for the entire stack rather than just that that slice. However, you can run Enhance Contrast
with different options by running Process > Enhance Contrast
. The section on that option on the ImageJ documentation wiki explains that if you want to change the pixel values rather than setting the minimum and maximum for the stack, you need to select the "Normalize" option. If I choose to do that instead, the macro recorder records:
imp.setSlice(20);
IJ.run(imp, "Enhance Contrast", "saturated=0.35 normalize");
... and you should see that only slice 20 has been altered. You can then wrap that in a loop that runs the same enhancement on every slice with:
var imp = IJ.getImage();
var n = imp.getStackSize();
for( var i = 0; i < n; ++i) {
imp.setSlice(i+1);
IJ.run(imp, "Enhance Contrast", "saturated=4 normalize");
}
(If you're using Fiji, then the Script Editor (e.g. via File > New > Script
) is an easy way to experiment with such scripts.)
Of course, using the normalize option does result in the pixel values being altered, which means in this case that you're losing information, so I wouldn't use the resulting stack for quantitative results.
I hope that's of some use.