Different output between set(x,y,pixel) and set(i, pixel) in python

Hi All,

I am getting different output when I am using the two fonctions in the ImageProcessor class. The aim of these function is to remove dead cells in a stack that I know to be very bright.
Here are the two functions that should do the same:

def remove_overPixel(imp_):
    stack_ = imp_.getStack()
    for i in range(imp_.getStackSize()):
	    ip_ = stack_.getProcessor(i+1)
	    ip_.setAutoThreshold("Default")
  	    threshold_ = ip_.getAutoThreshold()
	    pixels = ip_.getPixels()
	    for j in range(len(pixels)) :
		     if pixels[j]> threshold_ :
			    ip_.set(j, 0)
     return imp_

and the second one

def remove_overPixel2(imp_):
    stack_ = imp_.getStack()
    for i in range(imp_.getStackSize()):
	    ip_ = stack_.getProcessor(i+1)
	    ip_.setAutoThreshold("Default")
	    threshold_ = ip_.getAutoThreshold()
	    for x in range(ip_.width):
		   for y in range(ip_.height):
			   if ip_.getPixel(x,y)> threshold_ :
				   ip_.set(x,y,0)
    return imp_

The second function (remove_overPixel2) is doing the job properly but the first one (remove_overPixel) let some pixels with a grey level above the threshold that I am calculating for each images of the stack.
It is not really important because by using remove_overPixel2 i am getting what i want but I really want to understand why the first one is not doing the job.
Do you have any idea ?

Just for info, I am calling each function as:

imp0 = IJ.getImage()
imp = imp0.duplicate()
imp.setTitle("image2")
imp = remove_overPixel(imp) 

Let me know if you know why ?

regards
Philippe

Hello Philippe -

The issue is most likely due to an unexpected (absence of)
type conversion.

ImageProcessor.getPixel (int, int) always returns
an int (that might actually be the bit pattern of a float stored
in an int and requiring reinterpretation).

ImageProcessor.getPixels() returns an Object that is
an array of the type (more or less) of the data stored in
the ImageProcessor. Python (jython) knows what type
this is, so it can interpret the data correctly.

Try the following:

Add print type (ip_) to both of your functions so we
can see the actual type of your ImageProcessor. And add
print type (pixels) to your first function so we can
see the actual type of your pixel array.

Note, in particular, that if you have a FloatProcessor, the
int returned by FloatProcessor.getPixel (int, int)
requires reinterpretation. Quoting from its documentation:

public int getPixel(int x, int y)

Returns a pixel value that must be converted using Float.intBitsToFloat().

Thanks, mm

Hi @mountain_man

thank you for your reply.
Here is what I get:
type(ip_) = <type ‘ij.process.ShortProcessor’>
type(pixels) = <type ‘array.array’>

It is not surprising for the type of image because the stack is a stack of 16bit images.

regards
Philippe

Hello Philippe -

That makes sense. Here is most likely what is happening:
ImageJ treats the java short values in the ShortProcessor
as unsigned values running from 0 to 2^16 - 1. But the
java designers foolishly elected not to support unsigned
types in java (as did the python designer). This causes
headaches, of which this is one.

By the time your pixels get to python they are a python
array of (signed) python integers that have the values of
the (signed) java shorts stored in the ShortProcessor,
interpreted as signed values.

Modify your first function as follows:

	    pixels = ip_.getPixels()
	    for j in range(len(pixels)) :
		     # if pixels[j]> threshold_ :
		     p_signed = pixels[j]
		     p_unsigned = (p_signed + 2**16) % 2**16
		     if p_unsigned > threshold_ :
			    ip_.set(j, 0)

For the specific case of ShortProcessor, this will convert
the pixel value to a (signed) python integer that has the value
in [0, 2^16), matching how ImageJ interprets ShortProcessor
pixels.

(The code for ShortProcessor.getPixel (int, int)
uses a standard java signed --> unsigned idiom that does, in
effect, the same thing.)

Thanks, mm

1 Like

Hi @mountain_man

sorry for the late reply. It is perfect. I understand better now why …
Thank you very much

regards
Philippe