qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

          Java圖片上查找圖片算法

           之前用按鍵精靈寫過一些游戲輔助,里面有個(gè)函數(shù)叫FindPic,就上在屏幕范圍查找給定的一張圖片,返回查找到的坐標(biāo)位置。
            現(xiàn)在,Java來實(shí)現(xiàn)這個(gè)函數(shù)類似的功能。
            算法描述:
            屏幕截圖,得到圖A,(查找的目標(biāo)圖片為圖B);
            遍歷圖A的像素點(diǎn),根據(jù)圖B的尺寸,得到圖B四個(gè)角映射到圖A上的四個(gè)點(diǎn);
            得到的四個(gè)點(diǎn)與圖B的四個(gè)角像素點(diǎn)的值比較。如果四個(gè)點(diǎn)一樣,執(zhí)行步驟4;否則,回到步驟2繼續(xù);
            進(jìn)一步對(duì)比,將映射范圍內(nèi)的全部點(diǎn)與圖B全部的點(diǎn)比較。如果全部一樣,則說明圖片已找到;否則,回到步驟2繼續(xù);
            這里,像素之間的比較是通過BufferedImage對(duì)象獲取每個(gè)像素的RGB值來比較的。如下,將BufferedImage轉(zhuǎn)換為int二維數(shù)組:
          1     /**
          2      * 根據(jù)BufferedImage獲取圖片RGB數(shù)組
          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)獲取該點(diǎn)的顏色值是ARGB,而在實(shí)際應(yīng)用中使用的是RGB,所以需要將ARGB轉(zhuǎn)化成RGB,即bufImg.getRGB(w, h) & 0xFFFFFF。
          13                 result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
          14             }
          15         }
          16         return result;
          17     }
            比較兩個(gè)像素點(diǎn)的RGB值是否相同,是通過異或操作比較的(據(jù)說比==效率更高),如果異或操作后得到的值為0,說明兩個(gè)像素點(diǎn)的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;           //查找目標(biāo)圖片
          22
          23     int scrShotImgWidth;              //屏幕截圖寬度
          24     int scrShotImgHeight;             //屏幕截圖高度
          25
          26     int keyImgWidth;                  //查找目標(biāo)圖片寬度
          27     int keyImgHeight;                 //查找目標(biāo)圖片高度
          28
          29     int[][] screenShotImageRGBData;   //屏幕截圖RGB數(shù)據(jù)
          30     int[][] keyImageRGBData;          //查找目標(biāo)圖片RGB數(shù)據(jù)
          31
          32     int[][][] findImgData;            //查找結(jié)果,目標(biāo)圖標(biāo)位于屏幕截圖上的坐標(biāo)數(shù)據(jù)
          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      * 從本地文件讀取目標(biāo)圖片
          69      * @param keyImagePath - 圖片絕對(duì)路徑
          70      * @return 本地圖片的BufferedImage對(duì)象
          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      * 根據(jù)BufferedImage獲取圖片RGB數(shù)組
          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)獲取該點(diǎn)的顏色值是ARGB,而在實(shí)際應(yīng)用中使用的是RGB,所以需要將ARGB轉(zhuǎn)化成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         //遍歷屏幕截圖像素點(diǎn)數(shù)據(jù)
          107         for(int y=0; y<scrShotImgHeight-keyImgHeight; y++) {
          108             for(int x=0; x<scrShotImgWidth-keyImgWidth; x++) {
          109                 //根據(jù)目標(biāo)圖的尺寸,得到目標(biāo)圖四個(gè)角映射到屏幕截圖上的四個(gè)點(diǎn),
          110                 //判斷截圖上對(duì)應(yīng)的四個(gè)點(diǎn)與圖B的四個(gè)角像素點(diǎn)的值是否相同,
          111                 //如果相同就將屏幕截圖上映射范圍內(nèi)的所有的點(diǎn)與目標(biāo)圖的所有的點(diǎn)進(jìn)行比較。
          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                     //如果比較結(jié)果完全相同,則說明圖片找到,填充查找到的位置坐標(biāo)數(shù)據(jù)到查找結(jié)果數(shù)組。
          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      * 判斷屏幕截圖上目標(biāo)圖映射范圍內(nèi)的全部點(diǎn)是否全部和小圖的點(diǎn)一一對(duì)應(yīng)。
          135      * @param y - 與目標(biāo)圖左上角像素點(diǎn)想匹配的屏幕截圖y坐標(biāo)
          136      * @param x - 與目標(biāo)圖左上角像素點(diǎn)想匹配的屏幕截圖x坐標(biāo)
          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      * 輸出查找到的坐標(biāo)數(shù)據(jù)
          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 }
            這種算法是精確比較,只要有一個(gè)像素點(diǎn)有差異,就會(huì)找不到圖片。當(dāng)然,如果想指定一個(gè)比較的精確度,我也有個(gè)思路,就是在算法步驟4比較映射范圍內(nèi)全部像素點(diǎn)的時(shí)候做個(gè)統(tǒng)計(jì),如果90%的點(diǎn)都相同,那就是說精確度是0.9。
            另外,可能還要考慮效率問題,不過,我在我的應(yīng)用場景中并不太在意效率。如果有朋友看到這篇文章,對(duì)這個(gè)話題有更好的想法,請(qǐng)留言。

          posted on 2014-09-17 09:52 順其自然EVO 閱讀(727) 評(píng)論(0)  編輯  收藏 所屬分類: 測(cè)試學(xué)習(xí)專欄

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

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 虞城县| 康定县| 张家界市| 河源市| 绥化市| 平乡县| 江北区| 阜阳市| 江山市| 平泉县| 长白| 闽清县| 来凤县| 双柏县| 静安区| 小金县| 白沙| 环江| 杨浦区| 新野县| 汶上县| 江川县| 汕头市| 江油市| 田林县| 梁山县| 泰兴市| 富裕县| 德化县| 宁武县| 搜索| 布拖县| 江安县| 天台县| 扶风县| 大田县| 达孜县| 阿巴嘎旗| 金阳县| 交城县| 新乡县|