Java to achieve the picture contrast function

  • 2020-04-01 03:28:59
  • OfStack

Before using the button wizard to write some game AIDS, there is a function called FindPic, on the screen range to find a given picture, return the coordinates found.

Now, Java implements this function in a similar way.

Algorithm description:

Screen capture to get figure A (figure B is the target picture to look for);
Traversing the pixel points of figure A, according to the size of figure B, the four angles of figure B are mapped to four points on figure A;
The resulting four points are compared with the values of the four corner pixels in figure B. If the four points are the same, execute step 4; Otherwise, go back to step 2 and continue.
For further comparison, compare all points in the mapping range with all points in figure B. If all are the same, the picture has been found. Otherwise, go back to step 2 and continue.
Here, comparisons between pixels are made by getting the RGB value of each pixel from the BufferedImage object. Convert BufferedImage to an int 2d array as follows:


   
   public static int[][] getImageGRB(BufferedImage bfImage) {
     int width = bfImage.getWidth();
     int height = bfImage.getHeight();
     int[][] result = new int[height][width];
     for (int h = 0; h < height; h++) {
       for (int w = 0; w < width; w++) {
         //GetRGB (w, h) is used to get that the color value of the point is ARGB, while RGB is used in practice, so ARGB needs to be converted to RGB, that is, bufimg. getRGB(w, h) & 0xFFFFFF.
         result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
       }
     }
     return result;
   }

  Comparing the RGB value of two pixels is the same, is through xor operation comparison (it is said to be more efficient than ==), if the value is 0 after xor operation, it means that the RGB of two pixels is the same, otherwise not the same.

The following is the complete Java code of the algorithm:


 package com.jebysun.test.imagefind;
 
 import java.awt.AWTException;
 import java.awt.Rectangle;
 import java.awt.Robot;
 import java.awt.Toolkit;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 
 import javax.imageio.ImageIO;
 /**
 *  Finds the specified image on the screen 
 * @author Jeby Sun
 * @date 2014-09-13
 * @website http://www.jebysun.com
 */
 public class ImageFindDemo {
   
   BufferedImage screenShotImage;  //Screen capture
   BufferedImage keyImage;      //Find the target image
   
   int scrShotImgWidth;       //Screen capture The width of the 
   int scrShotImgHeight;       //Screen capture highly 
   
   int keyImgWidth;         //Find the target image The width of the 
   int keyImgHeight;         //Find the target image highly 
   
   int[][] screenShotImageRGBData;  //Screen captureRGB data 
   int[][] keyImageRGBData;     //Find the target imageRGB data 
   
   int[][][] findImgData;      // Find the result, the target icon is located Screen capture The coordinate data of  
   
   
   public ImageFindDemo(String keyImagePath) {
     screenShotImage = this.getFullScreenShot();
     keyImage = this.getBfImageFromPath(keyImagePath);
     screenShotImageRGBData = this.getImageGRB(screenShotImage);
     keyImageRGBData = this.getImageGRB(keyImage);
     scrShotImgWidth = screenShotImage.getWidth();
     scrShotImgHeight = screenShotImage.getHeight();
     keyImgWidth = keyImage.getWidth();
     keyImgHeight = keyImage.getHeight();
     
     //Start looking for
     this.findImage();
     
   }
   
   
   public BufferedImage getFullScreenShot() {
     BufferedImage bfImage = null;
     int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
     int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
     try {
       Robot robot = new Robot();
       bfImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
     } catch (AWTException e) {
       e.printStackTrace();
     }
     return bfImage;
   }
   
   
   public BufferedImage getBfImageFromPath(String keyImagePath) {
     BufferedImage bfImage = null;
     try {
       bfImage = ImageIO.read(new File(keyImagePath));
     } catch (IOException e) {
       e.printStackTrace();
     }
     return bfImage;
   }
   
   
   public int[][] getImageGRB(BufferedImage bfImage) {
     int width = bfImage.getWidth();
     int height = bfImage.getHeight();
     int[][] result = new int[height][width];
     for (int h = 0; h < height; h++) {
       for (int w = 0; w < width; w++) {
         //GetRGB (w, h) is used to get that the color value of the point is ARGB, while RGB is used in practice, so ARGB needs to be converted to RGB, that is, bufimg. getRGB(w, h) & 0xFFFFFF.
         result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
       }
     }
     return result;
   }
   
   
   
   public void findImage() {
     findImgData = new int[keyImgHeight][keyImgWidth][2];
     // traverse Screen capture Pixel data 
     for(int y=0; y<scrShotImgHeight-keyImgHeight; y++) {
       for(int x=0; x<scrShotImgWidth-keyImgWidth; x++) {
         // According to the size of the target graph, the four corners of the target graph are mapped to Screen capture The four points above, 
         //Determine whether the corresponding four points on the screenshot have the same values as the four corner pixels in FIG. B.
         // If it's the same, it's going to be Screen capture All points in the upper map range are compared with all points in the target graph. 
         if((keyImageRGBData[0][0]^screenShotImageRGBData[y][x])==0
             && (keyImageRGBData[0][keyImgWidth-1]^screenShotImageRGBData[y][x+keyImgWidth-1])==0
             && (keyImageRGBData[keyImgHeight-1][keyImgWidth-1]^screenShotImageRGBData[y+keyImgHeight-1][x+keyImgWidth-1])==0
             && (keyImageRGBData[keyImgHeight-1][0]^screenShotImageRGBData[y+keyImgHeight-1][x])==0) {
           
           boolean isFinded = isMatchAll(y, x);
           //If the comparison results are identical, the image is found, and the position coordinate data found is filled into the search results array.
           if(isFinded) {
             for(int h=0; h<keyImgHeight; h++) {
               for(int w=0; w<keyImgWidth; w++) {
                 findImgData[h][w][0] = y+h; 
                 findImgData[h][w][1] = x+w;
               }
             }
             return;
           }
         }
       }
     }
   }
   
   
   public boolean isMatchAll(int y, int x) {
     int biggerY = 0;
     int biggerX = 0;
     int xor = 0;
     for(int smallerY=0; smallerY<keyImgHeight; smallerY++) {
       biggerY = y+smallerY;
       for(int smallerX=0; smallerX<keyImgWidth; smallerX++) {
         biggerX = x+smallerX;
         if(biggerY>=scrShotImgHeight || biggerX>=scrShotImgWidth) {
           return false;
         }
         xor = keyImageRGBData[smallerY][smallerX]^screenShotImageRGBData[biggerY][biggerX];
         if(xor!=0) {
           return false;
         }
       }
       biggerX = x;
     }
     return true;
   }
   
   
   private void printFindData() {
     for(int y=0; y<keyImgHeight; y++) {
       for(int x=0; x<keyImgWidth; x++) {
         System.out.print("("+this.findImgData[y][x][0]+", "+this.findImgData[y][x][1]+")");
       }
       System.out.println();
     }
   }
 
   
   public static void main(String[] args) {
     String keyImagePath = "D:/key.png";
     ImageFindDemo demo = new ImageFindDemo(keyImagePath);
     demo.printFindData();
   }
 
 }

This algorithm is accurate comparison, as long as one pixel difference, will not find the picture. Of course, if I want to specify the accuracy of a comparison, I also have an idea, which is to do a statistic when I compare all the pixels in the mapping range in algorithm step 4, if 90% of the points are the same, that means the accuracy is 0.9.

In addition, you might want to consider efficiency, but I don't really care about efficiency in my application scenarios. If any friends see this article and have better ideas on this topic, please leave a comment.


Related articles: