Java BufferedImage - java

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.

Related

When I Read a Image Pixel the pixel Alpha is always 255

In the following code example I set an Image pixel Alpha value to 70 but when I extract it again I get 255. Am I extracting it wrong or setting it wrong? what am I missing or not understanding.
public void createImage()
{
BufferedImage img = new BufferedImage(2, 2,
BufferedImage.TYPE_INT_RGB);
//Set Pixel
int red = 50;
int green = 10;
int blue = 100;
int alpha = 70;
int col = (alpha << 24) | (red << 16) | (green << 8) | blue;
img.setRGB(0, 0, col); //Set pixel 0,0
//Read Pixel
int colint = img.getRGB(0, 0); //Get pixel 0,0
Color newCol = new Color(colint,true);
int alphaToPrint = newCol.getAlpha();
int redToPrint = newCol.getRed();
int greenToPrint = newCol.getGreen();
int blueToPrint = newCol.getBlue();
System.out.println("redToPrint :" +String.valueOf(redToPrint));
System.out.println("greenToPrint :" +String.valueOf(greenToPrint));
System.out.println("blueToPrint :" +String.valueOf(blueToPrint));
System.out.println("alphaToPrint :" +String.valueOf(alphaToPrint));
}
The result when running the code :
What I expected is to get 70 when reading the alpha value :
int alphaToPrint = newCol.getAlpha();
Please help.
Your BufferedImage has no alpha channel (TYPE_INT_RGB)
Use BufferedImage.TYPE_INT_ARGB instead (note the 'A')

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();

Java image conversion to RGB565

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

convert pixel values into RGB format

I a have the red, green and blue values of a pixel seperately. How to convert them into RBG format to create a new image? I basically need a reverse process for this:
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
int rgb = ((r << 16) | ((g << 8) | b);
assuming it's RGB888. Make sure r,g and b are all in the 0-255 range
It's a great practice to use the java.awt.Color class instead.
It will make the things simpler and easier. In your case it would be:
Color myColor = new Color(red, green, blue); //Construct the color
myColor.getRGB(); //Get the RGB of the constructed color
Or the inverse:
Color myColor = new Color(rgb); //Construct the color with the RGB value
myColor.getRed(); //Get the separate components of the constructed color
myColor.getGreen();
myColor.getBlue();
For more info, consult the Javadocs.

Categories