9 Replies Latest reply: Jun 21, 2010 12:58 AM by 791266 RSS

    Comparing images, image subtractions

    843802
      Hi,
      i am trying to compare images, i know it's a huge field but i'm actually looking for an "easy"solution.
      My idea it's to subtract the two images i want to compare and check if the result it's within a threshold.
      Basically i would convert the two images into two int arrays, using the PixelGrabber class, but then, how can i subtract them in order to get a single value that describes the level of difference between the two images?

      Anyway, is this a correct approach? Is there a better way?


      Thanks for help,

      Nite
        • 1. Re: Comparing images, image subtractions
          843802
          Are you familiar with the BufferedImage class and its method getRGB(int x, int y) ?
          • 2. Re: Comparing images, image subtractions
            843802
            Maxideon wrote:
            Are you familiar with the BufferedImage class and its method getRGB(int x, int y) ?
            Not really, anyway that should give me the same int array

            getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) , if this is what you were talking about
            • 3. Re: Comparing images, image subtractions
              843802
              You had mentioned the PixelGrabber class so I wasn't sure. Rarely do you need a full copy of the data when dealing with image processing using BufferedImages (it's a big waste of memory). And at the very least, the PixelGrabber is pointless with BufferedImages.

              The way I see it, there are three are ways you could implement this threshold idea of yours. For every (x,y) in the two images you can compare there rgb values and get a Euclidean distance squared of the two. You're threshold would then be a euclidean distance (squared) threshold. In the example below, I store the results in an black/white binary image called "diffImage." White is where the images are close, black is where the images were far apart.
              int euclideanThreshold = 5*5;
              BufferedImage img1 = ...
              BufferedImage img2 = ...
              int width = Math.min(img1.getWidth(),img2.getWidth());
              int height = Math.min(img1.getHeight(),img2.getHeight();
              BufferedImage diffImage = 
                      new BufferedImage(width,height,BufferedImage.TYPE_BYTE_BINARY);
              
              int similarCount;
              for(int x = 0; x < width; x++)
                   for(int y = 0; y < height; y++) {
                       int rgb1 = img1.getRGB(x,y);
                       int rgb2 = img2.getRGB(x,y);
                       
                       int diffR = ((rgb1<<16)&0xff)-((rgb2<<16)&0xff);
                       int diffG = ((rgb1<< 8)&0xff)-((rgb2<< 8)&0xff);
                       int diffB = ((rgb1    )&0xff)-((rgb2    )&0xff);
                       
                       if(diffR*diffR + diffG*diffG + diffB*diffB < euclideanThreshold) {
                        similarCount++;
                           diffImage.setRGB(x,y,-1); //set white
                       }else {
                           diffImage.setRGB(x,y,0); //set black
                       }
                   }
              A second way is to specify a threshold for the difference in each individual color component. The same threshold can be used for all three components. In the above example, the absolute value of diffR, diffG, and diffB would have to be below this threshold for you to consider the pixels similar.

              A last option is to convert both images to grayscale. You can find the difference in gray level between the two images for (x,y) and threshold accordingly.

              Then you can base your conclusions on whether the two images are similar by how many white pixels there are vs. how many black pixels in the difference image. In the above example, this would be "similar count" vs. "diffImage.getWidth() * diffImage.getHeight() - similarCount." In fact, you don't even need the difference image if nothing is going to be done with it (in which case I can suggest an even better method for quickly comparing two images).

              As for a better way, this is a perfectly acceptable method if you're going to use the difference image. It's the same method used for detecting motion or change in a video.
              • 4. Re: Comparing images, image subtractions
                843802
                Thank you very much for the help.
                I actually don't need the difference image, i only have to tell if the two images are close to each other.

                Nite
                • 5. Re: Comparing images, image subtractions
                  843802
                  in which case I can suggest an even better method for quickly comparing two images

                  Ugh.. that was premature. I was thinking of this forum post and my response to it,
                  http://forums.sun.com/thread.jspa?forumID=20&threadID=5345358

                  In retrospect though, this will only work if the images are exactly identical. You can still scale down the images under the presumption that if they are "similar", then their thumnails will also be "similar" (although I have no evidence to say this is so). If you're content with comparing thumnail versions though, then comparing the images will be really fast (not to say an average computer looping over a normal sized image is slow; because it's not).

                  Wether you use scaled down versions or not though, the procedure is the same. Determine how you want to threshold (eculidean distance squared, individual difference, or gray level difference) and count the number of similar pixels vs the number of non-similar pixels.

                  And as a side note, the gray values of a grayscaled image can also be thought of as brightness or luminance. If the images are similar according to their grayscaled versions, then they have similar brightness across the the pixels.
                  • 6. Re: Comparing images, image subtractions
                    843802
                    Here's a much more efficient algorithm than the above:

                    public static long calculateSumOfAbsoluteDifferences(BufferedImage first, BufferedImage second) {
                    assert first.getWidth() == second.getWidth();
                    assert first.getHeight() == second.getHeight();

                    final int[] firstRGB = getRawData(first);
                    final int[] secondRGB = getRawData(second);
                    final int length = firstRGB.length;
                    assert length == secondRGB.length;
                    long sum = 0;
                    for (int i = 0; i < length; ++i) {
                    int rgb1 = firstRGB;
                    int rgb2 = secondRGB[i];
                    int diffR = Math.abs(((rgb1 >> 16) & 0xff) - ((rgb2 >> 16) & 0xff));
                    int diffG = Math.abs(((rgb1 >> 8) & 0xff) - ((rgb2 >> 8) & 0xff));
                    int diffB = Math.abs(((rgb1) & 0xff) - ((rgb2) & 0xff));
                    sum += diffR + diffG + diffB;
                    }
                    return sum;
                    }
                    • 7. Re: Comparing images, image subtractions
                      843802
                      Hmm. That didn't come through right. Here's another try:
                          public static long calculateSumOfAbsoluteDifferences(BufferedImage first, BufferedImage second) {
                              assert first.getWidth() == second.getWidth();
                              assert first.getHeight() == second.getHeight();
                      
                              final int[] firstRGB = getRawData(first);
                              final int[] secondRGB = getRawData(second);
                              final int length = firstRGB.length;
                              assert length == secondRGB.length;
                              long sum = 0;
                              for (int i = 0; i < length; ++i) {
                                  int rgb1 = firstRGB;
                      int rgb2 = secondRGB[i];
                      int diffR = Math.abs(((rgb1 >> 16) & 0xff) - ((rgb2 >> 16) & 0xff));
                      int diffG = Math.abs(((rgb1 >> 8) & 0xff) - ((rgb2 >> 8) & 0xff));
                      int diffB = Math.abs(((rgb1) & 0xff) - ((rgb2) & 0xff));
                      sum += diffR + diffG + diffB;
                      }
                      return sum;
                      }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
                      • 8. Re: Comparing images, image subtractions
                        843802
                        Forgot this part...
                            static int[] getRawData(final BufferedImage image) {
                                return ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
                            }
                        • 9. Re: Comparing images, image subtractions
                          791266
                          Ixchel wrote:
                          Here's a much more efficient algorithm than the above:
                          Hi,

                          Nice to see that you want to help people, but please, don't resurrect old threads. I'm now locking this one.

                          Kaj