Potential bug in the Color Thresholder

issue
colorthreshold
yuv
Tags: #<Tag:0x00007fb87ed61d78> #<Tag:0x00007fb87ed61b98> #<Tag:0x00007fb87ed61a58>

#1

Dear @Wayne, @gabriel,

by trying to run a certain setting in the Color Thresholder using the YUV color space in relation to a user question here. I figured out a weird behaviour of the tool.

Using the YUV color space manually in the Color Thresholder works fine and gives different results from using the other 3 color spaces.

But recording the YUV setting leads to the application of the user specified YUV limits to the actual RGB stack since the RGBtoYUV conversion is somehow not applied to the image before converting it into an RGB stack. This can be seen in the MCVE below which gives the same values in RGB color space vs. YUV color space when applied as a macro.

Here a MCVE as in the original post:

run("Set Measurements...", "area mean standard modal min center integrated median skewness kurtosis display redirect=None decimal=3");
run("Lena (68K)");
rename("RGB");
original = getTitle();
run("Duplicate...", " ");
rename("YUV");
call("ij.plugin.frame.ColorThresholder.RGBtoYUV");
run("RGB Stack");
run("Measure");
run("Next Slice [>]");
run("Measure");
run("Next Slice [>]");
run("Measure");

selectWindow(original);
run("RGB Stack");
run("Measure");
run("Next Slice [>]");
run("Measure");
run("Next Slice [>]");
run("Measure");

The following two macros show this behaviour as well by applying the same values once in RGB and once in “YUV” color space, while the latter is actually not happening, because the RGBtoYUV conversion does not take place.

Macro For RGB:

run("Lena (68K)");
// Color Thresholder 2.0.0-rc-61/1.51s
// Autogenerated macro, single images only!
min=newArray(3);
max=newArray(3);
filter=newArray(3);
a=getTitle();
run("RGB Stack");
run("Convert Stack to Images");
selectWindow("Red");
rename("0");
selectWindow("Green");
rename("1");
selectWindow("Blue");
rename("2");
min[0]=130;
max[0]=255;
filter[0]="pass";
min[1]=0;
max[1]=255;
filter[1]="pass";
min[2]=0;
max[2]=255;
filter[2]="pass";
for (i=0;i<3;i++){
  selectWindow(""+i);
  setThreshold(min[i], max[i]);
  run("Convert to Mask");
  if (filter[i]=="stop")  run("Invert");
}
imageCalculator("AND create", "0","1");
imageCalculator("AND create", "Result of 0","2");
for (i=0;i<3;i++){
  selectWindow(""+i);
  close();
}
selectWindow("Result of 0");
close();
selectWindow("Result of Result of 0");
rename(a);
// Colour Thresholding-------------

Macro for YUV:

run("Lena (68K)");
// Color Thresholder 2.0.0-rc-61/1.51s
// Autogenerated macro, single images only!
min=newArray(3);
max=newArray(3);
filter=newArray(3);
a=getTitle();
call("ij.plugin.frame.ColorThresholder.RGBtoYUV");
run("RGB Stack");
run("Convert Stack to Images");
selectWindow("Red");
rename("0");
selectWindow("Green");
rename("1");
selectWindow("Blue");
rename("2");
min[0]=130;
max[0]=255;
filter[0]="pass";
min[1]=0;
max[1]=255;
filter[1]="pass";
min[2]=0;
max[2]=255;
filter[2]="pass";
for (i=0;i<3;i++){
  selectWindow(""+i);
  setThreshold(min[i], max[i]);
  run("Convert to Mask");
  if (filter[i]=="stop")  run("Invert");
}
imageCalculator("AND create", "0","1");
imageCalculator("AND create", "Result of 0","2");
for (i=0;i<3;i++){
  selectWindow(""+i);
  close();
}
selectWindow("Result of 0");
close();
selectWindow("Result of Result of 0");
rename(a);
// Colour Thresholding-------------

#2

Hi, This seems to be a bug in the IJ applet, not in the Threshold_Colour plugin.
I think that the problem is that the line:

call("ij.plugin.frame.ColorThresholder.RGBtoYUV");

does not return the YUV image that is expected by the rest of the macro.
You can try the standalone plugin which seems to work fine, from here:

http://www.mecourse.com/landinig/software/software.html

This is the macro generated from the standalone version:

// Threshold Colour v1.16------
// Autogenerated macro, single images only!
// G. Landini 8/May/2015.
//
min=newArray(3);
max=newArray(3);
filter=newArray(3);
a=getTitle();
run("RGBtoYUV ");
run("RGB Stack");
run("Convert Stack to Images");
selectWindow("Red");
rename("0");
selectWindow("Green");
rename("1");
selectWindow("Blue");
rename("2");
min[0]=130;
max[0]=255;
filter[0]="pass";
min[1]=0;
max[1]=255;
filter[1]="pass";
min[2]=0;
max[2]=255;
filter[2]="pass";
for (i=0;i<3;i++){
  selectWindow(""+i);
  setThreshold(min[i], max[i]);
  run("Convert to Mask");
  if (filter[i]=="stop")  run("Invert");
}
imageCalculator("AND create", "0","1");
imageCalculator("AND create", "Result of 0","2");
for (i=0;i<3;i++){
  selectWindow(""+i);
  close();
}
selectWindow("Result of 0");
close();
selectWindow("Result of Result of 0");
rename(a);
// Threshold Colour ------------

#3

@gabriel and @Wayne,

I also nailed it down to the line call("ij.plugin.frame.ColorThresholder.RGBtoYUV"); and after installing the RGBtoYUV_.class file and using your macro it runs smoothly.

What puzzles me is that the macro command calls the static method ColorThresholder.RGBtoYUV and in the static method I find this code:

This contains a reference to the RGB to Lab conversion and would not return a YUV version of the image. While using the Color Thresholder it internally works since I guess it calls the method RGBtoYUV(ImageProcessor ip) which seems to really do the YUV conversion.

Shouldn’t the method look like this:

Not that I personally would need the application of YUV in a macro directly but you might consider changing this (if this is really the cause of the macro problem described above).

[Edit]: Tested the change as suggested above and works :slight_smile: Filed a PR


#4

Thanks @biovoxxel. Yes, you are right. @Wayne adapted the standalone version to the thresholding applet so I am sure he will fix this now in IJ since you found out where the issue was. Thanks.


#5

Dear all,
thanks for taking care of this bug and thanks @biovoxxel to point it out.
Just an add.
I think there is also another problem (I don’t think that this is an intended behavior) the macro recorder doesn’t record the Threshold method but just the threshold values used for that specific images.
So if you then would like to use the recorded macro to analyse another image it will use the automatic threshold values found with the other image.
Do you think it would be easy to record the threshold method instead of the values?

Thank you all,
Emanuele Martini


#6

Hi emartini,
I do not think you need that. The applet was an adaptation that Wayne did of the standalone plugin. The latter does not use “methods”.

But if you want to use an automated method on a colour image, then you do not need the applet or the slider values; there is a different way you should threshold your colour image:

For HSB, LAB or YUV: apply the greyscale method in the B, B or V channels (respectively) (really that is not really “colour thresholding” but on the intensity component).

For the RGB apply the greyscale method to each channel (R, G and B).
That is all.
The complication (and that is when I think the plugin is useful) is precisely when you want to specify the values.

Cheers


#7

I agree with that, I usually use some colour deconvolution methods and use automated threshold method on the single channels.
My point is that when you set a method in the applet maybe you can think that the autogenerated macro records also the method you used (since you can click on it in the applet GUI).
At least, I thought that for a while :slight_smile: and then after some checks I’ve got that it gets the values.
I think it could be helpful to point out that the autogenerated macro records the values and do not use the method, maybe directly in the comments of the autogenerated macro to avoid misunderstandings.

thank you for the reply,
Emanuele Martini


#8

Good day Gabriel,

thanks for these insights.

Before, I didn’t really understand the function because it doesn’t do anything else than set an automatic achromatic threshold according to one of the schemes, except the color values are specified by hand or per macro.

So in fact there is no automatic colour thresholding that deserved this name or that parallels the automatic gray-level thresholds for colour images.

The ImageJ manual isn’t perfectly helpful in this respect:

Thresholding Method Allows any of the 16 different automatic thresholding methods to be selected.

Again thanks for the clarification

Herbie


#9

You can use a method… to get the slider values. Sure it might not be applicable to another image. But there is no guarantee that the slider positions are given by the method! You can adjust that.
If you want to threshold on given slider values other images, then the automated method gets in the way. I would leave things as they are, many people have used it like this and would bring a change of function for old code.
I understand that the intention is a good one, but I do not think there is a simple solution as we do not know what the user is after.

There are similar issues, for example with convolution filtering of HSB images. You would not sharpen or blur the hue and saturation channels, but only the brightness one.


#10

The corrected version of the RGBtoYUV() method is in the latest ImageJ daily build (1.51t18).


Colour thresholding macro applied to several images
#11

I really think that it would be better to don’t have the automatic threshold methods and the button in the applet at all.
It can generate a lot of confusion and scientific inaccuracies.
It is like you are thresholding an 8bit grayscale image with Otsu’s method and the macro recorder records for you the values and not that you have used the Otsu’s method, and then you will use that to threshold other images saying: “I am getting nuclei with the Otsu’s Method”, while you are using the values coming from Otsu just from the first image you have analyzed against all the other images and not recalculating the Otsu’s threshold on the new image itself.

But ok I think our positions are clear enough and I really can understand end user “as we do not know what the user is after.” and “old code” problems.

Have a nice day,
thank you for the discussion
Emanuele Martini