qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Java圖片上查找圖片算法

           之前用按鍵精靈寫過一些游戲輔助,里面有個函數叫FindPic,就上在屏幕范圍查找給定的一張圖片,返回查找到的坐標位置。
            現在,Java來實現這個函數類似的功能。
            算法描述:
            屏幕截圖,得到圖A,(查找的目標圖片為圖B);
            遍歷圖A的像素點,根據圖B的尺寸,得到圖B四個角映射到圖A上的四個點;
            得到的四個點與圖B的四個角像素點的值比較。如果四個點一樣,執行步驟4;否則,回到步驟2繼續;
            進一步對比,將映射范圍內的全部點與圖B全部的點比較。如果全部一樣,則說明圖片已找到;否則,回到步驟2繼續;
            這里,像素之間的比較是通過BufferedImage對象獲取每個像素的RGB值來比較的。如下,將BufferedImage轉換為int二維數組:
          1     /**
          2      * 根據BufferedImage獲取圖片RGB數組
          3      * @param bfImage
          4      * @return
          5      */
          6     public static int[][] getImageGRB(BufferedImage bfImage) {
          7         int width = bfImage.getWidth();
          8         int height = bfImage.getHeight();
          9         int[][] result = new int[height][width];
          10         for (int h = 0; h < height; h++) {
          11             for (int w = 0; w < width; w++) {
          12                 //使用getRGB(w, h)獲取該點的顏色值是ARGB,而在實際應用中使用的是RGB,所以需要將ARGB轉化成RGB,即bufImg.getRGB(w, h) & 0xFFFFFF。
          13                 result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
          14             }
          15         }
          16         return result;
          17     }
            比較兩個像素點的RGB值是否相同,是通過異或操作比較的(據說比==效率更高),如果異或操作后得到的值為0,說明兩個像素點的RGB一樣,否則不一樣。
          下面附上算法完整java代碼:
          1 package com.jebysun.test.imagefind;
          2
          3 import java.awt.AWTException;
          4 import java.awt.Rectangle;
          5 import java.awt.Robot;
          6 import java.awt.Toolkit;
          7 import java.awt.image.BufferedImage;
          8 import java.io.File;
          9 import java.io.IOException;
          10
          11 import javax.imageio.ImageIO;
          12 /**
          13  * 屏幕上查找指定圖片
          14  * @author Jeby Sun
          15  * @date 2014-09-13
          16  * @website http://www.jebysun.com
          17  */
          18 public class ImageFindDemo {
          19
          20     BufferedImage screenShotImage;    //屏幕截圖
          21     BufferedImage keyImage;           //查找目標圖片
          22
          23     int scrShotImgWidth;              //屏幕截圖寬度
          24     int scrShotImgHeight;             //屏幕截圖高度
          25
          26     int keyImgWidth;                  //查找目標圖片寬度
          27     int keyImgHeight;                 //查找目標圖片高度
          28
          29     int[][] screenShotImageRGBData;   //屏幕截圖RGB數據
          30     int[][] keyImageRGBData;          //查找目標圖片RGB數據
          31
          32     int[][][] findImgData;            //查找結果,目標圖標位于屏幕截圖上的坐標數據
          33
          34
          35     public ImageFindDemo(String keyImagePath) {
          36         screenShotImage = this.getFullScreenShot();
          37         keyImage = this.getBfImageFromPath(keyImagePath);
          38         screenShotImageRGBData = this.getImageGRB(screenShotImage);
          39         keyImageRGBData = this.getImageGRB(keyImage);
          40         scrShotImgWidth = screenShotImage.getWidth();
          41         scrShotImgHeight = screenShotImage.getHeight();
          42         keyImgWidth = keyImage.getWidth();
          43         keyImgHeight = keyImage.getHeight();
          44
          45         //開始查找
          46         this.findImage();
          47
          48     }
          49
          50     /**
          51      * 全屏截圖
          52      * @return 返回BufferedImage
          53      */
          54     public BufferedImage getFullScreenShot() {
          55         BufferedImage bfImage = null;
          56         int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
          57         int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
          58         try {
          59             Robot robot = new Robot();
          60             bfImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
          61         } catch (AWTException e) {
          62             e.printStackTrace();
          63         }
          64         return bfImage;
          65     }
          66
          67     /**
          68      * 從本地文件讀取目標圖片
          69      * @param keyImagePath - 圖片絕對路徑
          70      * @return 本地圖片的BufferedImage對象
          71      */
          72     public BufferedImage getBfImageFromPath(String keyImagePath) {
          73         BufferedImage bfImage = null;
          74         try {
          75             bfImage = ImageIO.read(new File(keyImagePath));
          76         } catch (IOException e) {
          77             e.printStackTrace();
          78         }
          79         return bfImage;
          80     }
          81
          82     /**
          83      * 根據BufferedImage獲取圖片RGB數組
          84      * @param bfImage
          85      * @return
          86      */
          87     public int[][] getImageGRB(BufferedImage bfImage) {
          88         int width = bfImage.getWidth();
          89         int height = bfImage.getHeight();
          90         int[][] result = new int[height][width];
          91         for (int h = 0; h < height; h++) {
          92             for (int w = 0; w < width; w++) {
          93                 //使用getRGB(w, h)獲取該點的顏色值是ARGB,而在實際應用中使用的是RGB,所以需要將ARGB轉化成RGB,即bufImg.getRGB(w, h) & 0xFFFFFF。
          94                 result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
          95             }
          96         }
          97         return result;
          98     }
          99
          100
          101     /**
          102      * 查找圖片
          103      */
          104     public void findImage() {
          105         findImgData = new int[keyImgHeight][keyImgWidth][2];
          106         //遍歷屏幕截圖像素點數據
          107         for(int y=0; y<scrShotImgHeight-keyImgHeight; y++) {
          108             for(int x=0; x<scrShotImgWidth-keyImgWidth; x++) {
          109                 //根據目標圖的尺寸,得到目標圖四個角映射到屏幕截圖上的四個點,
          110                 //判斷截圖上對應的四個點與圖B的四個角像素點的值是否相同,
          111                 //如果相同就將屏幕截圖上映射范圍內的所有的點與目標圖的所有的點進行比較。
          112                 if((keyImageRGBData[0][0]^screenShotImageRGBData[y][x])==0
          113                         && (keyImageRGBData[0][keyImgWidth-1]^screenShotImageRGBData[y][x+keyImgWidth-1])==0
          114                         && (keyImageRGBData[keyImgHeight-1][keyImgWidth-1]^screenShotImageRGBData[y+keyImgHeight-1][x+keyImgWidth-1])==0
          115                         && (keyImageRGBData[keyImgHeight-1][0]^screenShotImageRGBData[y+keyImgHeight-1][x])==0) {
          116
          117                     boolean isFinded = isMatchAll(y, x);
          118                     //如果比較結果完全相同,則說明圖片找到,填充查找到的位置坐標數據到查找結果數組。
          119                     if(isFinded) {
          120                         for(int h=0; h<keyImgHeight; h++) {
          121                             for(int w=0; w<keyImgWidth; w++) {
          122                                 findImgData[h][w][0] = y+h;
          123                                 findImgData[h][w][1] = x+w;
          124                             }
          125                         }
          126                         return;
          127                     }
          128                 }
          129             }
          130         }
          131     }
          132
          133     /**
          134      * 判斷屏幕截圖上目標圖映射范圍內的全部點是否全部和小圖的點一一對應。
          135      * @param y - 與目標圖左上角像素點想匹配的屏幕截圖y坐標
          136      * @param x - 與目標圖左上角像素點想匹配的屏幕截圖x坐標
          137      * @return
          138      */
          139     public boolean isMatchAll(int y, int x) {
          140         int biggerY = 0;
          141         int biggerX = 0;
          142         int xor = 0;
          143         for(int smallerY=0; smallerY<keyImgHeight; smallerY++) {
          144             biggerY = y+smallerY;
          145             for(int smallerX=0; smallerX<keyImgWidth; smallerX++) {
          146                 biggerX = x+smallerX;
          147                 if(biggerY>=scrShotImgHeight || biggerX>=scrShotImgWidth) {
          148                     return false;
          149                 }
          150                 xor = keyImageRGBData[smallerY][smallerX]^screenShotImageRGBData[biggerY][biggerX];
          151                 if(xor!=0) {
          152                     return false;
          153                 }
          154             }
          155             biggerX = x;
          156         }
          157         return true;
          158     }
          159
          160     /**
          161      * 輸出查找到的坐標數據
          162      */
          163     private void printFindData() {
          164         for(int y=0; y<keyImgHeight; y++) {
          165             for(int x=0; x<keyImgWidth; x++) {
          166                 System.out.print("("+this.findImgData[y][x][0]+", "+this.findImgData[y][x][1]+")");
          167             }
          168             System.out.println();
          169         }
          170     }
          171
          172
          173     public static void main(String[] args) {
          174         String keyImagePath = "D:/key.png";
          175         ImageFindDemo demo = new ImageFindDemo(keyImagePath);
          176         demo.printFindData();
          177     }
          178
          179 }
            這種算法是精確比較,只要有一個像素點有差異,就會找不到圖片。當然,如果想指定一個比較的精確度,我也有個思路,就是在算法步驟4比較映射范圍內全部像素點的時候做個統計,如果90%的點都相同,那就是說精確度是0.9。
            另外,可能還要考慮效率問題,不過,我在我的應用場景中并不太在意效率。如果有朋友看到這篇文章,對這個話題有更好的想法,請留言。

          posted on 2014-09-17 09:52 順其自然EVO 閱讀(725) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

          <2014年9月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 颍上县| 壤塘县| 天台县| 海丰县| 克什克腾旗| 舟山市| 天峻县| 温州市| 宁海县| 绍兴市| 瑞金市| 三门峡市| 建水县| 清镇市| 洛扎县| 贡觉县| 望城县| 大渡口区| 资阳市| 什邡市| 天门市| 建平县| 井陉县| 乃东县| 岳阳县| 辛集市| 兴宁市| 奉化市| 蒙自县| 汪清县| 循化| 雅安市| 岢岚县| 福贡县| 古田县| 桐柏县| 江北区| 自治县| 隆尧县| 平谷区| 牙克石市|