Access pixel values in array

Hi,

I want to get all the pixel values in an array.
Is there any other way to use
instead of get and put

for (int v = 0; v < ip.getHeight(); v++) {
for (int u = 0; u < ip.getWidth(); u++) {
int c = ip.get(u, v);

There is a getPixels() method in the ImageProcessor class that loads the pixel data into a 1D array.

2 Likes

Adding to Gabriel’s answer, you’ll need to cast the result of getPixels() into the appropriate array depending upon what kind of ImageProcessor you have - as described here.

So, for example

byte[] pixels = (byte[])ip.getPixels();

will only work if

ip instanceof ByteProcessor

i.e., you’ve got an 8-bit image. If you have a 16 or 32-bit image, or RGB, it won’t, and you’d need to cast the returned value to the appropriate array (short[], float[] or int[] respectively).

Additionally, if you are working with a single channel (i.e. not an RGB image) then I’d warn against using getPixel() in general if you aren’t sure what type of image you have, since it always returns an int. If you happen to have a 32-bit image, the documentation says that the int is created using Float.intBitsToFloat() - which is unlikely to result in the value that you want.

Personally, I use getf(x, y) far more often to get pixel values for single-channel images. This works as expected for 8-bit, 16-bit and 32-bit images - only RGB needs to be handled differently.

Finally, if you have a single channel image, you might find it easier to do something like this:

FloatProcessor fp = ip.convertToFloatProcessor();
float[] pixels = (float[])fp.getPixels();

It’s not tremendously efficient, but at least you know what you have and don’t have to handle 8-bit, 16-bit and 32-bit images separately.

6 Likes

Just adding a minor remark to @petebankhead’s awesome answer:

Depending on what you are trying to achieve and your level of programming experience, @nickii, you might want to take a look at ImgLib2 examples and maybe ImageJ Ops for sophisticated data structures and image processing algorithms.

Best,
Stefan

2 Likes

Thanks for completing my incomplete answer :wink:
Apart from getf(x, y), there is also get(x,y) which is faster, because it does not check if x and y are within the image boundaries.

Thanks @gabriel :slight_smile:

Still, I remain so converted by getf(x, y), that at the risk of taking this all a bit far I wrote a little Groovy script to run through Fiji to test some different ways of accessing pixels, and remind myself why getf(x, y) wins for me.

The script creates a 2x2 ByteProcessor, ShortProcessor and FloatProcessor, each with the same pixel values:

-------------
|  1  |  2  |
-------------
| 128 | 129 |
-------------

It then tests different methods of accessing the pixels, including directly from an array with getPixels(). The results of running the script are:

-----------------------------
BYTEPROCESSOR

Accessing pixels with get:

	1	2	128	129

Accessing pixels with getPixel:

	1	2	128	129

Accessing pixels with getf:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixelValue:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixels()[]:

	1	2	-128	-127
-----------------------------
SHORTPROCESSOR

Accessing pixels with get:

	1	2	128	129

Accessing pixels with getPixel:

	1	2	128	129

Accessing pixels with getf:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixelValue:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixels()[]:

	1	2	128	129
-----------------------------
FLOATPROCESSOR

Accessing pixels with get:

	1065353216	1073741824	1124073472	1124139008

Accessing pixels with getPixel:

	1065353216	1073741824	1124073472	1124139008

Accessing pixels with getf:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixelValue:

	1.0	2.0	128.0	129.0

Accessing pixels with getPixels()[]:

	1.0	2.0	128.0	129.0
-----------------------------

Conclusions:

  • get and getPixel are fine for integers with Byte and ShortProcessors, but can go badly wrong with FloatProcessors if you aren’t careful.
  • Accessing the array directly is fine for a FloatProcessor, but you need to remember to mask the returned value yourself for ByteProcessor and ShortProcessor to handle the fact that the pixel values are unsigned (not doing so led to trouble in the ByteProcessor example above).
  • getf and getPixelValue behave as you’d expect across all the ImageProcessors.

The difference is that getf(x, y) doesn’t do bounds checking, while getPixelValue(x, y) returns 0 for out-of-image requests.

Therefore my advice would be to just stick with getf(x, y) in general as your go-to method for accessing pixels from an ImageProcessor and take care of your own bounds checking. You shouldn’t get any unwelcome surprises that way. Any of the other options, including getPixels(), require more care and attention.

Of course, all of this completely ignores ColorProcessors… and there’s always @stelfrich’s answer that should be considered :slight_smile:

2 Likes

We also have a subsection on accessing pixel values on the ImageJ wiki, @petebankhead. It would be great if you found the time to look at that section and augment it with your answers given here :slight_smile:

And thank you for the thorough investigation!! :thumbsup:

Thanks a lot @stelfrich and @petebankhead for your answers. Was really a help. :slight_smile: