A problem with the ImageStatistics field median

Hi,
I was trying to get the median values using the ImageStatistics object, but it always returns 0: (the mean is fine - I added it to show that using a different field gives good results)

importClass(Packages.ij.IJ);
importClass(Packages.ij.plugin.frame.RoiManager);
importClass(Packages.ij.io.OpenDialog);
importClass(Packages.ij.io.DirectoryChooser);
importClass(Packages.java.io.File);
importClass(Packages.ij.gui.GenericDialog);
importClass(Packages.ij.util.Tools);
importClass(Packages.ij.plugin.Duplicator);
importClass(Packages.ij.measure.ResultsTable);
importClass(Packages.ij.ImagePlus);
importClass(Packages.ij.process.ImageProcessor);
importClass(Packages.ij.util.ArrayUtil);
importClass(Packages.ij.gui.Overlay);
importClass(Packages.ij.plugin.filter.ParticleAnalyzer);
importClass(Packages.ij.gui.Roi);
importClass(Packages.ij.plugin.filter.Analyzer);
importClass(Packages.ij.plugin.RGBStackMerge);
importClass(Packages.ij.process.ImageConverter);
importClass(Packages.ij.gui.OvalRoi);
importClass(Packages.ij.WindowManager);
importClass(Packages.ij.ImageStack);
importClass(Packages.ij.gui.ProfilePlot);
importClass(Packages.ij.gui.Line);
importClass(Packages.ij.gui.Plot);
importClass(Packages.ij.measure.CurveFitter);
importClass(Packages.ij.plugin.frame.Fitter);
importClass(Packages.ij.gui.PolygonRoi);
importPackage(java.awt);


imp = IJ.createImage("randImg", "8-bit random", 17, 17, 1);
imp.setRoi(4,1,3,4);
rm = RoiManager.getInstance();// initiating the ROI manager in hidden mode
ip = imp.getProcessor();

stats = ip.getStatistics();
var medianVal = stats.median;
print("The median is: " + medianVal);

var meanVal = stats.mean;
print("The mean is: " + meanVal);

Is this a bug?

Thanks,
Avital

I can confirm that the median is 0 when using stats.median. Here is a minimal example where the results window shows the correct value (127):

importClass(Packages.ij.IJ);

imp = IJ.createImage("randImg", "8-bit random", 256, 256, 1);
stats = imp.getProcessor().getStatistics();
print("The median is: " + stats.median);
print("The mean is: " + stats.mean);

imp.show();
IJ.run("Set Measurements...", "mean median display redirect=None decimal=3");
IJ.run("Measure", "");
1 Like

Weird bug.

Out of curiosity, I whipped up an ImageJ Ops version. For those interested, here it is:

// @OpService ops
// @Dataset image
median = ops.run("stats.median", image);
print("Median is: " + median);
3 Likes

The javadoc for ImageProcessor.getStatistics() does not mention the median:

getStatistics()

Calculates and returns statistics (area, mean, std-dev, mode, min, max, centroid, center of mass, 256 bin histogram) for this image or ROI.


Interesting: while the original line

stats = imp.getProcessor().getStatistics();

as well as

stats = ImageStatistics.getStatistics(imp.getProcessor(), ImageStatistics.MEDIAN, imp.getCalibration());

reproduce the bug, it works correctly with:

stats = ImageStatistics.getStatistics(imp.getProcessor(), Measurements.MEDIAN, imp.getCalibration());

I found that the issue is specific to Javascript, where some constant fields appear as undefined:

importClass(Packages.ij.process.ImageStatistics);
importClass(Packages.ij.process.ByteStatistics);
importClass(Packages.ij.measure.Measurements);

print(ByteStatistics.MEDIAN);  // undefined
print(ImageStatistics.MEDIAN); // undefined
print(Measurements.MEDIAN);    // 65536

The following Groovy code works as expected:

import ij.process.ByteStatistics
import ij.process.ImageStatistics
import ij.measure.Measurements

println(ByteStatistics.MEDIAN)  // 65536
println(ImageStatistics.MEDIAN) // 65536
println(Measurements.MEDIAN)    // 65536
1 Like

The constant MEAN is undefined, too. But the mean value is calculated.

importClass(Packages.ij.process.ImageStatistics);
importClass(Packages.ij.process.ByteStatistics);
importClass(Packages.ij.measure.Measurements);

print(ByteStatistics.MEAN);  // undefined
print(ImageStatistics.MEAN); // undefined
print(Measurements.MEAN);    // 2

It’s a problem of the Method getStatistics() in ImageProcessor that uses ImageStatistics.getStatistics(this, 127, null);.
When implementing my example with Groovy, the median is 0, too.

import ij.IJ

imp = IJ.createImage("randImg", "8-bit random", 256, 256, 1)
stats = imp.getProcessor().getStatistics()
print("The median is: " + stats.median + "\n")
print("The mean is: " + stats.mean + "\n")

imp.show()
IJ.run("Set Measurements...", "mean median display redirect=None decimal=3")
IJ.run("Measure", "")

Thanks, @imagejan and @m-entrup - when I try to use the command you suggested:

stats = ImageStatistics.getStatistics(imp.getProcessor(), Measurements.MEDIAN, imp.getCalibration());

I get the following error message:

ReferenceError: "Measurements" is not defined.

What import do I need in order for the Measurements interface to be defined? I have the import ij.IJ.

Thanks,
Avital

Thanks, Curtis - now I have an excuse to justify learning how to use ops. :slight_smile:

@ctrueden - what is the type of the second argument? (image) And where would I find this in the javadocs?

Thanks,
Avital

Thanks, @imagejan - I found the following import that I was missing in your answer:

 importClass(Packages.ij.measure.Measurements);

And now the command you suggested works,

Avital

1 Like

It’s net.imagej.Dataset which can be found in the ImageJ2 javadoc.

Yes, you’re right, I was just posting the lines with the stats assignments here. But I did include the import statements in the other two snippets in my post, so hopefully finding the right thing to import wasn’t too difficult :slight_smile:

Anyhow, the ImageJ Ops solution by @ctrueden is much preferred, of course.

1 Like

Yes, I fully agree, but as I said, this very method is documented to not do the median calculation. I would guess that the median calculation is avoided by default for performancee reasons, but @Wayne might be able to tell us if this intended behavior or a bug.

1 Like

@imagejan or @ctrueden - can one of you post a full script in Javascript, including the imports and the definition of the image? Because I don’t understand how to use the following code:

// @OpService ops
// @Dataset image
median = ops.run("stats.median", image);
print("Median is: " + median);

It prints out the string “stats.median” when I try to use it.

Thanks,
Avital

The script works for me as is, when I have any image open (e.g. the Blobs example image) and start the script from the script editor (with either Javascript or Groovy selected as a language).

Keep in mind that the script parameters (i.e. ops and image) should be the very first lines in the script, otherwise the input won’t get harvested by the SciJava framework.

How did you try to run it?

1 Like

Thanks, @imagejan - I get an error message when I run it as is, and these comments are the first thing in the script:

Can’t find method net.imagej.ops.AbstractOpEnvironment.run(string,net.imagej.DefaultDataset).

I’m running ImageJ 1.50e, java 1.6.0_65,

Avital

Ah, yes, it’s possible that this only works in an up-to-date Fiji running on Java 8. To upgrade, first make sure you’re running ImageJ on Java 8 (e.g. by renaming the ./Fiji.app/java folder to java-old if you have a system Java 8 installed on Windows), then run the updater, activate the Java-8 update site, apply the changes and restart (see here).

Otherwise, you can also simply download a new Fiji that’s now shipping with Java 8 by default.

1 Like

Thanks - there’s a reason why I’m running Java 6. I’m using a mac and ImageJ doesn’t work well on a mac with Java 8.

1 Like

Yeah, the performance issues with multiple windows, etc., are one reason we have “procrastinated” so long to fully transition ImageJ2 over to Java 8. It is a transition that—for a variety of reasons—really, really needs to happen. But I do not have a good solution for the performance issues.

1 Like

in the latest ImageJ daily build (1.51a13), the ImageProcessor.getStatistics() method calculates all statistics, including mean. I did some testing and found that calculating all the statistics does not significantly slow down the method.

2 Likes

Thanks a lot, Wayne! Now I have an awesome script - I was only missing the median!