Saya telah menulis beberapa asisten permainan menggunakan panduan tombol sebelumnya. Ada fungsi yang disebut FindPic, yang mencari gambar tertentu dalam rentang layar dan mengembalikan posisi koordinat yang ditemukan.
Sekarang, Java mengimplementasikan fungsi serupa dengan fungsi ini.
Deskripsi algoritma:
Ambil screenshot dan ambil gambar A (gambar target yang dicari adalah gambar B);
Lintasi piksel gambar A, dan sesuai dengan ukuran gambar B, diperoleh keempat sudut gambar B yang dipetakan ke empat titik pada gambar A;
Keempat titik yang diperoleh dibandingkan dengan nilai keempat piksel sudut pada Gambar B. Jika keempat poinnya sama, lanjutkan ke langkah 4; jika tidak, kembali ke langkah 2 untuk melanjutkan;
Untuk perbandingan lebih lanjut, bandingkan semua titik dalam rentang pemetaan dengan semua titik pada Gambar B. Jika semuanya sama, maka gambar telah ditemukan; jika tidak, kembali ke langkah 2 untuk melanjutkan;
Di sini perbandingan antar piksel dilakukan dengan memperoleh nilai RGB setiap piksel melalui objek BufferedImage. Sebagai berikut, ubah BufferedImage menjadi array dua dimensi int:
/** * Dapatkan gambar array RGB berdasarkan BufferedImage * @param bfImage * @return */ public static int[][] getImageGRB(BufferedImage bfImage) { int width = bfImage.getWidth(); int height = bfImage.getHeight( ); int[][] hasil = int[tinggi][lebar] baru untuk (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { //Gunakan getRGB(w, h) untuk mendapatkan nilai warna titik, yaitu ARGB, tetapi dalam aplikasi sebenarnya , itu RGB, jadi ARGB perlu diubah menjadi RGB, yaitu bufImg.getRGB(w, h) & 0xFFFFFF. hasil[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
Membandingkan apakah nilai RGB dari dua piksel sama dilakukan melalui operasi XOR (dikatakan lebih efisien dari ==). Jika nilai yang diperoleh setelah operasi XOR adalah 0, berarti nilai RGB tersebut dari dua piksel itu sama, jika tidak maka tidak sama.
Kode java lengkap dari algoritma tersebut terlampir di bawah ini:
paket com.jebysun.test.imagefind; impor java.awt.AWTException; impor java.awt.Rectangle; impor java.awt.Robot; .File; import java.io.IOException; import javax.imageio.ImageIO; Jeby Sun * @tanggal 13-09-2014 * @situs web http://www.jebysun.com */ public class ImageFindDemo { BufferedImage screenShotImage; //Tangkapan Layar BufferedImage keyImage; //Temukan gambar target di scrShotImgWidth; //Lebar Tangkapan Layar int scrShotImgHeight; //Tinggi tangkapan layar int keyImgWidth; //Temukan lebar gambar target int keyImgHeight; //Temukan tinggi gambar target int[][] screenShotImageRGBData; //Tangkapan layar data RGB int[][] keyImageRGBData; //Temukan data RGB gambar target int[][][] findImgData; target Data koordinat ikon yang terletak pada tangkapan layar public ImageFindDemo(String keyImagePath) { screenShotImage = this.getFullScreenShot(); = ini.getBfImageFromPath(keyImagePath); screenShotImageRGBData = ini.getImageGRB(screenShotImage); keyImageRGBData = ini.getImageGRB(keyImage); keyImgWidth = keyImage.getWidth(); keyImgHeight = keyImage.getHeight(); //Mulai mencari this.findImage(); = nol ; ke dalam lebar = (ke dalam) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); Persegi Panjang baru(0, 0, lebar, tinggi)); tangkapan (AWTException e) { e.printStackTrace(); } return bfImage; } /** * Membaca gambar target dari file lokal * @param keyImagePath - jalur absolut gambar * @return objek BufferedImage dari gambar lokal */ public BufferedImage getBfImageFromPath (String keyImagePath) { BufferedImage bfImage = null; coba { bfImage = ImageIO.read(new File(keyImagePath)); } catch (IOException e) { e.printStackTrace(); } return bfImage; /** * Dapatkan gambar array RGB berdasarkan BufferedImage * @param bfImage * @return */ public int[] ] getImageGRB (BufferedImage bfImage) { int lebar = bfImage.getWidth(); tinggi = bfImage.getHeight(); int[][] hasil = int baru[tinggi][lebar]; untuk (int h = 0; h < tinggi; h++) { untuk (int w = 0; w < lebar; w++ ) { //Gunakan getRGB(w, h) Nilai warna yang diperoleh saat ini adalah ARGB, namun pada aplikasi sebenarnya digunakan RGB, sehingga ARGB perlu diubah menjadi RGB yaitu bufImg.getRGB(w, h) & 0xFFFFFF. hasil[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF; } mengembalikan hasil; 2]; //Melintasi data piksel tangkapan layar untuk(int y=0; y<scrShotImgHeight-keyImgHeight; y++) { for(int x=0; Apakah nilai keempat titik dan keempat piksel sudut pada Gambar B sama? //Jika sama, bandingkan semua titik dalam rentang pemetaan pada tangkapan layar dengan semua titik pada gambar target. 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); //Jika hasil perbandingan sama persis, berarti gambar ditemukan, dan data koordinat posisi yang ditemukan diisi ke dalam array hasil pencarian. jika(ditemukan) { untuk(int h=0; h<keyImgHeight; h++) { untuk(int w=0; w<keyImgWidth; w++) { findImgData[h][w][0] = y+h; h][w][1] = x+w; Tentukan apakah semua titik dalam rentang pemetaan gambar target pada tangkapan layar sesuai dengan titik gambar kecil satu-ke-satu. * @param y - Koordinat y dari screenshot yang ingin dicocokkan dengan titik pixel di pojok kiri atas gambar target * @param x - Koordinat x dari screenshot yang ingin dicocokkan dengan titik pixel di pojok kiri atas dari gambar target * @return */ public boolean isMatchAll(int y, int x) { int lebih besarY = 0; int lebih besarX = 0; int xor = 0; for(int lebih kecilY=0; lebih kecilY<keyImgHeight; lebih kecilY++) { lebih besarY = y+lebih kecilY; untuk(int lebih kecilX=0; lebih kecilX<keyImgWidth; lebih kecilX++) { lebih besarX = x+lebih kecilX; jika(lebih besarY>=scrShotImgHeight || lebih besarX>=scrShotImgWidth) { kembali salah; ]^screenShotImageRGBData[biggerY][biggerX]; if(xor!=0) { return false; } } bigX = x; } return true; } /** * Keluarkan data koordinat yang ditemukan*/ private void printFindData() { for(int y=0; y<keyImgHeight ; y++) { untuk(int x=0; x<keyImgWidth; x++) { System.out.print("("+ini.findImgData[y][x][0]+", "+ini.findImgData[y][x][1]+")"); println(); } } public static void main(String[] args) { String keyImagePath = "D:/key.png"; ImageFindDemo(keyImagePath); demo.printFindData();
Algoritma ini merupakan perbandingan yang akurat. Selama ada perbedaan satu piksel, gambarnya tidak akan ditemukan. Tentu saja, jika Anda ingin menentukan akurasi perbandingan, saya juga punya ide, yaitu membuat statistik ketika membandingkan semua piksel dalam rentang pemetaan pada langkah 4 algoritma. Jika 90% titiknya sama, itu artinya akurasinya 0,9.
Selain itu, masalah efisiensi juga dapat dipertimbangkan, namun saya tidak terlalu peduli dengan efisiensi dalam skenario aplikasi saya. Jika ada teman yang membaca artikel ini dan memiliki ide lebih baik tentang topik ini, silakan tinggalkan pesan.