Saturday, July 8, 2017

Image to Matrix and Matrix to Image conversion by retrieving RGB values

Let me go back into the background for writing this technical article. I was going through tutorials for Java FX , a Java library for creating desktop applications as well as rich internet applications and while going through the Image section of the tutorials , i questioned myself , how can an image be represented in a 2D dimensional matrix format & so i learnt how it is to be done and i am documenting it now.

Following are two functions that make the core of the program for reading from an image and persisting the RGB values in a 2D matrix or in a array of objects of a class . I find it easier to store it in a linkedList .

-> getRGBList

private List<ImageRGB> getRGBList(BufferedImage bufferedImage) {
          List<ImageRGB> rgbValues = new LinkedList<ImageRGB>();
           ImageRGB.setImageProperties(bufferedImage);
           for (int i = 0; i < bufferedImage.getWidth(); i++) {
                      for (int j = 0; j < bufferedImage.getHeight(); j++) {
                                 Color color = new Color(bufferedImage.getRGB(i, j));
                                 int red = color.getRed();
                                 int green = color.getGreen();
                                 int blue = color.getBlue();
                                 rgbValues.add(new ImageRGB(red, blue, green));
                      }
           }
           return rgbValues;
}

The above function takes the BufferedImage object , i will tell you later how that object was created .
  • Sets the ImageProperties  height , width and image type of the image 
  • Iterates over the each pixel in the image and get it's pixel data in RGB (bufferedImage.getRGB(i,j) , wrap it over the Color object and retrieve the red , green and blue components of the pixel.
  • I create an RGB object out of this value and add it to the linkedList of the Object.
After the end of execution of this method , we iterated over the rows of the image for each column of the image , i.e. iterate for each pixel in the height , for each pixel in the width and collected RGB values and stored them in an object . Now you can chose to persist this in database or serialize to a file or you name . I let it be in the memory for now .

-> generateImage

private void generateImage(List<ImageRGB> rgbValues, File destination) {
           try {
                  int k = -1;
                  BufferedImage image = new BufferedImage(ImageRGB.getWidth(),                                                     ImageRGB.getHeight(), ImageRGB.getImageType());
                  for (int i = 0; i < image.getWidth(); i++) {
                         for (int j = 0; j < image.getHeight(); j++) {
                                  k++;
                                  ImageRGB rgb = rgbValues.get(k);
                                  Color color = new Color(rgb.getRed(), rgb.getGreen(), rgb.getBlue());
                                  image.setRGB(i, j, color.getRGB());
                         }
                  }
                  ImageIO.write(image, "jpg", destination);
           } catch (Exception ex) {
                   ex.printStackTrace();
           }

 }

  • The above function is used to generate the image back from it's pixel values at each pixel.
  • The function takes the LinkedList we created in the previous method and an output File object to save the file .
  • It creates a Buffered Image object out of the Image Properties we had set in the previous method.
  • Iterates over each of the rows for each of the pixel in the width of the image , as we did in the previous method , generate the Color at that pixel after retrieving the RGB components from the ImageRGB object & set the pixel value at that pixel in the bufferedImage object.
  • After all the iterations are done , write the image to the destination. 
Do you get the exact image back , i bet you do , and it is indeed smart .

Lastly you need a main method to execute the above two methods and i would do the following

public class ImageProcessor {

           public static void main(String[] args) throws IOException {
           String srcFile = "C:\\Users\\adee\\Desktop\\src.jpg";
           String destFile = "C:\\Users\\adee\\Desktop\\destination.jpg";
           ImageProcessor iP = new ImageProcessor();
           BufferedImage bi = ImageIO.read(new File(srcFile));
           List<ImageRGB> rgbValues = iP.getRGBList(bi);
           iP.generateImage(rgbValues, new File(destFile));
 }
....
....

  • The above piece of code simply uses the javax.imageio libraries to read an image file and create a BufferedImage out of it which is passed to our method 1 to process the image.
Some more interesting things you can try out is to  get the contents of the image as a byte array 


byte[] bytes = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();

bufferedImage.getRaster() is an object of a  class representing a rectangular array of pixels. A Raster encapsulates a DataBuffer that stores the sample values and a SampleModel that describes how to locate a given sample value in a DataBuffer.
You can read more about Raster here .

Another interesting thing you could have done is , create a 2D array of number of rows = (height * width) of the Buffered Image and 3 columns representing the R G B components and iterating the same way over the Buffered Image and creating a 2D matrix out of the Image , and that would have made the program really cool . However i like to store it in an Object of RGB class for my convenience.

Lastly let me throw some light on RGB color space .The red, green and blue use 8 bits each, which have integer values from 0 to 255. This makes 256*256*256=16777216 possible colors. You can play around with the RGB values retrieved from the image and increase or decrease it for creating the image again , make sure it doesn't go beyond 255 and it doesn't go below 0. The newly generated image will be a totally new color

I hope you learnt something cool today .

Happy Coding

No comments:

Post a Comment