I want to convert a color image to grayscale.First I getting the data of color image and change this data but when I want to create a gary image from this data I have a error like this...
getData() maethod:
public double[] getData(BufferedImage a){
double[] data2=new double[h*w];
int red=0,green=0,blue=0;
int counter=0;
for(int w1=0;w1<w;w1++){
for(int h1=0;h1<h;h1++){
int rgb=a.getRGB(w1,h1);
red=(rgb)>> 16;
green=(rgb)>>8;
blue=(rgb);
data2[counter]=(red+green+blue)/3;
counter++;
}
}
return data2;
}
createimage() method:
void createImage(){
double[] data1=getData(colorImage);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
WritableRaster raster = image.getRaster();
int counter = 0 ;
for(int i = 0; i<h; i++){
for(int j = 0; j<w; j++){
raster.setSample(i, j, 0, data1[counter]);
counter++;
}
}
}
as it looks for me, the i and j in the setSample call must be swapped. (or w and h in BufferedImage)
Related
In the following code am trying to read a grayscale image, store the pixel values in a 2D array and rewrite the image with a different name.
The code is
package dct;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.io.File;
import javax.imageio.ImageIO;
public class writeGrayScale
{
public static void main(String[] args)
{
File file = new File("lightning.jpg");
BufferedImage img = null;
try
{
img = ImageIO.read(file);
}
catch(Exception e)
{
e.printStackTrace();
}
int width = img.getWidth();
int height = img.getHeight();
int[][] arr = new int[width][height];
Raster raster = img.getData();
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
arr[i][j] = raster.getSample(i, j, 0);
}
}
BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_BYTE_GRAY);
byte[] raster1 = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(arr,0,raster1,0,raster1.length);
//
BufferedImage image1 = image;
try
{
File ouptut = new File("grayscale.jpg");
ImageIO.write(image1, "jpg", ouptut);
}
catch(Exception e)
{
e.printStackTrace();
}
}// main
}// class
For this code , the error is
Exception in thread "main" java.lang.ArrayStoreException
at java.lang.System.arraycopy(Native Method)
at dct.writeGrayScale.main(writeGrayScale.java:49)
Java Result: 1
How to remove this error to write the grayscale image?
I found this: "ArrayStoreException -- if an element in the src array could not be stored into the dest array because of a type mismatch." http://www.tutorialspoint.com/java/lang/system_arraycopy.htm
Two thoughts:
You're copying an int-array into a byte-array.
That's not part of the exceptions, but are the dimensions right? arr is a two-dimensional array, raster1 is a one-dimensional array.
And you can't just change the byte-array in a two-dimensional one ignoring the output of the method you're calling.
Change int[][] arr to byte[] arr like this.
byte[] arr = new byte[width * height * 4];
for (int i = 0, z = 0; i < width; i++) {
for (int j = 0; j < height; j++, z += 4) {
int v = getSample(i, j, 0);
for (int k = 3; k >= 0; --k) {
arr[z + k] = (byte)(v & 0xff);
v >>= 8;
}
}
}
I have some question, here is my code :
int W = img.getWidth();
int H = img.getHeight();
int [][] pixels = new int [W][H];
int [][][] rgb = new int [3][H][W];
for(int i=0;i<W;i++)
for(int j=0;j<H;j++){
pixels[i][j] = img.getRGB(i,j);
Color clr = new Color(pixels[i][j]);
rgb[0][j][i] = clr.getRed();
rgb[1][j][i] = clr.getGreen();
rgb[2][j][i] = clr.getBlue();
}
/*
pixels changing process
*/
//1st for
for(int[] asd : rgb[0])
System.out.println(Arrays.toString(asd));
//2nd for
for(int i=0;i<W;i++)
for(int j=0;j<H;j++){
/*Color myColor = new Color (rgb[0][i][j],rgb[1][i][j],rgb[2][i][j]);
int newrgb = myColor.getRGB();
img.setRGB(W,H,newrgb);*/
}
}
printing the red values with 1st works normally, but why I can't put that values using 2nd for ?
when I run the code, it issues ByteInterleavedRaster.setDataElements(int, int, Object) line: not available
I want to assign image colors with new values of rgb[0] (red), rgb[1] (green), rgb[2] (blue) that printed by using 1st for. When I expected it could work with 2nd for, it threw an error.
thanks in advance :)
I think this looks correct
int W = img.getWidth();
int H = img.getHeight();
int [][] pixels = new int [W][H];
int [][][] rgb = new int [3][W][H];
for(int i=0; i<W; i++)
for(int j=0; j<H; j++) {
pixels[i][j] = img.getRGB(i,j);
Color clr = new Color(pixels[i][j]);
rgb[0][i][j] = clr.getRed();
rgb[1][i][j] = clr.getGreen();
rgb[2][i][j] = clr.getBlue();
}
/*
pixels changing process
*/
for(int i=0; i<W; i++)
for(int j=0; j<H; j++){
Color myColor = new Color (rgb[0][i][j],
rgb[1][i][j],
rgb[2][i][j]);
int newrgb = myColor.getRGB();
img.setRGB(i, j, newrgb);
}
}
You have to change this line img.setRGB(W,H,newrgb) to this one img.setRGB(j,i,newrgb).
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.
Below is the following code that reads in RGB values using BufferedImage, and then simply writes them back out again to file. The resultant image is perfect, and looks good. No worries there.
I run a print test to print out the first 10 RBG int values. This is to test the "test.png" file, and then to test the resultant image - "new-test.png".
For some reason I am getting different RBG values between the two files.
E.g. (The first 3 RGB int values)
test.png : -16704215, -16704215, -16704215
new-test.png : -16638935, -16638935, -16573142
Can anyone identify to why I am getting different RBG values that printed out for both test files?
try
{
BufferedImage imgBuf = ImageIO.read(new File("test.png"));//also testing with GIFs, JPEGs
int w = imgBuf.getWidth();
int h = imgBuf.getHeight();
int[] RGBarray = imgBuf.getRGB(0,0,w,h,null,0,w);
//Arrays to store their respective component values
int [][] redPixels = new int [h][w];
int [][] greenPixels = new int [h][w];
int [][] bluePixels = new int [h][w];
for(int i=0; i<=10; i++)
{
//print out the first 10 RGB int values - testing purposes
System.out.println(RGBarray[i]);
}
//Separate the RGB int values into 3 array, red, green and blue ....
int x=0;
for(int row=0; row<h; row++)
{
for(int col=0; col<w; col++)
{
redPixels[row][col] = ((RGBarray[x]>>16)&0xff);
greenPixels[row][col] = ((RGBarray[x]>>8)&0xff);
bluePixels[row][col] = (RGBarray[x]&0xff);
x++;
}
}
//set pixels back using the setRBG() ...
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for(int row=0; row<h; row++)
{
for(int col=0; col<w; col++)
{
//use bit shifting to re-form the RGB int again
int rgb = (redPixels[row][col] & 0xff) << 16 | (greenPixels[row][col] & 0xff) << 8 | (bluePixels[row][col] & 0xff);
bufferedImage.setRGB(col, row, rgb);
}
}
}
catch(IOException i){}; // This exception format is only temporary !
Here is small modification of your code that also saves the image and then reads it back again. With this code I get exactly the same int values before and after.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.junit.Test;
public class PngReadWriteTest {
#Test
public void test(){
try
{
BufferedImage imgBuf = ImageIO.read(new File("test.png"));//also testing with GIFs, JPEGs
int w = imgBuf.getWidth();
int h = imgBuf.getHeight();
int[] RGBarray = imgBuf.getRGB(0,0,w,h,null,0,w);
//Arrays to store their respective component values
int [][] redPixels = new int [h][w];
int [][] greenPixels = new int [h][w];
int [][] bluePixels = new int [h][w];
System.out.println("IMAGE FIRST READ:");
printPixelValues(imgBuf);
//Separate the RGB int values into 3 array, red, green and blue ....
int x=0;
for(int row=0; row<h; row++)
{
for(int col=0; col<w; col++)
{
redPixels[row][col] = ((RGBarray[x]>>16)&0xff);
greenPixels[row][col] = ((RGBarray[x]>>8)&0xff);
bluePixels[row][col] = (RGBarray[x]&0xff);
x++;
}
}
//set pixels back using the setRBG() ...
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for(int row=0; row<h; row++)
{
for(int col=0; col<w; col++)
{
//use bit shifting to re-form the RGB int again
int rgb = (redPixels[row][col] & 0xff) << 16 | (greenPixels[row][col] & 0xff) << 8 | (bluePixels[row][col] & 0xff);
bufferedImage.setRGB(col, row, rgb);
}
}
System.out.println("IMAGE BEFORE SAVE:");
printPixelValues(bufferedImage);
//Save image as png
ImageIO.write(bufferedImage, "png", new File("new-test.png"));
BufferedImage newImage = ImageIO.read(new File("new-test.png"));//also testing with GIFs, JPEGs
System.out.println("IMAGE AFTER SECOND READ:");
printPixelValues(newImage);
}
catch(IOException i){}; // This exception format is only temporary !
}
private void printPixelValues(BufferedImage image){
int w = image.getWidth();
int h = image.getHeight();
int[] RGBarray = image.getRGB(0,0,w,h,null,0,w);
for(int i=0; i<=10; i++)
{
//print out the first 10 RGB int values - testing purposes
System.out.println(RGBarray[i]);
}
}
}
This will only work if you use PNG since it is lossless. If you use JPG you will not get the same result since it is lossy. when you save the file as a JPG it will not result in a file containing the exact same bytes as in your first image. The level of compression will affect the image. So even if the files looks just the same by eye, they will not be exactly the same.
I have tried to make method which changes one color of BufferedImage to be invisible.
I can't find solution myself so I ask for your help.
Here is method made by me:
public static BufferedImage makeWithoutColor(BufferedImage img, Color col)
{
BufferedImage img1 = img;
BufferedImage img2 = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img2.createGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(img1, null, 0, 0);
g.dispose();
for(int i = 0; i < img2.getWidth(); i++)
{
for(int j = 0; i < img2.getHeight(); i++)
{
if(img2.getRGB(i, j) == col.getRGB())
{
img2.setRGB(i, j, 0x8F1C1C);
}
}
}
return img2;
}
And here is one from tutorial i read.
public static BufferedImage makeColorTransparent(BufferedImage ref, Color color) {
BufferedImage image = ref;
BufferedImage dimg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = dimg.createGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(image, null, 0, 0);
g.dispose();
for(int i = 0; i < dimg.getHeight(); i++) {
for(int j = 0; j < dimg.getWidth(); j++) {
if(dimg.getRGB(j, i) == color.getRGB()) {
dimg.setRGB(j, i, 0x8F1C1C);
}
}
}
return dimg;
}
Your mistake is this line:
for(int j = 0; i < img2.getHeight(); i++)
should be:
for(int j = 0; j < img2.getHeight(); j++)
// ^ ^ as Ted mentioned...
I assume that by "invisible" you mean that you want to make one color transparent. You aren't going to be able to do it using this approach, because setRGB doesn't affect the alpha channel. You are better off using an image filter. Here's an approach taken from this thread:
public static Image makeWithoutColor(BufferedImage img, Color col)
{
ImageFilter filter = new RGBImageFilter() {
// the color we are looking for... Alpha bits are set to opaque
public int markerRGB = col.getRGB() | 0xFF000000;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0xFF000000) == markerRGB) {
// Mark the alpha bits as zero - transparent
return 0x00FFFFFF & rgb;
} else {
// nothing to do
return rgb;
}
}
};
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
This will turn any pixel with the indicated RGB color and any transparency to a fully transparent pixel of the same color.