2

My requirement is that, I need to convert a color image into gray scale image and obtain pixels values of gray scale image to an array and perform some encryption algorithm on that array and again using this changed pixel array, I need to convert back/create a gray scale image and display it. Here are my doubts.

  1. Using the color image I have obtained the RGB pixel values in three different arrays. As per my knowledge, gray scale pixels can be obtained by doing red+green+blue/3=gray. Here red, blue, green, gray are 2-D arrays. Is this right way to obtain gray scale pixel values?

    gray[x][y] = (r[x][y]+g[x][y]+b[x][y])/3;
    
  2. If this is correct, then I can easily perform algorithm on that array. The real problem arises here. How to convert back/create a gray scale image using that pixel array. An example to show how a gray scale image can be created using pixel values will be really helpful. Thank you.

    for(int x = 0;x<=height;x++) {
        for(int y = 0;y<=width;y++) {
            gray[x][y] = (r[x][y]+g[x][y]+b[x][y])/3;
            System.out.print(gray[x][y]+"\t");
        }
         System.out.println(" ");
    }
    
Tombart
  • 30,520
  • 16
  • 123
  • 136
user3364490
  • 113
  • 2
  • 10
  • See java.awt.Image.ColorModel – ControlAltDel Mar 26 '15 at 14:46
  • Color model is used to get RGB pixel values right? My requirement is to create a gray scale image using array of pixels – user3364490 Mar 26 '15 at 14:52
  • Check out this tutorial. http://www.java2s.com/Tutorial/Java/0261__2D-Graphics/ConvertingaColoredBufferedImagetoGray.htm Doesn't use the array directly, but if you have a BufferedImage it will do it for you. Do you have code sample of what you're trying to do? – Amber Mar 26 '15 at 14:53
  • well regarding my first question can gray scale pixel values can be obtained like the way I have mentioned in the code above? If yes, then I want to know how a gray scale buffered image can be created using the array gray[x][y] – user3364490 Mar 26 '15 at 15:03
  • The link you have mentioned in the comment is used to convert color image to gray scale image, it is no where related to pixel arrays or creating buffered image using pixel values, as per my knowledge. – user3364490 Mar 26 '15 at 15:08
  • @user3364490 I don't think the method you are suggesting will work. Color (255,0,0) has a bigger saturation value (right?) than Color (100,100,55); For grayscale, you probably care about saturation in the HSV ColorModel – ControlAltDel Mar 26 '15 at 16:23
  • So, can you tell me which method is suitable for my requirements? – user3364490 Mar 26 '15 at 17:25
  • "Is this right way to obtain gray scale pixel values?" It's one way. There are others. The way black and white film works is it has different sensitivities to different wavelengths, so there isn't a canonical approach to this. – David Ehrmann Mar 26 '15 at 20:35

3 Answers3

1

Instead of converting the image to grayscale by manipulating the pixels yourself I'd suggest creating a new BufferedImage of TYPE_BYTE_GRAY. Then you can manipulate the pixels directly.

public static BufferedImage convertToGray(BufferedImage biColor)
{
    BufferedImage biGray = new BufferedImage(biColor.getWidth(), biColor.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
    biGray.getGraphics().drawImage(biColor, 0, 0, null);
    return biGray;
}

public static void manipulatePixels(BufferedImage biGray)
{
    byte [] imageData = ((DataBufferByte)biGray.getRaster().getDataBuffer()).getData();

    for (int i = 0; i < imageData.length; i++)
    {
        // do manipulation/encryption here - or on the entire array at once
    }
}

If for some reason you want to create a brand new image from the byte array, just create a new image and copy the pixels into its byte array.

public static BufferedImage createImageFromArray(byte[] imageData, int width, int height)
{
    BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    byte [] newData = ((DataBufferByte) newImage.getRaster().getDataBuffer()).getData();

    for (int i = 0; i < imageData.length; i++)
    {
        newData[i] = imageData[i];
    }
    return newImage;
}
Amber
  • 2,413
  • 1
  • 15
  • 20
  • The example given is for grabbing pixel values of gray scale image, can you tell me how can I create a gray scale image using the pixel values (i.e.., imageData byte array to gray scale image.) – user3364490 Mar 26 '15 at 17:28
  • when I tried to display the imageData array, it is showing negative values like -1 in the array. I thought that byte values are different from int values and again tried to create an image using the same byte values but it is not working. – user3364490 Mar 27 '15 at 05:51
  • so I felt like what ever byte values I tried to obtain are wrong values. byte [] newData = ((DataBufferByte) newImage.getRaster().getDataBuffer()).getData(); This line is giving wrong bytes. – user3364490 Mar 27 '15 at 05:52
  • It is expected that you would get some negative values. Have you tried saving the image to see what it looks like? i.e. ImageIO.write(image, "JPEG", new FileImageOutputStream(new File("image.jpg"))); – Amber Mar 27 '15 at 15:03
  • Image itself is not saving.. I think because of that byte array only. – user3364490 Mar 28 '15 at 03:38
0

there are multiple ways to transform a color to a greyscale, your way is the simpliest and correct.

you can Turn your array back into a picture by using this http://www.java2s.com/Tutorial/Java/0261__2D-Graphics/CreateBufferredImagewithcolorsbasedonintegerarray.htm

BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
image.setRGB(0, 0, width, height, data, 0, width);

while data is a 1D IntegerArray with the length (hope I didnt mix up the indices)

int[] data=new int[height*width];
for (int i=0;i<height;i++){
    for (int k=0;k<width;k++){
        //EDIT: The gray[][] array, is the one you already got.
        data[i*width+k]=getIntFromColor(gray[i][k],gray[i][k],gray[i][k]);
    }
}

where the method of creating the correct Integer from your colorcode (int, int, int) is given in: how to convert rgb color to int in java

public int getIntFromColor(int Red, int Green, int Blue){
    Red = (Red << 16) & 0x00FF0000; //Shift red 16-bits and mask out other stuff
    Green = (Green << 8) & 0x0000FF00; //Shift Green 8-bits and mask out other stuff
    Blue = Blue & 0x000000FF; //Mask out anything not blue.

    return 0xFF000000 | Red | Green | Blue; //0xFF000000 for 100% Alpha. Bitwise OR everything together.
}

Greetings Reineke

Community
  • 1
  • 1
meister_reineke
  • 364
  • 1
  • 14
  • Hai, the link you have given to turn your array back to picture is for color image(RGB arrays are there). I want to obtain gray scale image from the single array – user3364490 Mar 26 '15 at 17:43
  • the only difference is, that in grayscale the red/blue/green parts are all the same. and i wrote, that your algorithm to obtain the grayscale is correct?? – meister_reineke Mar 30 '15 at 10:59
0
public class GrayScaleTest {

    public void convert(int[] r, int[] g, int[] b, int imageWidth, int imageHeight) {
        int[] grayScaleValues = converToGrayscale(r,g,b);
        int[] encryptedValues = encryptValues(grayScaleValues);

        BufferedImage imageFromGrayScale = createImage(grayScaleValues, imageWidth, imageHeight);
        BufferedImage imageFromEncryptedValues = createImage(encryptedValues, imageWidth, imageHeight);
    }

    private BufferedImage createImage(int[] values, int imageWidth, int imageHeight) {
        BufferedImage image = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB);
        int[] raster = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(values,0,raster,0,raster.length);
        return image;
    }

    private int[] encryptValues(int[] grayScaleValues) {
        // run your encryption
        // I just return input
        return grayScaleValues;
    }

    private int[] converToGrayscale(int[] r, int[] g, int[] b) {
        int sz = r.length;
        int[] grayscale = new int[sz];
        for(int i = 0; i < sz; i++) {
            grayscale[i] = (r[i] + g[i] + b[i]) / 3;
        }
        return grayscale;
    }
}

You can of course use a different bufferedimage type, but I didnt want to have to deal with anything other than ints for this. But this code snippet should do what I think you want done.

Terje
  • 1,753
  • 10
  • 13
  • BufferedImage.TYPE_INT_ARGB is for gray scale image or RGB image? – user3364490 Mar 27 '15 at 04:24
  • raster variable can take only 1-D array, but my arrays(r[][], g[][],b[][],gray[][]) are 2-D arrays. should i copy (gray[][]--->2-D array to 1-D array and then perform the task? – user3364490 Mar 27 '15 at 04:40
  • Yes, it would be easiar to copy to 1D array for readability. The other solution is converting the x,y indexes of your 2-D arrays to a 1-D index, pixel pr. pixel. Inside the convertToGrayscale method, you can find the index in each color array with int index = (imageWidth * y) + x; The BufferedImage.TYPE_INT_ARGB is just for ease and habit, so that you can always work with ints no matter what. If the image size is an issue, choose a byte sized image instead. – Terje Mar 27 '15 at 08:03