I used the accepted answer's code from this SO question. Now, I want to convert in back to a BufferedImage (preferably not with setRGB()). I've tried this:
private BufferedImage createImage(int[][] pixelData, BufferedImage outputImage){
final int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData();
System.arraycopy(pixelData, 0, outputImagePixelData, 0, pixelData.length);
return outputImage;
}
but it doesn't work because it takes a 1D array as a parameter, not a 2D array.
If your outputImage has already the good type and format, then you can simply do a 2D to 1D conversion using loops (assuming your array encoding is [nbRows][RowLength]):
private BufferedImage createImage(int[][] pixelData, BufferedImage outputImage)
{
int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData() ;
final int width = outputImage.getWidth() ;
final int height = outputImage.getHeight() ;
for (int y=0, pos=0 ; y < height ; y++)
for (int x=0 ; x < width ; x++, pos++)
outputImagePixelData[pos] = pixelData[y][x] ;
return outputImage;
}
But, the type INT is not really well defined in the BufferedImage. By default, you have TYPE_INT_RGB and TYPE_INT_ARGB, which concatenates the R, G, B, A values of a pixel encoding with a single INT. If you want to create a gray level BufferedImage of type INT with a single channel, then you should do:
private BufferedImage createImage(int[][] pixelData)
{
final int width = pixelData[0].length ;
final int height = pixelData.length ;
// First I create a BufferedImage with a DataBufferInt, with the appropriate dimensions and number of channels/bands/colors
ColorSpace myColorSpace = new FloatCS(ColorSpace.TYPE_GRAY, channel) ;
int[] bits = new int[]{32} ;
ColorModel myColorModel = new ComponentColorModel(myColorSpace,bits,false,false,ColorModel.OPAQUE,DataBuffer.TYPE_INT) ;
BufferedImage outputImage = new BufferedImage(myColorModel, myColorModel.createCompatibleWritableRaster(width, height), false, null) ;
int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData() ;
for (int y=0, pos=0 ; y < height ; y++)
for (int x=0 ; x < width ; x++, pos++)
outputImagePixelData[pos] = pixelData[y][x] ;
return outputImage ;
}
With FloatCS being the ColorSpace class. You have to create you own ColorSpace class when you want specific ColorSpace like Lab, HLS, etc.
public class FloatCS extends ColorSpace
{
private static final long serialVersionUID = -7713114653902159981L;
private ColorSpace rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB) ;
public FloatCS(int type, int channel)
{
super(type, channel) ;
}
#Override
public float[] fromCIEXYZ(float[] pixel)
{
return fromRGB(rgb.fromCIEXYZ(pixel)) ;
}
#Override
public float[] fromRGB(float[] RGB)
{
return RGB ;
}
#Override
public float[] toCIEXYZ(float[] pixel)
{
return rgb.toCIEXYZ(toRGB(pixel)) ;
}
#Override
public float[] toRGB(float[] nRGB)
{
return nRGB ;
}
}
Instead of using System.arraycopy, you can simply use a double for-loop and iterate over x/y, something like this:
private BufferedImage createImage(int[][] pixelData, BufferedImage outputImage) {
int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData();
int width = outputImage.getWidth();
int height = outputImage.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
outputImagePixelData[y * width + x] = pixelData[x][y];
}
}
return outputImage;
}
The code above assumes that one array element corresponds to one pixel element (which is the case for all of the BufferedImage.TYPE_INT_* types).
Related
I have a code that puts an image in a pixel matrix.I have to split this image into four parts and get 4 different image files for these parts.
Then I have to do some image processing on it and then join those parts back together in a single image.
Please help me in achieving this.
Note:the image is colored and we want to just split it into 4 equal parts and then get it back as one.No changes needed.Here is the code to get four matrices of intensities.But I don't know what to do with it.It might be that there is no need of it at all.
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
class Optimization
{
public static void main(String[] args) throws IOException
{
BufferedImage hugeImage = ImageIO.read(new File("comp.jpg"));
final byte[] pixels = ((DataBufferByte) hugeImage.getRaster().getDataBuffer()).getData();
int width = hugeImage.getWidth();
int height = hugeImage.getHeight();
if(width%2!=0)
width=width-1;
if(height%2!=0)
height=height-1;
//System.out.print(width+" "+height);
int intensity[][]=new int[width][height];
int b1[][]=new int[width/2][height/2];
int b2[][]=new int[width/2][height/2];
int b3[][]=new int[width/2][height/2];
int b4[][]=new int[width/2][height/2];
int x1=0,y1=0,x2=0,y2=0,x3=0,x4=0,y3=0,y4=0;
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength)
{
int a1,a2,a3;
a3= ((int) pixels[pixel] & 0xff); // blue
a2= (((int) pixels[pixel + 1] & 0xff)); // green
a1= (((int) pixels[pixel + 2] & 0xff)); // red
int i=(a1+a2+a3)/3;
intensity[col][row]=i;
if((col<=width/2-1)&&(row<=height/2-1))
{
b1[x1][y1]=i;
x1++;
if(col==width/2-1)
{
x1=0;
y1++;
}
}
if((col<width)&&(row<=height/2-1)&&(col>width/2-1))
{
b2[x2][y2]=i;
x2++;
if(col==width-1)
{
x2=0;
y2++;
}
}
if((col<width/2)&&(row<height)&&(row>=height/2))
{
b3[x3][y3]=i;
x3++;
if(col==width/2-1)
{
x3=0;
y3++;
}
}
if((col>width/2-1)&&(row>height/2-1))
{
b4[x4][y4]=i;
x4++;
if(col==width-1)
{
x4=0;
y4++;
}
}
col++;
if (col == width)
{
col = 0;
row++;
}
}
for(int m=0;m<height/2;m++)
{
for(int n=0;n<width/2;n++)
{
System.out.print(b1[n][m]+" ");
}
System.out.println();
}
}
}
java.awt.Image provides you getSubimage(int x, int y, int w, int h)
"Returns a subimage defined by a specified rectangular region." You just return four equal regions and thats it.
You can use getSubImage(int x, int y, int w, int h), but you will get an image that shares the same raster than the original image, meaning that if you modify the new sub-image, then you also modify the original image. If it's not problematic for you, then use it.
Else, as you have already accessed the DataBuffer (good idea), here is a simple code to do what you want (I just make DataBuffer copies, and it works when the image dimensions are odd):
BufferedImage image = ... ;
BufferedImage q1 = new BufferedImage(image.getWidth()/2, image.getHeight()/2, image.getType()) ;
BufferedImage q2 = new BufferedImage(image.getWidth()-image.getWidth()/2, image.getHeight()/2, image.getType()) ;
BufferedImage q3 = new BufferedImage(image.getWidth()/2, image.getHeight()-image.getHeight()/2, image.getType()) ;
BufferedImage q4 = new BufferedImage(image.getWidth()-image.getWidth()/2, image.getHeight()-image.getHeight()/2, image.getType()) ;
byte[] bb = ((DataBufferByte)image.getRaster().getDataBuffer()).getData() ;
byte[] bbq1 = ((DataBufferByte)q1.getRaster().getDataBuffer()).getData() ;
byte[] bbq2 = ((DataBufferByte)q2.getRaster().getDataBuffer()).getData() ;
byte[] bbq3 = ((DataBufferByte)q3.getRaster().getDataBuffer()).getData() ;
byte[] bbq4 = ((DataBufferByte)q4.getRaster().getDataBuffer()).getData() ;
for (int y=0 ; y < q1.getHeight() ; y++) // Fill Q1 and Q2
{
System.arraycopy(bb, y*image.getWidth(), bbq1, y*q1.getWidth(), q1.getWidth()) ;
System.arraycopy(bb, y*image.getWidth()+q1.getWidth(), bbq2, y*q2.getWidth(), q2.getWidth()) ;
}
for (int y=0 ; y < q3.getHeight() ; y++) // Fill Q3 and Q4
{
System.arraycopy(bb, (y+q1.getHeight())*image.getWidth(), bbq3, y*q3.getWidth(), q3.getWidth()) ;
System.arraycopy(bb, (y+q1.getHeight())*image.getWidth()+q3.getWidth(), bbq4, y*q4.getWidth(), q4.getWidth()) ;
}
I am trying to shrink an image to half its height and width. This is what I have so far. I have no clue where to go from there.
One way to do it is to simply replace a group of pixels from the original image with a single pixel in the new shrunken image which is the average color over the group in the original.
I can also create a new array whose height and width are half the height and width of the image passed in as an argument. Then, insert new pixels into the new image as I figure out what the color values should be.
public class ImageManipulation
{
public static void main(String[] args) throws FileNotFoundException
{
Pixel[][] image = readImage("griff.ppm");
flipVertical(image);
writeImage(image,"manipulatedImage.ppm");
}
public static void grayscale(Pixel[][] imageArr)
{
int height = imageArr.length;
int width = imageArr[0].length;
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
Pixel p = imageArr[row][col];
int grayValue = (p.getRed() + p.getBlue() + p.getGreen())/3;
p.setBlue(grayValue);
p.setGreen(grayValue);
p.setRed(grayValue);
imageArr[row][col] = p;
}
}
}
public static void shrink (Pixel[][] imageArr)
{
int height = imageArr.length/2;
int width = imageArr[0].length/2;
No, you don't need to write all that code yourself :)
public BufferedImage shrink(File source, int w, int h) {
int dstWidth = w / 2;
int dstHeight = h / 2;
BufferedImage originalImage = ImageIO.read(source);
BufferedImage resizedImage = new BufferedImage(
dstWidth
, dstHeight
, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, dstWidth, dstHeight, null);
g.dispose();
return resizedImage;
}
Given an image file, say of PNG format, how to I get an array of int [r,g,b,a] representing the pixel located at row i, column j?
So far I am starting here:
private static int[][][] getPixels(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
int[][][] result = new int[height][width][4];
// SOLUTION GOES HERE....
}
Thanks in advance!
You need to get the packed pixel value as an int, you can then use Color(int, boolean) to build a color object from which you can extract the RGBA values, for example...
private static int[][][] getPixels(BufferedImage image) {
int[][][] result = new int[height][width][4];
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
Color c = new Color(image.getRGB(i, j), true);
result[y][x][0] = c.getRed();
result[y][x][1] = c.getGreen();
result[y][x][2] = c.getBlue();
result[y][x][3] = c.getAlpha();
}
}
}
It's not the most efficient method, but it is one of the simplest
BufferedImages have a method called getRGB(int x, int y) which returns an int where each byte is the components of the pixel (alpha, red, green and blue). If you dont want to do the bitwise operators yourself you can use Colors.getRed/Green/Blue methods by creating a new instance of Java.awt.Color with the int from getRGB.
You can do this in a loop to fill the three-dimensional array.
This is my code for this problem:
File f = new File(filePath);//image path with image name like "lena.jpg"
img = ImageIO.read(f);
if (img==null) //if img null return
return;
//3d array [x][y][a,r,g,b]
int [][][]pixel3DArray= new int[img.getWidth()][img.getHeight()][4];
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
int px = img.getRGB(x,y); //get pixel on x,y location
//get alpha;
pixel3DArray[x][y][0] =(px >> 24)& 0xff; //shift number and mask
//get red
pixel3DArray[x][y][1] =(px >> 16)& 0xff;
//get green
pixel3DArray[x][y][2] =(px >> 8)& 0xff;
//get blue
pixel3DArray[x][y][3] =(px >> 0)& 0xff;
}
}
How convert Image obj to Bitmap obj and vice versa?
I have a method that get Image object input and return Image object but i want give bitmap object input and then get bitmap object output my code is this:
public Image edgeFilter(Image imageIn) {
// Image size
int width = imageIn.getWidth();
int height = imageIn.getHeight();
boolean[][] mask = null;
Paint grayMatrix[] = new Paint[256];
// Init gray matrix
for (int i = 0; i <= 255; i++) {
Paint p = new Paint();
p.setColor(Color.rgb(i, i, i));
grayMatrix[i] = p;
}
int [][] luminance = new int[width][height];
for (int y = 0; y < height ; y++) {
for (int x = 0; x < width ; x++) {
if(mask != null && !mask[x][y]){
continue;
}
luminance[x][y] = (int) luminance(imageIn.getRComponent(x, y), imageIn.getGComponent(x, y), imageIn.getBComponent(x, y));
}
}
int grayX, grayY;
int magnitude;
for (int y = 1; y < height-1; y++) {
for (int x = 1; x < width-1; x++) {
if(mask != null && !mask[x][y]){
continue;
}
grayX = - luminance[x-1][y-1] + luminance[x-1][y-1+2] - 2* luminance[x-1+1][y-1] + 2* luminance[x-1+1][y-1+2] - luminance[x-1+2][y-1]+ luminance[x-1+2][y-1+2];
grayY = luminance[x-1][y-1] + 2* luminance[x-1][y-1+1] + luminance[x-1][y-1+2] - luminance[x-1+2][y-1] - 2* luminance[x-1+2][y-1+1] - luminance[x-1+2][y-1+2];
// Magnitudes sum
magnitude = 255 - Image.SAFECOLOR(Math.abs(grayX) + Math.abs(grayY));
Paint grayscaleColor = grayMatrix[magnitude];
// Apply the color into a new image
imageIn.setPixelColor(x, y, grayscaleColor.getColor());
}
}
return imageIn;
}
If you want to convert an Image object to a Bitmap and the format has been selected as JPEG, then you can accomplish this by using the following code (if it is not a JPEG, then additional conversions will be needed):
...
if(image.getFormat() == ImageFormat.JPEG)
{
ByteBuffer buffer = capturedImage.getPlanes()[0].getBuffer();
byte[] jpegByteData = new byte[buffer.remaining()];
Bitmap bitmapImage = BitmapFactory.decodeByteArray(jpegByteData, 0, jpegByteData.length, null);
}
...
This link gives more into on saving images as a png format.
it is difficult to see what you are attempting to do, are you trying to alter this code so it also works for bitmap formats?
here is a answer of someone doing stuff with bitmap images, should be give you a idea of what other people do
I'm trying to implement averaging filter with different sizes 3x3 , 5x5 , 7x7 and 11x11 .. I did the calculations and the results are correct while debugging but the problem is that it is saved in the writable raster in negative, so I'm getting weird results. The second weird thing is that when I want to get the value of the same pixel that was saved in negative, it is retrieved with positive value !!
I'm using int.
What's wrong? any help ?!!
Here is my code for the 5x5 averaging filter.
public static BufferedImage filter5x5_2D(BufferedImage paddedBI , BufferedImage bi , double[][]filter)
{
WritableRaster myImage = paddedBI.copyData(null);
BufferedImage img = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
WritableRaster myImage2 = img.copyData(null);
for(int i =2; i< myImage.getHeight()-2; i++)
{
for(int j =2; j< myImage.getWidth()-2; j++)
{
int value = 0;
int copyi = i-2;
for (int m = 0 ; m<5 ; m++)
{
int copyj = j-2;
for (int n = 0; n<5; n++)
{
int result = myImage.getSample(copyj , copyi, 0);
double f = filter[m][n];
double add = result * filter[m][n];
value += (int) (filter[m][n] * myImage.getSample(copyj , copyi, 0));
copyj ++;
}
copyi++;
//myImage2.setSample(j-1 , i-1, 0, value);
}
myImage2.setSample(j-2 , i-2, 0, value);
//int checkResult = myImage2.getSample(j-1,i-1,0);
}
}
BufferedImage res= new BufferedImage(bi.getWidth(),bi.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
res.setData(myImage2);
return res;
}
I do not find any negative values. Here is my main with what I have tested this code:
public static void main(String[] args) throws IOException {
BufferedImage bi = ImageIO.read(new File("C:/Tmp/test.bmp"));
BufferedImage newImage = new BufferedImage(bi.getWidth()+4, bi.getHeight()+4, bi.getType());
Graphics g = newImage.getGraphics();
g.setColor(Color.white);
g.fillRect(0,0,bi.getWidth()+4,bi.getHeight()+4);
g.drawImage(bi, 2, 2, null);
g.dispose();
double[][] filter = new double[5][5];
for( int i = 0; i < 5; ++i){
for( int j = 0; j < 5; ++j){
filter[i][j] = 1.0/(5*5);
}
}
BufferedImage filtered = filter5x5_2D(newImage, bi, filter);
ImageIO.write(filtered, "bmp", new File("C:/tmp/filtered.bmp"));
}
You should consider that your variables result, f and add are unused. Also it would be better if value would be of type double instead of int. In a worst case, you would get 25 times a value of 11 which will be rounded to zero after multiplying with 1/25. This would result in your code as a grey value of zero while it should result in 11.