Tuesday, October 24, 2017

Read and Write Pixels in Grayscale Images



Thanks to the methods of the class ImageProcessor [see Post], it is possible to read and write pixels in an image.



Updated for  ECMAScript2015+, it requires at least version ImageJ 1.51r and Java 9. See this post for update [Link].

1. Reading pixels in a grayscale image

As shown in a previous post [see Post], you can use the method (or function) getPixel(x,y) to read a pixel of an image. As a refresher, if you load the sample image entitled Boats and copy the following script for reading the pixel of X,Y-coordinates (100,200), the value 155 is displayed in the Log window.

// File > Open Samples > Boats
let imp = IJ.getImage();
let ip = img.getProcessor();
let pixel = ip.getPixel(100,200);
IJ.log(pixels) // 155

The first line of the script, get the active image as an object ImagePlus, then you need the corresponding ImageProcessor allowing an access to the pixels.
Note: If you don't know what are the differences between 8-bit, 16-bit, and 32-bit gray-scale images in ImageJ, see this post [Link].

Because the pixels array of an image is stored as a 1D array, it is sometimes more convenient to get the pixel using the index in this array rather than using its coordinates. In this case, we are using another method named get(...) existing in two versions:
  • get(index) taking the index as argument
  • get(x,y) taking the X,Y-coordinates as arguments

... as shown in the ImageJ API of the class ImageProcessor...

abstract int  get(int index) 
abstract int  get(int x, int y)
This is a faster version of getPixel() that does not do bounds checking.

Note: The index is calculated from the formula:
  • index = x + img_width * y
and the coordinates (x,y) are obtained from the index with:
  • x = index % img_width
  • y = Math.floor(index / img_width)

The previous script may be completed as follows...

let pixel_with_coord = ip.get(100,200);
let pixel_with_index = ip.get(100 + imp.getWidth()*200);
IJ.log(`${pixel_with_coord} is equal to ${pixel_with_index}.`);

2. Writing pixels

The methods available in class ImageProcessor are:
  • putPixel(int x, int y, int value): Stores the specified value at (x,y).
  • set(int x, int y, int value): Faster version of putPixel() that does not clip out of range values and does not do bounds checking.
  • set(index): Same as above but with index rather coordinates

For example, if we append the following lines to our script, now the pixel (100,200) has a value of 0.


// Set the pixel (100,200) a value of 0 (black).
ip.putPixel(100,200,0);
IJ.log(ip.getPixel(100,200));

3.What about the 32-bit floating-point image?

The methods getPixel(..) and putPixel(..) also works with 32-bit image. However, you must use the equivalent getf(..) and setf(..) methods to read and write pixel with floating-point numbers.

4. Application: Thresholding

Among the segmentation operations, the thresholding is one of the most popular allowing to partition an image into two populations of pixels: True (255) and False (0).
The algorithm is simple: if the pixel value is greater than a threshold value, the pixel is set to 255 otherwise to 0. For the implementation, rather than using nested loops (two loops: one for the X and the other for the Y), it is more convenient to use one big loop scanning all the image pixels and apply our conditional.

++++ JavaScript: thresholding.js ++++ ++++ JavaScript: End of thresholding.js ++++

Thank you for reading.


5. Other crazybiocomputing posts

Further readings are available in ...
  • Programming in JavaScript Series  [Link]
  • JavaScript/ECMAScript TOC [Link]

No comments:

Post a Comment