I'm trying to get an image matriz (pixels configuration) in a fast way... In JAVA
I can get the matriz but depend the resolution of the pic, it takes a lot of time, so if somebody knows how to get it in a fast way, please tell me.
int a;
int r ;
int g ;
int b ;
for(int y = 0; y < bufImage2.getHeight(); y++) {
for(int x = 0 ; x < bufImage2.getWidth(); x++){
color = new Color(bufImage2.getRGB(x, y));
a = color.getAlpha();
r = color.getRed();
g = color.getGreen();
b = color.getBlue();
System.out.print(r+"."+g+"."+b+":");
}
That's the "for" that I use to get the RGB values.
If there are libraries or something to do it more fast tell me.
Thanks.
Based on a similar question found here, here is what i have found for you, BufferedImage has its own getRGB function, it just has to be processed to get the values at any point (pixX, pixY)
int w = image.getWidth();
int h = image.getHeight();
int[] dataBuffInt = image.getRGB(0, 0, w, h, null, 0, w);
int pixX = 25;
int pixY = 50;
Color c = new Color(dataBuffInt[pixX+pixY*w]);
System.out.println(c.getRed()); // = (dataBuffInt[100] >> 16) & 0xFF
System.out.println(c.getGreen()); // = (dataBuffInt[100] >> 8) & 0xFF
System.out.println(c.getBlue()); // = (dataBuffInt[100] >> 0) & 0xFF
System.out.println(c.getAlpha()); // = (dataBuffInt[100] >> 24) & 0xFF
Related
I got this error.
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
rgb2 cannot be resolved to a variable
its always the rgb2 array that caused the error. How to solve this problem?
BufferedImage img1 = ImageIO.read(file1);
BufferedImage img2 = ImageIO.read(file2);
int w = img1.getWidth();
int h = img1.getHeight();
long diff = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int rgb1[] = img1.getRGB(x, y, w, h, rgb1, 0, w);
int rgb2[]= img2.getRGB(x, y, w, h, rgb2, 0, w);
int index = y * w + x;
int r1 = (rgb1[index] >> 16) & 0xff;
int g1 = (rgb1[index] >> 8) & 0xff;
int b1 = (rgb1[index] ) & 0xff;
int r2 = (rgb2[index] >> 16) & 0xff;
int g2 = (rgb2[index]>> 8) & 0xff;
int b2 = (rgb2[index] ) & 0xff;
r2 += Math.abs(r2 - r1);
g2 += Math.abs(g2 - g1);
b2 += Math.abs(b2 - b1);
rgb2[index] = (((r2 & 0xff) << 16) + ((g2 & 0xff) << 8) +(b2 & 0xff));
rgb2[index] = (rgb2[index]*17);
}
}
int i = 0;
for (int y = 0; y < h; y++) {
int red = (y * 255) / (h - 1);
for (int x = 0; x < w; x++) {
int green = (x * 255) / (w - 1);
int blue = 128;
rgb2[i++] = (red << 16) | (green << 8) | blue;//the problem is at this line
}
}
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
image.setRGB(0, 0, w, h, rgb2, 0, w);
Graphics g = image.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
File imageFile = new File("saved.jpeg");
ImageIO.write(image, "jpg", imageFile);
}
I got this error after declare outside the loop.
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The local variable rgb1 may not have been initialized
int w = img1.getWidth();
int h = img1.getHeight();
int scale = w * h * 3;
int rgb1[] = img1.getRGB(0, 0, w, h, rgb1, 0, w);
int rgb2[] = img2.getRGB(0, 0, w, h, rgb2, 0, w);
Your problem is because rgb2[] is declared inside a for loop immediately before, in this line:
int rgb2[]= img2.getRGB(x, y, w, h, rgb2, 0, w);
Then the for loop ends, so rgb2[] falls out of scope and is released from memory, and no longer defined. If you want rgb2[] to be accessible from outside the loop, you have to say int rgb2[]; before the loop is called, so that the variable is in the same scope as the line where it needs to be called. Remember, scope is inherited downwards -- anything accessible immediately before the loop is accessible inside it -- but not the other way around.
You declared your rgb2 variable inside your first for loop, which is not visible to your second for loop, where the problem occurs. To fix it, simply declare rgb2 array before your for loops.
I'm writing a method that will attempt to find a color in a bufferedImage. At the moment, the method works by taking a screencap, and then scanning the image for a specific color. Now I'd like to add some RGB tolerence, so if the user is trying to find color (1, 3, 5) with tolerance 1, any color +-1 R, B or G will return true.
I could solve this by first generating a arrayList of RGB values that work, and then for each pixel I could go through the array and check with each value. The problem is that would probably get VERY slow for high tolerances on large images.
Is there a more efficient or possibly a built in way I can do this? Here is my method as it stands right now. Thank you!
public static Point findColor(Box searchArea, int color){
System.out.println("Test");
BufferedImage image = generateScreenCap(searchArea);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
if((image.getRGB(i, j)*-1)==color){
return new Point(i + searchArea.x1, j + searchArea.y1);
}
}
}
return new Point(-1, -1);
}
Edit: I'm using the int RGB values for all comparisons, so instead of Color[1, 1, 1], I use Color.getRGB() which returns a negative int which I convert to positive for end user simplicity.
You need to compare RGB values and not the "whole" color if you want to have a custom tolerance. Here is the code, it is not tested, but you get the idea :
public static Point findColor(Box searchArea, int r, int g, int b, int tolerance) {
// Pre-calc RGB "tolerance" values out of the loop (min is 0 and max is 255)
int minR = Math.max(r - tolerance, 0);
int minG = Math.max(g - tolerance, 0);
int minB = Math.max(b - tolerance, 0);
int maxR = Math.min(r + tolerance, 255);
int maxG = Math.min(g + tolerance, 255);
int maxB = Math.min(b + tolerance, 255);
BufferedImage image = generateScreenCap(searchArea);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
// get single RGB pixel
int color = image.getRGB(i, j);
// get individual RGB values of that pixel
// (could use Java's Color class but this is probably a little faster)
int red = (color >> 16) & 0x000000FF;
int green = (color >> 8) & 0x000000FF;
int blue = (color) & 0x000000FF;
if ( (red >= minR && red <= maxR) &&
(green >= minG && green <= maxG) &&
(blue >= minB && blue <= maxB) )
return new Point(i + searchArea.x1, j + searchArea.y1);
}
}
return new Point(-1, -1);
}
This is how I am doing to convert from RGB to CMYK using the more "correct" way - i.e using an ICC color profile.
// Convert RGB to CMYK with level shift (minus 128)
private void RGB2CMYK(int[] rgb, float[][] C, float[][] M, float[][] Y, float[][] K, int imageWidth, int imageHeight) throws Exception {
ColorSpace instance = new ICC_ColorSpace(ICC_Profile.getInstance(JPEGWriter.class.getResourceAsStream(pathToCMYKProfile)));
float red, green, blue, cmyk[];
//
for(int i = 0, index = 0; i < imageHeight; i++) {
for(int j = 0; j < imageWidth; j++, index++) {
red = ((rgb[index] >> 16) & 0xff)/255.0f;
green = ((rgb[index] >> 8) & 0xff)/255.0f;
blue = (rgb[index] & 0xff)/255.0f;
cmyk = instance.fromRGB(new float[] {red, green, blue});
C[i][j] = cmyk[0]*255.0f - 128.0f;
M[i][j] = cmyk[1]*255.0f - 128.0f;
Y[i][j] = cmyk[2]*255.0f - 128.0f;
K[i][j] = cmyk[3]*255.0f - 128.0f;
}
}
}
My problem is: it's prohibitively slow given a large image. In one case, it took about 104s instead of the usual 2s for me to write the data as a JPEG image. It turns out the above transform is the most time-consuming part.
I am wondering if there is any way to make it faster. Note: I am not going to use the cheap conversion algorithm one can find form the web.
Update: following haraldK's suggestion, here is the revised version:
private void RGB2CMYK(int[] rgb, float[][] C, float[][] M, float[][] Y, float[][] K, int imageWidth, int imageHeight) throws Exception {
if(cmykColorSpace == null)
cmykColorSpace = new ICC_ColorSpace(ICC_Profile.getInstance(JPEGWriter.class.getResourceAsStream(pathToCMYKProfile)));
DataBuffer db = new DataBufferInt(rgb, rgb.length);
WritableRaster raster = Raster.createPackedRaster(db, imageWidth, imageHeight, imageWidth, new int[] {0x00ff0000, 0x0000ff00, 0x000000ff}, null);
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorConvertOp cco = new ColorConvertOp(sRGB, cmykColorSpace, null);
WritableRaster cmykRaster = cco.filter(raster, null);
byte[] o = (byte[])cmykRaster.getDataElements(0, 0, imageWidth, imageHeight, null);
for(int i = 0, index = 0; i < imageHeight; i++) {
for(int j = 0; j < imageWidth; j++) {
C[i][j] = (o[index++]&0xff) - 128.0f;
M[i][j] = (o[index++]&0xff) - 128.0f;
Y[i][j] = (o[index++]&0xff) - 128.0f;
K[i][j] = (o[index++]&0xff) - 128.0f;
}
}
}
Update: I also found out it's much faster to do filter on a BufferedImage instead of a Raster. See this post: ARGB int array to CMYKA byte array convertion
You should get rid of the memory allocation within the innermost loop. new is a prohibitively expensive operation. Also it might kick the garbage collector into action, which adds a further penality.
If you can affort the memory consumption, you could create a lookup table:
private void RGB2CMYK(int[] rgb, float[][] C, float[][] M, float[][] Y, float[][] K, int imageWidth, int imageHeight) throws Exception {
ColorSpace cs = new ICC_ColorSpace(...);
int[] lookup = createRGB2CMYKLookup(cs);
for(int y = 0, index = 0; y < imageHeight; y++) {
for(int x = 0; x < imageWidth; x++, index++) {
int cmyk = lookup[rgb[index]];
C[y][x] = ((cmyk >> 24) & 255) - 128F;
M[y][x] = ((cmyk >> 16) & 255) - 128F;
Y[y][x] = ((cmyk >> 8) & 255) - 128F;
K[y][x] = ((cmyk ) & 255) - 128F;
}
}
}
static int[] createRGB2CMYKLookup(ColorSpace cs) {
int[] lookup = new int[16 << 20]; // eats 16m times 4 bytes = 64mb
float[] frgb = new float[3];
float fcmyk[];
for (int rgb=0; rgb<lookup.length; ++rgb) {
frgb[0] = ((rgb >> 16) & 255) / 255F;
frgb[1] = ((rgb >> 8) & 255) / 255F;
frgb[2] = ((rgb ) & 255) / 255F;
fcmyk = cs.fromRGB(frgb);
int c = (int) (fcmyk[0] * 255F);
int m = (int) (fcmyk[1] * 255F);
int y = (int) (fcmyk[2] * 255F);
int k = (int) (fcmyk[3] * 255F);
int icmyk = (c << 24) | (m << 16) | (y << 8) | k;
}
return lookup;
}
Now this may actually worsen performance for small images as it is. It will only help if you can re-use the lookup table for multiple images, but as your example looks you're using actually the same ICC profile over and over. Thus you could cache the lookup table and pay its initialization cost only once:
static int[] lookup;
static {
ColorSpace cs = new ICC_ColorSpace(...);
lookup = createRGB2CMYKLookup(cs);
}
// convert always using (the same) lookup table
private void RGB2CMYK(int[] rgb, float[][] C, float[][] M, float[][] Y, float[][] K, int imageWidth, int imageHeight) throws Exception {
for(int y = 0, index = 0; y < imageHeight; y++) {
for(int x = 0; x < imageWidth; x++, index++) {
int cmyk = lookup[rgb[index]];
C[y][x] = ((cmyk >> 24) & 255) - 128F;
M[y][x] = ((cmyk >> 16) & 255) - 128F;
Y[y][x] = ((cmyk >> 8) & 255) - 128F;
K[y][x] = ((cmyk ) & 255) - 128F;
}
}
}
You should probably use ColorConvertOp. It uses optimized native code on most platforms, and supports ICC profile transforms.
Not sure how fast it will work when using float based Rasters, but it does the job.
Something like:
ICC_Profile cmyk = ...;
ICC_Profile sRGB = ...;
ColorConvertOp cco = new ColorConvertOp(sRGB, cmyk);
Raster rgbRaster = ...;
WritableRaster cmykRaster = cco.filter(rgbRaster, null);
// Or alternatively, if you have a BufferedImage input
BufferedImage rgbImage = ...;
BufferedImage cmykImage = cco.filter(rgbImage, null);
Hi. I want rgb values in this format: In a 1d vector I want first R values, then G values, and then B Values. I tried to use this code:
pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0,
bitmap.getWidth(), bitmap.getHeight());
// int R, G, B,Y;
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int index = y * bitmap.getHeight() + x;
int R = (pixels[index] >> 16) & 0xff; // bitwise shifting
int G = (pixels[index] >> 8) & 0xff;
int B = pixels[index] & 0xff;
// R,G.B - Red, Green, Blue
// to restore the values after RGB modification, use
// next statement
pixels[index] = 0xff000000 | (R << 16) | (G << 8) | B;
}
}
bitmap.recycle();
} catch (NullPointerException exception) {
Log.e("Error Utils",
"Photo is damaged or does not support this format!");
}
return pixels;
But, I still have only a 300*200 1d array.
Not 300*200*3 1d array!
Maybe it's that what you try to do
public static int[] getPixel(Bitmap bitmap) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
int[] pixelIn = new int[width * height];
bitmap.getPixels(pixelIn, 0, width, 0, 0, width, height);
bitmap.recycle();
int[] pixelOut = new int[width * height * 3];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int index = y * height + x;
int R = (pixelIn[index] >> 16) & 0xff;
int G = (pixelIn[index] >> 8) & 0xff;
int B = (pixelIn[index] >> 0) & 0xff;
int indexOut = index * 3;
pixelOut[indexOut++] = R;
pixelOut[indexOut++] = G;
pixelOut[indexOut ] = B;
}
}
return pixelOut;
}
Untested but it should create an int[] (you should consider byte[]) that is filled [R][G][B][R][G][B]...
same for bytes
public static byte[] getPixelBytes(Bitmap bitmap) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final int total = width * height;
int[] pixelIn = new int[total];
bitmap.getPixels(pixelIn, 0, width, 0, 0, width, height);
bitmap.recycle();
byte[] pixelOut = new byte[total * 3];
int indexOut = 0;
for (int pixel : pixelIn) {
byte R = (byte) ((pixel >> 16) & 0xff);
byte G = (byte) ((pixel >> 8) & 0xff);
byte B = (byte) ((pixel ) & 0xff);
pixelOut[indexOut++] = R;
pixelOut[indexOut++] = G;
pixelOut[indexOut++] = B;
}
return pixelOut;
}
And to get it in three separate arrays like [R R R R][G G G G][B B B B]
public static byte[][] getPixelBytes(Bitmap bitmap) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final int total = width * height;
int[] pixelIn = new int[total];
bitmap.getPixels(pixelIn, 0, width, 0, 0, width, height);
bitmap.recycle();
byte[][] result = new byte[3][total];
int index = 0;
for (int pixel : pixelIn) {
byte R = (byte) ((pixel >> 16) & 0xff);
byte G = (byte) ((pixel >> 8) & 0xff);
byte B = (byte) ((pixel ) & 0xff);
result[0][index] = R;
result[1][index] = G;
result[2][index] = B;
index++;
}
return result;
}
The rgb values of the 5th (= index 4) pixel would be
byte R = result[0][4];
byte G = result[1][4];
byte B = result[2][4];
Or to separate that into 3 arrays
byte[] rArray = result[0]; // each 0 .. (width x height - 1)
byte[] gArray = result[1];
byte[] bArray = result[2];
Also don't forget that Java's byte is -128..127, not 0..255.
I'm trying to write a code that masks red and blue channel from the image inputed. I have retrieved R, G, B values but however stuck up in proceeding further. Can anyone help me in this please?
public class Green {
public static void main(String args[]) throws IOException {
BufferedImage bi = ImageIO.read(new File("image.jpg"));
for (int x = 0; x <= bi.getWidth(); x++) {
for (int y = 0; y <= bi.getHeight(); y++) {
int pixelCol = bi.getRGB(x, y);
int r = (pixelCol >> 16) & 0xff;
int b = pixelCol & 0xff;
int g = (pixelCol >> 8) & 0xff;
int px = 0;
px = (px | (g << 8));
bi.setRGB(x, y, px);
}
}
}
}
Some remarks:
Use an IDE (Integrated Development Environment) like Eclipse or NetBeans.
Use < instead of <= as condition in your for loops.
Use code formatting (that is a feature of the IDE)
For clearness, order r, g and b.
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = (color >> 0) & 0xff;
Since you said you were stuck, the only thing left to do is save the manipulated image:
ImageIO.write(bi, "JPG", new File("green.jpg"));
A little trick to perform the mask quickly is this:
bi.setRGB(x, y, bi.getRGB(x, y) & 0xff00ff00);
So, the clean working code should be this:
public class Green
{
public static void main(String args[]) throws IOException
{
/* Read the image */
BufferedImage bi= ImageIO.read(new File("image.jpg"));
/* Loop through all the pixels */
for (int x=0; x < bi.getWidth(); x++)
{
for (int y = 0; y < bi.getHeight(); y++)
{
/* Apply the green mask */
bi.setRGB(x, y, bi.getRGB(x, y) & 0xff00ff00);
}
}
/* Save the image */
ImageIO.write(bi, "JPG", new File("green_mask.jpg"));
}
}
In addition to copying and scaling images, the Java 2D API also filter an image. Filtering is drawing or producing a new image by applying an algorithm to the pixels of the source image.
Image filters can be applied by using the following method:
void Graphics2D.drawImage(BufferedImage img,
BufferedImageOp op,
int x, int y)
The BufferedImageOp parameter implements the filter.
See this document for Image filter examples: http://ptgmedia.pearsoncmg.com/images/9780132413930/samplechapter/0132413930_CH08.pdf