I am trying to read the pixel values of the image using the below code
int[] pixel;
BufferedImage imageA = ImageIO.read(new File("xyz.bmp"));
for (int y = 0; y < imageA.getHeight(); ++y) {
for (int x = 0; x < imageA.getWidth(); ++x) {
pixel = imageA.getRaster().getPixel(x, y, new int[3]);
}}
values of RGB are stored in pixel[0],pixel[1] and pixel[2] respectively and when i saw the output i saw the values ranging between 0 to 255.
I saw some use the below code to get pixel values
int pixel;
BufferedImage imageA = ImageIO.read(new File("xyz.bmp"));
for (int y = 0; y < imageA.getHeight(); ++y) {
for (int x = 0; x < imageA.getWidth(); ++x) {
pixel = imageA.getRGB(x, y);
}}
When i saw the output for a particular pixel it was -14935264 . What does this value represent and whats the difference between the above two methods.
In the second case, you get an int that contains the RGB-values in the lower 24 bits. The red component is bits 23-16, the green component is bits 15-8 and the blue component is bits 7-0.
If you want to get the components out of the int:
int red = (pixel >> 16) & 0xFF;
int green = (pixel >> 8) & 0xFF;
int blue = pixel & 0xFF;
The other way around:
int pixel = (red << 16) | (green << 8) | blue;
Related
I'm currently having an issue with alpha channels when reading PNG files with ImageIO.read(...)
fileInputStream = new FileInputStream(path);
BufferedImage image = ImageIO.read(fileInputStream);
//Just copying data into an integer array
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, width, height, pixels, 0, width);
However, when trying to read values from the pixel array by bit shifting as seen below, the alpha channel is always returning -1
int a = (pixels[i] & 0xff000000) >> 24;
int r = (pixels[i] & 0xff0000) >> 16;
int g = (pixels[i] & 0xff00) >> 8;
int b = (pixels[i] & 0xff);
//a = -1, the other channels are fine
By Googling the problem I understand that the BufferedImage type needs to be defined as below to allow for the alpha channel to work:
BufferedImage image = new BufferedImage(width, height BufferedImage.TYPE_INT_ARGB);
But ImageIO.read(...) returns a BufferedImage without giving the option to specify the image type. So how can I do this?
Any help is much appreciated.
Thanks in advance
I think, your "int unpacking" code might be wrong.
I used (pixel >> 24) & 0xff (where pixel is the rgba value of a specific pixel) and it worked fine.
I compared this with the results of java.awt.Color and they worked fine.
I "stole" the "extraction" code directly from java.awt.Color, this is, yet another reason, I tend not to perform these operations this way, it's to easy to screw them up
And my awesome test code...
BufferedImage image = ImageIO.read(new File("BYO image"));
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
//value = 0xff000000 | rgba;
int a = (pixel >> 24) & 0xff;
Color color = new Color(pixel, true);
System.out.println(x + "x" + y + " = " + color.getAlpha() + "; " + a);
}
}
nb: Before some one tells that this is inefficient, I wasn't going for efficiency, I was going for quick to write
You may also want to have a look at How to convert get.rgb(x,y) integer pixel to Color(r,g,b,a) in Java?, which I also used to validate my results
I think the problem is that you're using arithmetic shift (>>) instead of logical shift (>>>). Thus 0xff000000 >> 24 becomes 0xffffffff (i.e. -1)
I'm trying to change the saturation of a particular image, in Java. I already know how to edit the hue and brightness of a pixel, but I'm stumped how to do saturation. Here's the loop I use to cycle through each of the pixels, if you need to know it. I know it isn't good for performance, but it's temporary.
Loop:
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
int r = (pixel >> 16) & 0xFF;
int g = (pixel >> 8) & 0xFF;
int b = (pixel) & 0xFF;
//Adjust saturation:
//?????????????????????
}
}
In short, I'm not sure how to change the saturation of a pixel, but I want to know how. The loop I'm using above is working perfectly, so no problems there. Thanks! :D
You can use:
int red = ...;
int green = ...;
int blue = ...;
float[] hsb = Color.RGBtoHSB(red, green, blue, null);
float hue = hsb[0];
float saturation = hsb[1];
float brightness = hsb[2];
/* then change the saturation... */
int rgb = Color.HSBtoRGB(hue, saturation, brightness);
red = (rgb>>16)&0xFF;
green = (rgb>>8)&0xFF;
blue = rgb&0xFF;
I have a 2D array which contains the RGB values. I need to create a valid image from these pixel values and save it. I have given the 2D array below. I wanted to implement this part in my project, so please help me with this. Thank you.
int[] pixels = new int[imageSize * 3];
int k = 0;
for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
if(k<imageSize*3)
{
pixels[k] = r[i][j];
pixels[k+1] = g[i][j];
pixels[k+2] = b[i][j];
}
k = k+3;
}
}
You can build a BufferedImage of type BufferedImage.TYPE_INT_RGB. This type represents a color as an int where:
3rd byte (16-23) is red,
2nd byte (8-15) is green and
1st byte (7-0) is blue.
You can get the pixel RGB value as follows:
int rgb = red;
rgb = (rgb << 8) + green;
rgb = (rgb << 8) + blue;
Example (Ideone full example code):
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int rgb = r[y][x];
rgb = (rgb << 8) + g[y][x];
rgb = (rgb << 8) + b[y][x];
image.setRGB(x, y, rgb);
}
}
File outputFile = new File("/output.bmp");
ImageIO.write(image, "bmp", outputFile);
For some reason, I can change a buffered image by using setRGB but not by using the actual int array in the raster:
This works
BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 32; x++) {
int gray = (int) (MathUtil.noise(x, y) * 255); //I have tested the noise function, and know it works fine
img.setRGB(x, y, gray << 16 | gray << 8 | gray);
}
}
This does not
BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_RGB);
int[] data = ((DataBufferInt) img.getData().getDataBuffer()).getData();
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 32; x++) {
int gray = (int) (MathUtil.noise(x, y) * 255); //I have tested the noise function, and know it works fine
data[x + y * 32] = gray << 16 | gray << 8 | gray;
}
}
Noise function:
public static float noise(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
return Math.abs((1.0f - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f));
}
EDIT
Nevermind I fixed it. I needed to use getRaster :P
Because when you call BufferedImage.getData() it is returning a copy, not the actual backing array. So any changes you make directly to that array will not be reflected in the image.
From the JavaDoc for BufferedImage.getData():
Returns:
a Raster that is a copy of the image data.
Edit What's interesting is what it says for the same method in the Java 6 JavaDoc, it's more explicit about the copy's effects. I wonder why they changed it?
Returns the image as one large tile. The Raster returned is a copy of the image data is not updated if the image is changed
Could the answer be as simple as the changes in the data array not being reflected in img object?
How to isolate red/green/blue channel in BufferedImage: I have following code that does NOT work:`
public static BufferedImage isolateChannel(BufferedImage image,
EIsolateChannel channel)
{
BufferedImage result=new BufferedImage(image.getWidth(),
image.getHeight(),
image.getType());
int iAlpha=0;
int iRed=0;
int iGreen=0;
int iBlue=0;
int newPixel=0;
for(int i=0; i<image.getWidth(); i++)
{
for(int j=0; j<image.getHeight(); j++)
{
iAlpha=new Color(image.getRGB(i, j)).getAlpha();
iRed=new Color(image.getRGB(i, j)).getRed();
iGreen=new Color(image.getRGB(i, j)).getGreen();
iBlue=new Color(image.getRGB(i, j)).getBlue();
if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
{
newPixel=iRed;
}
if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
{
newPixel=iGreen;
}
if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
{
newPixel=iBlue;
}
result.setRGB(i,
j,
newPixel);
}
}
return result;
}`
By isolating channel I mean that if red channel is selected for isolation, for example, that only red component of picture is shown!
Color in java is defined in a packed integer,that is in a 32 bit integer the first 8 bits are alpha, next 8 are red, next 8 are green and last 8 are blue.
Suppose the following is an 32 bit integer representing a color.Then,
AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
^Alpha ^Red ^Green ^Blue
That is, each of alpha, red, green and blue are basically 8 bits with values from 0 to 255 (the color range). So when you would want to combine these individual components back into the 32 bit integer color you should write
color=alpha<<24 | red<<16 | green<<8 | blue
So as per the rules change the code to the following
if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
{
newPixel = newPixel | iRed<<16;
//Can also write newPixel=iRed , since newPixel is always 0 before this
}
if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
{
newPixel = newPixel | iGreen<<8;
}
if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
{
newPixel = newPixel | iBlue;
}
Note : I have ORed the newPixel before each component to allow display of multiple channels simultaneously, i.e you could display red and green with blue turned off.
UPDATE
The second error you are getting is due to the fact that you are not resetting the value of newPixel after each iteration. So to fix it add the line newPixel=0 within the loop.
Your code should be
newPixel=0; //Add this line
iAlpha=new Color(img.getRGB(x, y)).getAlpha();
iRed=new Color(img.getRGB(x, y)).getRed();
iGreen=new Color(img.getRGB(x, y)).getGreen();
iBlue=new Color(img.getRGB(x, y)).getBlue();
For added efficiency I would suggest using bitshifts for obtaining the red, green, blue, and the alpha.
int rgb = img.getRGB(x,y);
iAlpha = rgb>>24 & 0xff;
iRed = rgb >>16 & 0xff;
iGreen = rgb>>8 & 0xff;
iBlue = rgb & 0xff;
This code would run faster as it does not creates 4 Color objects for each pixel in the source image
Try this:
int width = bufferedImage.getWidth(), height = bufferedImage.getHeight();
Object dataElements = null;
Raster raster = bufferedImage.getRaster();
ColorModel colorModel = bufferedImage.getColorModel();
int red, blue, green, alpha;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
dataElements = raster.getDataElements(x, y, dataElements);
// extract colors
red = colorModel.getRed(dataElements);
blue = colorModel.getBlue(dataElements);
green = colorModel.getGreen(dataElements);
alpha = colorModel.getAlpha(dataElements);
}
}