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;
}
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 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.
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 would like to take a picture in true black and white in my app. I searched for solutions (in this site too), but I always found solution to put a photo in gray scale (for example in this topic), but it's not what I am looking for ...
I also found a topic proposing this :
public static Bitmap createContrast(Bitmap src, double value) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// get contrast value
double contrast = Math.pow((100 + value) / 100, 2);
// scan through all pixels
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
// apply filter contrast for every channel R, G, B
R = Color.red(pixel);
R = (int) (((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if (R < 0) {
R = 0;
} else if (R > 255) {
R = 255;
}
G = Color.red(pixel);
G = (int) (((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if (G < 0) {
G = 0;
} else if (G > 255) {
G = 255;
}
B = Color.red(pixel);
B = (int) (((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if (B < 0) {
B = 0;
} else if (B > 255) {
B = 255;
}
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
return bmOut;
}
But the image quality is horrible ...
Is anyone having an idea please?
Thank you
If you like the image to be 1bit black/white you can use a simple (& slow) threshold algorithm
public static Bitmap createBlackAndWhite(Bitmap src) {
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// scan through all pixels
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
int gray = (int) (0.2989 * R + 0.5870 * G + 0.1140 * B);
// use 128 as threshold, above -> white, below -> black
if (gray > 128)
gray = 255;
else
gray = 0;
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, gray, gray, gray));
}
}
return bmOut;
}
But depending on what that will not look good, for better results you need a dithering algorithm, see Algorithm overview - this one is the threshold method.
For 256 levels of gray conversion:
according to http://www.mathworks.de/help/toolbox/images/ref/rgb2gray.html you calculate the gray value of each pixel as gray = 0.2989 * R + 0.5870 * G + 0.1140 * B which would translate to
public static Bitmap createGrayscale(Bitmap src) {
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// scan through all pixels
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
int gray = (int) (0.2989 * R + 0.5870 * G + 0.1140 * B);
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, gray, gray, gray));
}
}
return bmOut;
}
But that is pretty slow since you have to do that for millions of pixels separately.
https://stackoverflow.com/a/9377943/995891 has a much nicer way of achieving the same.
// code from that answer put into method from above
public static Bitmap createGrayscale(Bitmap src) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmOut);
ColorMatrix ma = new ColorMatrix();
ma.setSaturation(0);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(ma));
canvas.drawBitmap(src, 0, 0, paint);
return bmOut;
}
G = Color.red(pixel);
G = Color.green(pixel);
B = Color.red(pixel);
B = Color.blue(pixel);
See if this changes (in bold) helps.
I want to show the jpeg image R_G_B channels as separated images in jlabel and the Y-Cb-Cr channels as well, I got the arrays but don't know how to convert them to images
///
Edit:
thanX very much , this is the method I'm writing ,Now It can display just the upper left quarter of the image ,and show it in a blue color whatever the color channel was?
public void getRGB_YCC(int width,int height,String inFileName) {
R=new int[height][width];G=new int[height][width];
B=new int[height][width];Y=new int[height][width];
Cb1=new int[height][width];Cr1=new int[height][width];
final int values[] = new int[width * height];
int r, g, b, Y_ch,Cb,Cr, y, x;
final PixelGrabber grabber = new PixelGrabber(image.getSource(), 0, 0,width,height, values, 0, width);
try {
if (grabber.grabPixels() != true) {
try {
throw new AWTException("Grabber returned false: " + grabber.getStatus());
} catch (final Exception e) {};
}
} catch (final InterruptedException e) {};
int index = 0;
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
r = values[index] >> 16 & 0xff;
g = values[index] >> 8 & 0xff;
b = values[index] & 0xff;
Y_ch= (int)(0.299 * r + 0.587 * g + 0.114 * b);
Cb= 128 + (int) (-0.16874 * r - 0.33126 * g + 0.5 * b);
Cr= 128 + (int)(0.5 * r - 0.41869 * g - 0.08131 * b);
R [y][x]=r;
G [y][x]=g;
B [y][x]=b;
Y [y][x]=Y_ch;
Cb1[y][x]=Cb;
Cr1[y][x]=Cr;
index++;
}
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
for( y=0;y<height;y++)
{
for( x=0;x<width;x++)
{
pixels[x + y*width] =R[y][x]<<16;
}
}
jLabel15.setIcon(new ImageIcon(img));
}
A simple and fast way to get an array of pixels into an image is using BufferedImage:
This example creates a grayscale 8 bit image and retrieves a 'pixel buffer' for it:
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
byte[] pixels = ((DataBufferByte)img.getRaster().getDataBuffer()).getData();
This also works with RGB:
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
You now can set pixels by just writing to the pixels array like pixels[x + y * w] = value and the results are instantly visible.