What are the display and processing protocols for NaNs in the various image types

plugins
Tags: #<Tag:0x00007fb882c3f838>

#1

I’m wondering if there is a good writeup for how NaNs are handled

Image Type NaN is Displayed as Nan is processed as
RGB
indexed color
8-bit
16-bit
32-bit

Thanks
Ron DeSpain


#2

Dear @rondespain,

as far as I know, NaN is only supported in the 32-bit case when you setting a threshold. Conversions to other image types will replace NaN with 0. How NaNs are processed depends on the implementation of a plugin. Most of the built-in filters seem to ignore NaN in their computations. Additionally, you can use Process > Noise > Remove NaNs… to replace NaN intensities with the median intensity of their neighborhood.

Best,
Stefan


#3

Hello stelfrich
Any idea why the conversion of nans to a value with changeValues isn’t working below?

requires("1.45e");
run("32-bit");  //must be 32 bit

changeValues(200,255,NaN);
changeValues(0,10,NaN);
getStatistics(area,mean);
//print(area,mean);
changeValues(NaN,NaN,mean);
waitForUser("NaNs not changed to mean");
run("8-bit");  
changeValues(0,0,mean);

#4

changeValues(NaN,NaN,mean); does not work as you expect it to work in this case. You will have to iterate the pixels manually and replace NaN instances with mean:

//...
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) { 
	for(y=0;y<ymax;y++) { 
		v=getPixel(x,y);
		if(isNaN(v)) {
			setPixel(x,y,mean);
		} 
	}
} 
//...
Comparisons with `NaN` always evaluate to `false`:

https://docs.oracle.com/javase/specs/jls/se9/html/jls-4.html#jls-4.2.3:

NaN is unordered, so:

  • The numerical comparison operators <, <=, >, and >= return false if either or both operands are NaN (§15.20.1).

#5

I am comparing two techniques for replacing flares and darkfield backgrounds with the mean of the image by using NaNs, and ran into a confusing result…possibly a memory problem within ImageJ
Here is the code I used:

requires("1.45e");
oit=getTitle();
run("Duplicate...", "title=[Conversion Technique]");
run("32-bit");

changeValues(200,255,NaN);
changeValues(0,10,NaN);
getStatistics(area,mean1);
print("The Mean is: "+mean1+" for the Conversion Technique");


starttime1=getTime();
run("8-bit");  
changeValues(0,0,mean1);
run("32-bit");
endtime1=getTime();

selectWindow(oit);
run("Duplicate...", "title=[Pixel Technique]");
run("32-bit");
changeValues(200,255,NaN);
changeValues(0,10,NaN);
getStatistics(area,mean2);
print("The Mean is: "+mean2+" for the Pixel Replacement Technique")
starttime2=getTime();
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) { 
	for(y=0;y<ymax;y++) { 
		v=getPixel(x,y);
		if(isNaN(v)) {
			setPixel(x,y,mean2);
		} 
	}
} 
endtime2=getTime();

print("Replacing NaNs via 8bit conversion change time = "+endtime1-starttime1+"\nReplacing NaNs via 32bit pixel replacement time = "+endtime2-starttime2);
run("Tile");

// ##########Cycle 2##############

oit=getTitle();
run("Duplicate...", "title=[Conversion Technique]");
run("32-bit");

changeValues(200,255,NaN);
changeValues(0,10,NaN);
getStatistics(area,mean1);
print("The Mean is: "+mean1+" for the Conversion Technique");


starttime1=getTime();
run("8-bit");  
changeValues(0,0,mean1);
run("32-bit");
endtime1=getTime();

selectWindow(oit);
run("Duplicate...", "title=[Pixel Technique]");
run("32-bit");
changeValues(200,255,NaN);
changeValues(0,10,NaN);
getStatistics(area,mean2);
print("The Mean is: "+mean2+" for the Pixel Replacement Technique")
starttime2=getTime();
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) { 
	for(y=0;y<ymax;y++) { 
		v=getPixel(x,y);
		if(isNaN(v)) {
			setPixel(x,y,mean2);
		} 
	}
} 
endtime2=getTime();

print("Replacing NaNs via 8bit conversion change time = "+endtime1-starttime1+"\nReplacing NaNs via 32bit pixel replacement time = "+endtime2-starttime2);
run("Tile");

Here is the result:

I can’t seem to upload the Tif image I used. You can just cut it out of the screenshot if you want to run the code on the same image.

Any ideas on what’s happening here would be appreciated.

Thanks
Ron DeSpain


#6

Does this also happen when you manually run the macro twice?


#7

Yup…here’s the code that loops back to the original image so you can just click the run button in FIJI to run it again.

requires("1.45e");
oiid=getImageID();
run("Duplicate...", "title=[Pixel Technique]");
run("32-bit");
changeValues(200,255,NaN);
changeValues(0,10,NaN);
//waitForUser("Check For NaNs","Where's The NaN when you need one?");
getStatistics(area,mean2);
print("The Mean is: "+mean2+" for the Pixel Replacement Technique")
starttime2=getTime();
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) { 
	for(y=0;y<ymax;y++) { 
		v=getPixel(x,y);
		if(isNaN(v)) {
			setPixel(x,y,mean2);
		} 
	}
} 
endtime2=getTime();

//run("Enhance Contrast...", "saturated=0.3 normalize");
print("Replacing NaNs via 32bit pixel replacement time = "+endtime2-starttime2);
run("Tile");
selectImage(oiid);

Here is the output:


#8

I wasn’t able to reproduce the issue on my Ubuntu 16.04.3 machine with an up-to-date Fiji and the most recent Java version with the Clown or Lena sample images. Could you please save your input image as PNG and upload it here?

Also, your macro that runs the operations twice should have a selectWindow(oit); directly after // ##########Cycle 2##############. Otherwise, you are running the second cycle not on the input image but on the Pixel Technique image of the previous run. That’s not what you are trying to do, is it?


#9

Here’s the image

Here’s the code:

requires("1.45e");
oiid=getImageID();
run("Duplicate...", "title=[Pixel Technique]");
run("32-bit");
changeValues(200,255,NaN);
changeValues(0,10,NaN);
//waitForUser("Check For NaNs","Where's The NaN when you need one?");
getStatistics(area,mean2);
print("The Mean is: "+mean2+" for the Pixel Replacement Technique")
starttime2=getTime();
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) { 
	for(y=0;y<ymax;y++) { 
		v=getPixel(x,y);
		if(isNaN(v)) {
			setPixel(x,y,mean2);
		} 
	}
} 
endtime2=getTime();

//run("Enhance Contrast...", "saturated=0.3 normalize");
print("Replacing NaNs via 32bit pixel replacement time = "+endtime2-starttime2);
run("Tile");
selectImage(oiid);

Here’s the output after 9 repeat runs in FIJI with the PNG attached

Here’s some runs in ImageJ:

P.S. I did leave out the selection of the original image in the 2 runs code…the attached code only runs once and returns to the input PNG at its end, so you can just run it again in either FIJI or ImageJ

thanks for your help
Ron DeSpain


#10

I put together this simple test image

target 255

and here are the results of repeat runs of pixel replacement of the NaNs.

It looks like NaNs that get replaced with the mean are displayed as zeros (their value is reported correctly when moused over), and bands of the image are displayed differently (suggesting to me that the pointers to the images are getting confused as to where the images are in memory).

Ron DeSpain


#11

Is that also the case for the pixels highlighted with “Memory?” or do you observe other pixel intensities for those (it’s not really clear to me from your first illustration… sorry)?

I can’t seem to reproduce the issue with the test image:


#12

Their value is correct when moused over, but they are displayed as black…not good.

For some reason the cyan arrows got hidden behind the images when uploaded (must be a PNG thing). The indication that memory isn’t being accessed correctly also seems to be removed with PNGs. Here’s a jpg showing the stripe on the left side of the image that gets processed correctly, but doesn’t include the entire image.

Pixel Technique
-------> Partial Processing???

This image is of course not 32 bit, so it doesn’t have the same mouseover values as the 32 bit images with NaNs replaced with the mean. I also noted that the entire image gets processed correctly when I save it as a Tif (which can’t be uploaded here), or if I draw an arrow on the image in a color and type cmd-d. You will have to run the code in order to see these things as I can’t upload a 32 bit tif. Run the code 8 to 10 times (fill the screen with images) and some of them will have the gray strip on the left. This stripe is at the mean and correctly displayed as a medium gray. The black regions at the bottom of the image also have the mouseover value of the mean, but they are displayed as black.

This is a hard problem to communicate about since the 32 bit images can’t be shared, and the problem disappears when the image is saved as a 32 bit tif. I suppose a work around would be to save the processed image and open it up again programatically.

You’ll have to run the code below to see the problem.

requires(“1.45e”);
oiid=getImageID();
run(“Duplicate…”, “title=[Pixel Technique]”);
run(“32-bit”);
changeValues(200,255,NaN);
changeValues(0,10,NaN);
//waitForUser(“Check For NaNs”,“Where’s The NaN when you need one?”);
getStatistics(area,mean2);
print(“The Mean is: “+mean2+” for the Pixel Replacement Technique”)
starttime2=getTime();
xmax = getWidth();
ymax = getHeight();
for(x=0;x<xmax;x++) {
for(y=0;y<ymax;y++) {
v=getPixel(x,y);
if(isNaN(v)) {
setPixel(x,y,mean2);
}
}
}
endtime2=getTime();

//run(“Enhance Contrast…”, “saturated=0.3 normalize”);
print("Replacing NaNs via 32bit pixel replacement time = "+endtime2-starttime2);
run(“Tile”);
selectImage(oiid);

If this interests you, you can call me
Ron DeSpain 321 751 3789


#13

If their values are correct, I wouldn’t think too hard about the issue. The issue is not that they are displayed in black, but that the same value is displayed with different colors. What happens when you change the Lookup Table to a different color (let’s say Green)?

The values are correct: if you continue with your analysis, you should be fine.

It is an interesting issue, for which we very likely won’t find a solution because we can’t seem to reproduce the issue. Hence, I’d say you continue with your analysis and don’t mind how the image “looks” or, as you suggested, save the image and open it again.


#14

applying the gray lookup table displays the image correctly. It looks like ImageJ sometimes just doesn’t process the entire image when displaying it. It’s important that the image be displayed correctly as the image colors are being used by doctors as a decision support tool during diagnosis, possibly during a surgery. GOOD WORKAROUND THOUGH.

Thanks for your help
Ron DeSpain


#15

Hello Stelfrich…
FYI: upon reading the users manual I see that the image is not updated when pixels are changed via setPixel()…The image must be updated with updateDisplay(); in order to get a properly displayed image…DUH…Who Knew!

Ron DeSpain