Java image conversion to RGB565 - java

I try to convert image to RGB565 format.
I read this image:
BufferedImage bufImg = ImageIO.read(imagePathFile);
sendImg = new BufferedImage(CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, BufferedImage.TYPE_USHORT_565_RGB);
sendImg.getGraphics().drawImage(bufImg, 0, 0, CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, null);
Here is it:
Then I convert it to RGB565:
int numByte=0;
byte[] OutputImageArray = new byte[CONTROLLER_LCD_WIDTH*CONTROLLER_LCD_HEIGHT*2];
int i=0;
int j=0;
int len = OutputImageArray.length;
for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {
Color c = new Color(sendImg.getRGB(i, j));
int aRGBpix = sendImg.getRGB(i, j);
int alpha;
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
//RGB888
red = (aRGBpix >> 16) & 0x0FF;
green = (aRGBpix >> 8) & 0x0FF;
blue = (aRGBpix >> 0) & 0x0FF;
alpha = (aRGBpix >> 24) & 0x0FF;
//RGB565
red = red >> 3;
green = green >> 2;
blue = blue >> 3;
//A pixel is represented by a 4-byte (32 bit) integer, like so:
//00000000 00000000 00000000 11111111
//^ Alpha ^Red ^Green ^Blue
//Converting to RGB565
short pixel_to_send = 0;
int pixel_to_send_int = 0;
pixel_to_send_int = (red << 11) | (green << 5) | (blue);
pixel_to_send = (short) pixel_to_send_int;
//dividing into bytes
byte byteH=(byte)((pixel_to_send >> 8) & 0x0FF);
byte byteL=(byte)(pixel_to_send & 0x0FF);
//Writing it to array - High-byte is second
OutputImageArray[numByte]=byteH;
OutputImageArray[numByte+1]=byteL;
numByte+=2;
}
}
Then I try to restore this from resulting array OutputImageArray:
i=0;
j=0;
numByte=0;
BufferedImage NewImg = new BufferedImage(CONTROLLER_LCD_WIDTH, CONTROLLER_LCD_HEIGHT, BufferedImage.TYPE_USHORT_565_RGB);
for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {
int curPixel=0;
int alpha=0x0FF;
int red;
int green;
int blue;
byte byteL=0;
byte byteH=0;
byteH = OutputImageArray[numByte];
byteL = OutputImageArray[numByte+1];
curPixel= (byteH << 8) | (byteL);
//RGB565
red = (curPixel >> (6+5)) & 0x01F;
green = (curPixel >> 5) & 0x03F;
blue = (curPixel) & 0x01F;
//RGB888
red = red << 3;
green = green << 2;
blue = blue << 3;
//aRGB
curPixel = 0;
curPixel = (alpha << 24) | (red << 16) | (green << 8) | (blue);
NewImg.setRGB(i, j, curPixel);
numByte+=2;
}
}
I output this restored image. But I see that it looks very poor.
I expected the lost of pictures quality.
But as I thought, this picture has to have almost the same quality as the previous picture. Is it right?
Is my code right?

The reason you see these yellow artefacts is simply due to negative values for byteL overwriting bits from byteH containing the correct values for red and (part of) green channels. Let me explain.
Remember, if the highest bit in a byte is set to 1, the value is considered negative (-128 to -1 instead of 128 to 255), and by converting it to an int all the extra high-bits are set to 1 to conserve the same values (-128 to -1).
In your program, these extra bits set to 1 are in direct conflict with the value in byteH when applying the OR bit-operator |, overwriting (saturating) the red and (part of) green values you are trying to extract and display.
curPixel = (byteH << 8) | (byteL); // BUG: issue with negative byteL values
A solution is to apply an AND-mask to be sure to get rid of any unwanted bits before applying the OR bit-operator.
curPixel = byteL & 0xFF; // Convert byte to int to be within [0 , 255]
curPixel = (byteH << 8) | curPixel; // Apply OR bit-operator

Related

Getting a grey level image back from a color image in android after bitwise extraction

The following code shows a part of my code.
When I delete the part between '// start of color extraction & composing'
and '// end of color extraction & composing' I always get the same color image back
in tmpBmp. But if I insert the part, then I always get a grey-level image
displayed (whereas I'm expecting the same color image).
Is there any reason that the code between '// start of color extraction & composing' and '// end of color extraction & composing' returns a grey-scaled image?
int width = captureBmp.getWidth();
int height = captureBmp.getHeight();
int red, green, blue, alpha;
Bitmap tmpBmp = captureBmp.copy(Bitmap.Config.ARGB_8888, true);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int value = captureBmp.getPixel(x, y);
// start of color extraction & composing
alpha = value & 0xFF000000 >> 24;
red = value & 0x00FF0000 >> 16;
green = value & 0x0000FF00 >> 8;
blue = value & 0x000000FF;
value = ( (alpha << 24) & 0xFF000000) |
( (red << 16) & 0x00FF0000) |
((green << 8) & 0x0000FF00) |
(blue & 0x000000FF);
// end of color extraction & composing
tmpBmp.setPixel(x, y, value);
}
}
ImageView imgView = (ImageView) findViewById(R.id.imageview);
imgView.setImageBitmap(tmpBmp);
The line
red = value & 0x00FF0000 >> 16
is the same as
red = value & (0x00FF0000 >> 16)
Note that (0x00FF0000 >> 16) is just 0x000000FF. The same happens for green and blue, so you get the same value three times. Hence it's grey.
The alpha value is different because 0xFF000000 >> 24 is 0xFFFFFFFF due to the way the signed right shift works.
The solution is to rebracket. (I'd also use >>> for this, but it actually makes no difference because alpha gets shifted back 24 places left anyway).
alpha = (value & 0xFF000000) >>> 24;
red = (value & 0x00FF0000) >>> 16;
green = (value & 0x0000FF00) >>> 8;
blue = value & 0x000000FF;
The problem is that this code:
alpha = value & 0xFF000000 >> 24;
red = value & 0x00FF0000 >> 16;
green = value & 0x0000FF00 >> 8;
blue = value & 0x000000FF;
First masks with bitwise mask and then shifts, try the opposite. Shift then, bitmask with 0xFF.
It probabbly has to do with byte formats and unsigned integers and unsigned right shift in java.
As already noted by #Paul Boddington operator precedence plays a major part.

Java BufferedImage

I have stored a RGB image in a BufferedImage, what I want to do is take each color (eg. red) and store it in a new BufferedImage. So at the end, I will have four BufferedImage, the original one and one for each color. Each BufferedImage for each color should be 8 bits per pixel and this 8 bits contain the color value.
This is what I did.
String fileName = "test.jpg";
File inFile = new File(fileName);
BufferedImage refImg = ImageIO.read(inFile);
BufferedImage redImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), BufferedImage.TYPE_BYTE_GRAY); // LINE 4
BufferedImage greenImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), refImg.getType());
BufferedImage blueImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), refImg.getType());
for (int i = 0; i < refImg.getWidth(); i++)
for (int j = 0; j < refImg.getHeight(); j++)
{
int rgb = refImg.getRGB(i, j);
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
int ronly = (red << 16) | (0 << 8) | 0;
int gonly = (0 << 16) | (green << 8) | 0;
int bonly = (0 << 16) | (0 << 8) | blue;
redImage.setRGB(i, j, ronly);
greenImage.setRGB(i, j, gonly);
blueImage.setRGB(i, j, bonly);
}
File redOut = new File("testRed.jpg");
File greenOut = new File("testGreen.jpg");
File blueOut = new File("testBlue.jpg");
ImageIO.write(redImage, "jpg", redOut);
ImageIO.write(greenImage, "jpg", greenOut);
ImageIO.write(blueImage, "jpg", blueOut);
However, I am still in the RGB color model. When I changed the type of the bufferedImage for the red one to GRAY (LINE 4), I do not get the red component.
Any help or direction.
It's a bit hard to understand what you are trying to achieve here... If you make the images TYPE_BYTE_GRAY, they will be gray.
Also, if you want to store as JPEG, you have to choose between single channel gray or 3 channel RGB. You can't have single channel red/green/blue.
So, you basically have two options:
In addition to the original RGB image, you could have 3 gray images, stored as grayscale JPEGs. You will need to change some code:
BufferedImage redImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
BufferedImage greenImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
BufferedImage blueImage = new BufferedImage(refImg.getWidth(), refImg.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
...
int ronly = (red << 16) | (red << 8) | red;
int gonly = (green << 16) | (green << 8) | green;
int bonly = (blue << 16) | (blue << 8) | blue;
redImage.setRGB(i, j, ronly);
greenImage.setRGB(i, j, gonly);
blueImage.setRGB(i, j, bonly);
These images will contain the red, green and blue channels respectively, but they will by default display as gray. You can use LookupOp to convert your images back to all-red/green/blue RGB for display purposes, if needed.
The alternative is to have 3 RGB images containing only red, green and blue (like your initial attempt). These images will be RGB, have 3 channels and store as RGB (as YCbCr, most likely) JPEGs.
A third option would be to use an all-red/green/blue (256 shades) palette IndexColorModel. But JPEG can't store palette/indexed images, so they will have to be converted back to RGB, or you can change the file format to PNG, GIF or BMP.

Incorrect result of image subtraction

I wanted to subtract two images pixel by pixel to check how much they are similar. Images have the same size one is little darker and beside brightness they don't differ. But I get those little dots in the result. Did I subtract those two images rigth? Both are bmp files.
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Main2 {
public static void main(String[] args) throws Exception {
int[][][] ch = new int[4][4][4];
BufferedImage image1 = ImageIO.read(new File("1.bmp"));
BufferedImage image2 = ImageIO.read(new File("2.bmp"));
BufferedImage image3 = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
int color;
for(int x = 0; x < image1.getWidth(); x++)
for(int y = 0; y < image1.getHeight(); y++) {
color = Math.abs(image2.getRGB(x, y) - image1.getRGB(x, y));
image3.setRGB(x, y, color);
}
ImageIO.write(image3, "bmp", new File("image.bmp"));
}
}
Image 1
Image 2
Result
The problem here is that you can't subtract the colors direcly. Each pixel is represented by one int value. This int value consists of 4 bytes. These 4 bytes represent the color components ARGB, where
A = Alpha
R = Red
G = Green
B = Blue
(Alpha is the opacity of the pixel, and always 255 (that is, the maximum value) in BMP images).
Thus, one pixel may be represented by
(255, 0, 254, 0)
When you subtract another pixel from this one, like (255, 0, 255, 0), then the third byte will underflow: It would become -1. But since this is part of ONE integer, the resulting color will be something like
(255, 0, 254, 0) -
(255, 0, 255, 0) =
(255, 255, 255, 0)
and thus, be far from what you would expect in this case.
The key point is that you have to split your color into the A,R,G and B components, and perform the computation on these components. In the most general form, it may be implemented like this:
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
int a0 = (argb0 >> 24) & 0xFF;
int r0 = (argb0 >> 16) & 0xFF;
int g0 = (argb0 >> 8) & 0xFF;
int b0 = (argb0 ) & 0xFF;
int a1 = (argb1 >> 24) & 0xFF;
int r1 = (argb1 >> 16) & 0xFF;
int g1 = (argb1 >> 8) & 0xFF;
int b1 = (argb1 ) & 0xFF;
int aDiff = Math.abs(a1 - a0);
int rDiff = Math.abs(r1 - r0);
int gDiff = Math.abs(g1 - g0);
int bDiff = Math.abs(b1 - b0);
int diff =
(aDiff << 24) | (rDiff << 16) | (gDiff << 8) | bDiff;
result.setRGB(x, y, diff);
Since these are grayscale images, the computations done here are somewhat redundant: For grayscale images, the R, G and B components are always equal. And since the opacity is always 255, it does not have to be treated explicitly here. So for your particular case, it should be sufficient to simplify this to
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
// Here the 'b' stands for 'blue' as well
// as for 'brightness' :-)
int b0 = argb0 & 0xFF;
int b1 = argb1 & 0xFF;
int bDiff = Math.abs(b1 - b0);
int diff =
(255 << 24) | (bDiff << 16) | (bDiff << 8) | bDiff;
result.setRGB(x, y, diff);
You did not "subtract one pixel from the other" correctly. getRGB returns "an integer pixel in the default RGB color model (TYPE_INT_ARGB)". What you are seeing is an "overflow" from one byte into the next, and thus from one color into the next.
Suppose you have colors 804020 - 404120 -- this is 3FFF00; the difference in the G component, 1 gets output as FF.
The correct procedure is to split the return value from getRGB into separate red, green, and blue, subtract each one, make sure they fit into unsigned bytes again (I guess your Math.abs is okay) and then write out a reconstructed new RGB value.
I found this which does what you want. It does seem to do the same thing and it may be more "correct" than your code. I assume it's possible to extract the source code.
http://tutorial.simplecv.org/en/latest/examples/image-math.html
/Fredrik Wahlgren

How Do I Change 4 Separate Int Values For Alpha, Red, Green, Blue into TYPE_INT_RGB?

thank you for your time :). I have already taken a look at Format of TYPE_INT_RGB and TYPE_INT_ARGB and now know how to convert this TYPE_INT_RGB into 4 separate values, but if I were to do a modification to each (say add 20 to each, so Alpha+=20, red+=20, and so on) how would I recombine these values into this TYPE_INT_RGB formatting? Thank you!
// to extract the components into individual ints.
int argb = something();
int red = 0xFF & ( argb >> 16);
int alpha = 0xFF & (argb >> 24);
int blue = 0xFF & (argb >> 0 );
int green = 0xFF & (argb >> 8 );
// to recreate the argb
int argb = (alpha << 24) | (red << 16 ) | (green<<8) | blue;
I would use java.awt.Color for this.
int ARGB = new Color(red, green, blue, alpha).getRGB();
I guess you are using bitwise operations to pull out the individual color channels, but again the Color class can hide those gory details.
Color color = new Color(ARGB);
int red = color.getRed();
int green = color.getGreen();
// etc.
I believe this should work
int RGB = alpha;
RGB = (RGB << 8) + red;
RGB = (RGB << 8) + green;
Rgb = (RGB << 8) + blue;
There's another way without bit shifting, but I'm sure you'll figure it out.
This one is okay, too:
int rgba = new java.awt.Color(r,g,b,a).getRGB();

signed int to unsigned byte and vice versa

I have a signed value e.g. -7368817
when I cast it to byte it will be something like: -113
I convert it to unsigned byte bye & 0xff and it will be something like 143
now I manipulate this byte value and after that I want to whole way back! to get the signed integer of the new byte. :)
Update
The whole story:
I have an image which is 8-bit depth and gray scale! it means that all pixels are presented using 1 byte
BufferedImage image = ImageIO.read(new File("my_grayscal_8bit_photo.jpg"));
int intPixel = image.getRGB(1, 1);
now I need some bit manipulation in this pixel but since it is int I must convert it to byte first:
byte bytePixel = (byte) intPixel;
and to make it unsigned:
int intPixel2 = bytePixel & 0xff;
now I do my bit manipulation and want to convert it to int and do:
image.setRGB(1, 1, neworiginalint);
The getRGB(int x, int y) method always returns an int pixel in the TYPE_INT_ARGB color model. To manually extract the red, green, blue and alpha values for the pixel you can do this:
int pixel = image.getRGB(1, 1);
int a = (pixel >> 24) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int g = (pixel >> 8) & 0xFF;
int b = pixel & 0xFF;
Or use the Color(int rgba, boolean hasalpha) constructor for convenience (at the cost of performance). Once you've manipulated the red, green, blue and alpha values (in the range of 0 to 255) you can recombine them back into an int for setting pixels:
int newPixel = (a << 24) | (r << 16) | (g << 8) | b;
Using the -7368817 pixel you mentioned with this code, the alpha is 255 (so no transparency) and the red, green and blue values are all 143. Since you're dealing with grayscale you could just pick any of red, green or blue to get the gray value. However on setting the pixel you're going to have set all three to maintain the grayscale since it's RGB. You could shortcut it a bit like so:
int pixel = image.getRGB(1, 1);
// extract your gray value from blue, assume red and green are same
int gray = pixel & 0xFF;
// this method does your manipulation on the gray value, 0 to 255
gray = manipulate(gray);
// recombine back into int, preserving the original alpha
int newPixel = (pixel & 0xFF000000) | (gray << 16) | (gray << 8) | gray;
// now you can set your new pixel
image.setRGB(1, 1, nexPixel);
Basically the trick is to use int as your unsigned byte. Just make sure you keep the values from 0 to 255 and everything should work fine.
Are you asking how to manipulate the least-significant byte in an signed int, without touching the more significant byte?
This can be done like this:
int i = -7368817; // 0xFF8F 8F8F
int b = i & 0xFF; // "signed byte", = 0x8F = 143
b += 0x2C; // your manipulation, result = 0xBB
i = (i & 0xFFFFFF00) | (b & 0xFF); // result of LSB modification = 0xFF8F8FBB
or in one step: i = (i & 0xFFFFFF00) | ((i + 0x2C) & 0xFF); if it is a simple manipulation.
If the manipulation can't ever produce an overflow, you can simply do it on the whole int:
i ^= 0x34; // i = 0xFF8F8FBB

Categories