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.
Related
I would like to create an image filter and have read the following Wikipedia article. I wanted to test the example from Wikipedia and get an incorrect result.
https://en.wikipedia.org/wiki/Kernel_(image_processing)
(For some reason I cannot upload images)
Result:
https://imgur.com/FiYFuZS
Expected result:
https://upload.wikimedia.org/wikipedia/commons/2/20/Vd-Rige1.png
I've also read the following source and still do not know how to fix it :/
Bluring a Java buffered image
URL url = new URL("https://upload.wikimedia.org/wikipedia/commons/5/50/Vd-Orig.png");
BufferedImage image = ImageIO.read(url);
float[][] kernel = {
{0, -1, 0},
{-1, 4, -1},
{0, -1, 0}
};
int w = image.getWidth();
int h = image.getHeight();
// Center point
int cx = kernel.length / 2;
int cy = kernel[0].length / 2;
BufferedImage cImage = new BufferedImage(w, h, image.getType());
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
float r = 0;
float g = 0;
float b = 0;
for (int dx = -cx; dx <= cx; dx++) {
for (int dy = -cy; dy <= cy; dy++) {
float e = kernel[dx + cx][dy + cy];
int xImage = x + dx;
int yImage = y + dy;
if (xImage < 0 || xImage >= w || yImage < 0 || yImage >= h) {
continue;
}
Color pixel = new Color(image.getRGB(xImage, yImage));
r += pixel.getRed() * e;
g += pixel.getGreen() * e;
b += pixel.getBlue() * e;
}
}
// Boundaries
r = Math.min(255, Math.max(0, r));
g = Math.min(255, Math.max(0, g));
b = Math.min(255, Math.max(0, b));
Color newPixel = new Color((int) r, (int) g, (int) b);
cImage.setRGB(x, y, newPixel.getRGB());
}
}
ImageIO.write(cImage, "png", Files.newOutputStream(Path.of("c.png")));
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
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.
Can anyone let me know how can I read pixels from buffer in JOGL. Please illustrate with a code.
After rendering is done, call this method:
public BufferedImage toImage(GL gl, int w, int h) {
gl.glReadBuffer(GL.GL_FRONT); // or GL.GL_BACK
ByteBuffer glBB = ByteBuffer.allocate(3 * w * h);
gl.glReadPixels(0, 0, w, h, GL.GL_BGR, GL.GL_BYTE, glBB);
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int[] bd = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int b = 2 * glBB.get();
int g = 2 * glBB.get();
int r = 2 * glBB.get();
bd[(h - y - 1) * w + x] = (r << 16) | (g << 8) | b | 0xFF000000;
}
}
return bi;
}