I'm creating a simple program which accepts a gray scale image as an input and what I simply want to do is retrieve the color information of each pixel, store it in an array of objects I call PixelClass. The ultimate goal is simply to repaint the image to a new BufferedImage using the said acquired color information.
Code used to create the pixel array from a given image.
public static PixelClass[][] getPixelArray(BufferedImage bi){
int height = bi.getHeight();
int width = bi.getWidth();
PixelClass[][] pixelArray = new PixelClass[height][width];
for(int i = 0 ; i < height ; i++){
for(int j = 0 ; j < width ; j++){
pixelArray [i] [j] = new PixelClass(bi.getRGB(j, i));
}
}
return pixelArray;
}
Code used to attempt to repaint the said image, using the array of PixelClass objects
public void paintToPanel(PixelClass [][] pc, int height, int width){
BufferedImage nbi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
for ( int i = 0 ; i < height ; i++){
for ( int j = 0 ; j < width ; j++){
nbi.setRGB(j, i, pc[i][j].getRGBValue());
}
}
JLabel containerLabel = new JLabel(new ImageIcon(nbi));
containerLabel.setBounds(10,10,nbi.getHeight(), nbi.getWidth());
this.add(containerLabel);
}
Links to original images
http://sphotos.ak.fbcdn.net/hphotos-ak-snc4/hs1364.snc4/163667_172099429501181_100001033756527_413302_3062182_n.jpg
As you can see there is significant degradation on the quality of the image. The resulting image appear to be faded.
I would suggest you use the MemoryImageSource class. Something like :
byte[] pixels = // your pixels
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
int bits[] = new int[] {8};
ColorModel cm = new ComponentColorModel(cs, bits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
MemoryImageSource mis = new MemoryImageSource(width, height, cm, pixels, 0, width);
Image im = Toolkit.getDefaultToolkit().createImage(mis);
Related
I have a txt file with nrows, ncols etc and ex elevation values as numbers which we are supposed to make a map image of.
I have code (that works) but my problem is that the pixels are exactly one pixel big each, they actually have a cellsize also that already is defined(10m). When the code runs I get the smallest greyscale map ever, I want it to be atleast 10x10 cm big imageicon so I can se what's going on but I don't know where to set it please help. Already searched for ways to resize etc but noone really fit me, what about a setpixels solution?
public void mapColor()
{
int height = nRows; int width = nCols;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = image.getRaster();
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
double value = values[i][j];
int[] color = new int[3];
int colValue = getColorValue(value); //In this case Green to Red strength
int percentage = ((100*colValue)/255);
int R; int G; int B = 0;
//Formula: Red= 255*percentage /100 G= (255*(100-percentage))/100
R = (255*percentage)/100; G=(255*(100-percentage))/100;
R = Math.round(R); G= Math.round(G);
color[0]= R; color[1] = G; color[2] = B; //100% will be bright red and 50% yellow
raster.setPixel(j, i, color);
//System.out.println("Value " + value + " Red is " + R + " Green is " + G);
}
}
JFrame jf = new JFrame();
JLabel jl = new JLabel();
ImageIcon ii = new ImageIcon(image);
jl.setIcon(ii);
jf.add(jl);
jf.setSize(200, 200);
jf.setVisible(true);
}
This returns an image that is 2x2mm big, values is a double array with all elevation data. It's my first java course ever I want easy solutions.
The most simple solution would be to use the getScaledInstance method
and use the resulting image to create the ImageIcon:
Image scaledImage = image.getScaledInstance(200 * nRows, 200 * nCols, Image.SCALE_DEFAULT);
ImageIcon ii = new ImageIcon(scaledImage);
Here i'm trying to do a fastest method to save 3 matrix(R, G and B) into a BufferedImage.
I've found this method here at StackExchange, but it doesn't work for me because the image it's being saved in a grayscale color.
If I'm doing something wrong or if there's a way of doing this faster than bufferimage.setRGB(), please help me. Thanks!
public static BufferedImage array_rasterToBuffer(int[][] imgR,
int[][]imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
int numBandas = 3;
int[] pixels = new int[width*height*numBandas];
int cont=0;
System.out.println("max: "+width*height*3);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int band = 0; band < numBandas; band++) {
pixels[(((i*width)+j)*numBandas +band)] =Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
cont+=1;
}
}
}
BufferedImage bufferImg = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
WritableRaster rast = (WritableRaster) bufferImg.getData();
rast.setPixels(0, 0, width, height, pixels);
bufferImg.setData(rast);
return bufferImg;
}
I think you are getting grey because the expression
Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
does not depend on band, so your rgb values are all the same.
The expression looks dodgy anyway because you normally use the left shift operator << when packing rgb values into a single int.
I don't know for sure, as I'm not familiar with the classes you are using, but I'm guessing something like this might work
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixels[(((i*width)+j)*numBandas)] = imgR[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 1)] = imgG[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 2)] = imgB[i][j] & 0xFF;
}
}
If you want a faster approach, you need to get the "live" WritableRaster from the BufferedImage and set pixels in the "native" format of the image, which is "pixel packed" for TYPE_INT_RGB. This will save you multiple (at least two) array copies and some data conversion. It will also save you 2/3rds of the memory used for the conversion, as we only need a single array component per pixel.
The below method should be quite a bit faster:
public static BufferedImage array_rasterToBuffer(int[][] imgR, int[][] imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
// The bands are "packed" for TYPE_INT_RGB Raster,
// so we need only one array component per pixel
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// "Pack" RGB values to native TYPE_INT_RGB format
// (NOTE: Do not use Math.abs on these values, and without alpha there won't be negative values)
pixels[((y * width) + x)] = ((imgR[y][x] & 0xff) << 16 | (imgG[y][x] & 0xff) << 8 | (imgB[y][x] & 0xff));
}
}
BufferedImage bufferImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// NOTE: getRaster rather than getData for "live" view
WritableRaster rast = bufferImg.getRaster();
// NOTE: setDataElements rather than setPixels to avoid conversion
// This requires pixels to be in "native" packed RGB format (as above)
rast.setDataElements(0, 0, width, height, pixels);
// No need for setData as we were already working on the live data
// thus saving at least two expensive array copies
return bufferImg;
}
// Test method, displaying red/green/blue stripes
public static void main(String[] args) {
int[][] fooR = new int[99][99];
int[][] fooG = new int[99][99];
int[][] fooB = new int[99][99];
for (int i = 0; i < 33; i++) {
Arrays.fill(fooR[i], 0xff);
Arrays.fill(fooG[i + 33], 0xff);
Arrays.fill(fooB[i + 66], 0xff);
}
BufferedImage image = array_rasterToBuffer(fooR, fooG, fooB);
showIt(image);
}
// For demonstration only
private static void showIt(final BufferedImage image) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("JPEGTest");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new JLabel(new ImageIcon(image)));
scroll.setBorder(BorderFactory.createEmptyBorder());
frame.add(scroll);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
It is possible to optimize this further, if you don't need a "managed" (possible hardware accelerated for display) image. The trick is to create the image directly "around" your pixels array, thus saving one more array allocation and array copy in setDataElements. The downside is that in some cases the image will be a little slower to draw onto the screen. This is mainly a concern for games or smooth animations though.
Replace the lines from BufferedImage bufferImg = new BufferedImage... until the return statement, with the following code:
DataBufferInt buffer = new DataBufferInt(pixels, pixels.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF}; // RGB (no alpha)
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, bandMasks, null);
ColorModel cm = new DirectColorModel(32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0x00000000 // No Alpha
);
BufferedImage bufferImg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
PS: Note that I also changed the shifts inside the x/y loop, from right to left shifts. Might have been just a minor typo. :-)
Hi everyone i have problems in converting GrayScale bmp images into integer 2D-array (with values 0-255) in Java.
I have a pmb image that could be seen as an integer(0-255) 2D-array and i want to see that 2D-array in a Java data structure
i tried this way:
Image image = ImageIO.read(new File("my_img.bmp"));
BufferedImage img = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
Then with my BufferedImage i create int[][] this way:
int w = img.getWidth();
int h = img.getHeight();
int[][] array = new int[w][h];
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
array[j][k] = img.getRGB(j, k);
}
}
But now all the 2D-array is full of number like "-9211021" or similar.
i think that the problem is in getRGB(j,k) but i don't know if it's possible to solve it.
edit:
i know RGB is not grayscale, so how can i get the grayscale value of a single pixel from a grayscale BufferedImage?
In a grayscale image, BufferedImage.getPixel(x,y) wont give values within the [0-255] range. Instead, it returns the corresponding value of a gray level(intensity) in the RGB colorspace. That's why you are getting values like "-9211021".
The following snippet should solve your problem :
Raster raster = image.getData();
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
array[j][k] = raster.getSample(j, k, 0);
}
}
where image is the created BufferedImage. The 0 in the getSample indicates that we are accessing the first byte/band(setting it to a greater value will throw a ArrayOutOfBoundException in grayscale images).
You can use Catalano Framework. Contains several filters for image processing.
http://code.google.com/p/catalano-framework/
Detail: That's it faster than using WritableRaster.
FastBitmap fb = new FastBitmap(bufferedImage);
int[][] image = new int[fb.getHeight()][fb.getWidth];
fb.toArrayGray(image);
//Do manipulations with image
//...
//Place the image into fastBitmap
fb.arrayToImage(image);
//Retrieve in bufferedImage if you desire.
bufferedImage = fb.toBufferedImage();
I'm attempting to take a picture as input, then manipulate said picture (I specifically want to make it greyscale) and then output the new image. This is a snippet of the code that I'm editing in order to do so but I'm getting stuck. Any ideas of what I can change/do next. Greatly appreciated!
public boolean recieveFrame (Image frame) {
int width = frame.width();
int height = frame.height();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color c1 = frame.get(i, j);
double greyScale = (double) ((Color.red *.3) + (Color.green *.59) + (Color.blue * .11));
Color newGrey = Color.greyScale(greyScale);
frame.set(i, j, newGrey);
}
}
boolean shouldStop = displayImage(frame);
return shouldStop;
}
I'm going to try to stick as close as possible to what you already have. So, I'll assume that you are looking for how to do pixel-level processing on an Image, rather than just looking for a technique that happens to work for converting to greyscale.
The first step is that you need the image to be a BufferedImage. This is what you get by default from ImageIO, but if you have some other type of image, you can create a BufferedImage and paint the other image into it first:
BufferedImage buffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffer.createGraphics();
g.drawImage(image, 0, 0);
g.dispose()
Then, you can operate on the pixels like this:
public void makeGrey(BufferedImage image) {
for(int x = 0; x < image.getWidth(); ++x) {
for(int y = 0; y < image.getHeight(); ++y) {
Color c1 = new Color(image.getRGB(x, y));
int grey = (int)(c1.getRed() * 0.3
+ c1.getGreen() * 0.59
+ c1.getBlue() * .11
+ .5);
Color newGrey = new Color(grey, grey, grey);
image.setRGB(x, y, newGrey.getRGB());
}
}
}
Note that this code is horribly slow. A much faster option is to extract all the pixels from the BufferedImage into an int[], operate on that, and then set it back into the image. This uses the other versions of the setRGB()/getRGB() methods that you'll find in the javadoc.
How do I create an in-memory fully transparent SWT image and draw a black line on it with antialias enabled?
I expect the result to include only black color and alpha values ranging from 0 to 255 due to antialias...
I googled and tried everything that I could... is this possible at all?
This is how I did and it works:
Image src = new Image(null, 16, 16);
ImageData imageData = src.getImageData();
imageData.transparentPixel = imageData.getPixel(0, 0);
src.dispose();
Image icon = new Image(null, imageData);
//draw on the icon with gc
I was able to make this work, although it feels a bit hacky:
Display display = Display.getDefault();
int width = 10;
int height = 10;
Image canvas = new Image(display, width, height);
GC gc = new GC(canvas);
gc.setAntialias(SWT.ON);
// This sets the alpha on the entire canvas to transparent
gc.setAlpha(0);
gc.fillRectangle(0, 0, width, height);
// Reset our alpha and draw a line
gc.setAlpha(255);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
gc.drawLine(0, 0, width, height);
// We're done with the GC, so dispose of it
gc.dispose();
ImageData canvasData = canvas.getImageData();
canvasData.alphaData = new byte[width * height];
// This is the hacky bit that is making assumptions about
// the underlying ImageData. In my case it is 32 bit data
// so every 4th byte in the data array is the alpha for that
// pixel...
for (int idx = 0; idx < (width * height); idx++) {
int coord = (idx * 4) + 3;
canvasData.alphaData[idx] = canvasData.data[coord];
}
// Now that we've set the alphaData, we can create our
// final image
Image finalImage = new Image(canvasData);
// And get rid of the canvas
canvas.dispose();
After this, finalImage can be drawn into a GC with drawImage and the transparent parts will be respected.
I made it by allocating an ImageData, making it transparent then creating the Image from the data :
static Image createTransparentImage(Display display, int width, int height) {
// allocate an image data
ImageData imData = new ImageData(width, height, 24, new PaletteData(0xff0000,0x00ff00, 0x0000ff));
imData.setAlpha(0, 0, 0); // just to force alpha array allocation with the right size
Arrays.fill(imData.alphaData, (byte) 0); // set whole image as transparent
// Initialize image from transparent image data
return new Image(display, imData);
}
To scale with transparency, I've found that I have to manually set the alpha byte array as shown below. So the alpha ends up with nearest-neighbor anti aliasing.
public static Image scaleImage(Device device, Image orig, int scaledWidth, int scaledHeight) {
Rectangle origBounds = orig.getBounds();
if (origBounds.width == scaledWidth && origBounds.height == scaledHeight) {
return orig;
}
ImageData origData = orig.getImageData();
ImageData imData = new ImageData(scaledWidth, scaledHeight, origData.depth, origData.palette);
if (origData.alphaData != null) {
imData.alphaData = new byte[imData.width * imData.height];
for (int row = 0; row < imData.height; row++) {
for (int col = 0; col < imData.width; col++) {
int origRow = row * origData.height / imData.height;
int origCol = col * origData.width / imData.width;
byte origAlpha = origData.alphaData[origRow * origData.width + origCol];
imData.alphaData[row * imData.width + col] = origAlpha;
}
}
}
final Image scaled = new Image(device, imData);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
gc.setBackground(device.getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(0, 0, scaledWidth, scaledHeight);
gc.drawImage(orig, 0, 0, origBounds.width, origBounds.height, 0, 0, scaledWidth, scaledHeight);
gc.dispose();
return scaled;
}