Tuesday, October 24, 2017

Read/Write Pixels in a RGB image



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 RGB 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 Clown and copy the following script for reading the pixel of X,Y-coordinates (60,100), the value -5432564 is displayed in the Log window.

// File > Open Samples > Clown
let imp = IJ.getImage();
let ip = imp.getProcessor();
let pixel = ip.getPixel(60,100);
IJ.log(pixel); // -5432564

Now, if we convert this signed integer number in an unsigned number using the bitwise operator >>> , we get...

let uint = pixel >>> 0;
IJ.log(uint); // 4289534732

Because this huge unsigned number 4289534732 is not really useful, it is more convenient — from a computer viewpoint — to display it using the hexadecimal notation...

IJ.log(uint.toString(16) ); // Hexadecimal: ffad1b0c
IJ.log(uint.toString(2) ); // Binary: 11111111101011010001101100001100

Here we go!! this 32-bit unsigned number contains the red, green and blue components encoded as 8-bit unsigned numbers (0 up to 255) .

Note:  Lost? Read the second section of this post [Link].

The 32-bit number is structured as shown in the table below.


-Byte#3Byte#2Byte#1Byte#0
Binary11111111101011010001101100001100
HexaDec.ffad1b0c
Dec.2551732712
ColorUnknownRedGreenBlue

Note: The byte #3 is unused in ImageJ but in other image processing softwares may be used to store the transparency or alpha channel.

To read the red, green, and blue components of this pixel, we need to extract them. For this, we use the bitwise operators: and (&) and shift (>>).

The blue is located at Byte #0 in the unsigned number. If we mask all the other bytes (and by extension, the corresponding bits), we will only extract the byte #0.

uint (base 2) 11111111101011010001101100001100
and (&)
mask          00000000000000000000000011111111
result        00000000000000000000000000001100 = 12 (base 10)

In JavaScript, this is written like that...

let blue = uint & 0xff; 

For the red and green components, we have to shift the number to the right before ANDing with the mask 0xff.
With green, we need to shift the number to the right of 8 bits  to place the byte #1 in the position of the byte #0.


uint (base 2)      11111111101011010001101100001100
unint shifted      0000000011111111101011010001101100001100 (>> 8)
and (&) mask       00000000000000000000000011111111
result             00000000000000000000000000011011 = 27 (base 10)

The shift operator >> pushes all the bits to the right and the outside extra-bits (in blue) are removed.

In JavaScript, this is written like that...

let green = uint >> 8 & 0xff; 
let red = uint >> 16 & 0xff; 

2. Writing pixels

We can use the same methods as those for grayscale image available in class ImageProcessor:
  • 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

However, we need to transform the red, green, and blue components in one single 32-bit number. Thus, we have to make the reverse operation, we need to shift the 8-bit numbers to the a certain amount of bits but now to the left and ORed all the shifted components.

For example, create a black RGB image of 100x100 pixels, then try to set the central pixel of coordinates (50,50) with the orange RGB color (250,105,30).

// Set the pixel (50,50) a value of (250,105,30 (orange).
let imp = IJ.createImage("RGB", "RGB black", 100, 100, 1);
let red = 250;
let green = 105;
let blue = 30;
let pixel = red << 16 | green << 8 | blue;
imp.getProcessor().putPixel(50,50,pixel);
imp.show();


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