# Binarize and SelectComponents gives incorrect output

Binarize seems to be giving me incorrect output.

Overall, I am trying to identify characteristics of different objects in my images. I have a label image that corresponds to the positions of each of the different objects. For example, all pixels corresponding to object 1 have value 1; pixels corresponding to object 2 have value 2, etc. Background has value 0.

Please find an example 16-bit label image at https://imgur.com/GuM1AFM (it's not scaled, so it looks all black). Here is a colorized version in which each pixel value corresponds to a different color (and 0 is black):

In order to identify all the pixels corresponding to object x, I have tried two ways (labelImage is the label image from above), one using Binarize and one using PixelValuePositions. Let's say I'm looking for object #136. Then with Binarize, I use

Binarize[labelImage, {136/2^16, 136/2^16}]


which outputs

or with PixelValuePositions, I use

ppos = PixelValuePositions[labelImage, 136/2^16];
ReplacePixelValue[labelImage, ppos -> Cyan] // ImageAdjust


which outputs

These are clearly different objects. When I look at the original image in ImageJ, the PixelValuePositions identifies the correct object, whereas Binarize identifies object #137. Any ideas on what's going on here?

UPDATE 1: (Another thought—I had forgotten about the built-in functions MorphologicalComponents and ComponentMeasurements, which can do much of what I’d like to do.)

UPDATE 2: I have been trying to use SelectComponents to get a label image containing only an object of interest. This seems to also give incorrect results in the same way that Binarize does. The command

SelectComponents[labelImage, #Label == 136 &] // ImageAdjust


Gives

Finally, this is a tangent, but SelectComponents also seems to be slow. The AbsoluteTiming for the above command is 0.466338, whereas the AbsoluteTiming for the following command using PixelValuePositions is 0.166369.

ReplacePixelValue[
ConstantImage[0, ImageDimensions[objectIdentitiesImages[[1]]],
"Bit16"],
PixelValuePositions[labelImage, 136/2^16] -> Cyan] // AbsoluteTiming


It's weird that you get any pixels a tall, because the value 136/2^16 isn't even in the image:

MemberQ[Flatten[DeleteDuplicates[ImageData[img]]], 136/2^16]


False

My guess is that PixelValuePositions and Binarize round the value resp. thresholds to the closest possible pixel values. And (wild guess) Binarize probably takes the Floor of the lower and the Ceiling of the upper threshold, while PixelValuePositions probably rounds to the closest value.

If you use 136/(2^16 - 1) instead (because the highest possible value in a 16 bit image, 2^16-1 is mapped to 1.0), you get the same object.

• Thanks nikie. That sounds like a reasonable hypothesis. Mathematica seems to like rescaling images to values between 0 and 1, which is why I had to divide by 2^16 in the first place and which also seems to complicate things unnecessarily. – jeremyc0 Dec 4 '17 at 8:09
• I agree, it's unfortunate that you can't turn off rescaling. You can use imgInteger = img*65535;, though, and only work with integers after that. You just have to be careful because some image processing functions (like ImageAdd, IIRC?) clip the output to the range 0..1 – Niki Estner Dec 4 '17 at 8:42
• You can use, e.g., Clip to preprocess the image. – Henrik Schumacher Dec 4 '17 at 8:49