ฉันเคยเขียนผู้ช่วยเกมบางคนโดยใช้ปุ่มวิซาร์ดมาก่อน มีฟังก์ชันที่เรียกว่า FindPic ซึ่งจะค้นหารูปภาพที่กำหนดภายในช่วงหน้าจอและส่งกลับตำแหน่งพิกัดที่พบ
ตอนนี้ Java ใช้ฟังก์ชันการทำงานที่คล้ายกันกับฟังก์ชันนี้
คำอธิบายอัลกอริทึม:
ถ่ายภาพหน้าจอและรับภาพ A (ภาพเป้าหมายที่คุณกำลังมองหาคือภาพ B)
สำรวจพิกเซลของภาพ A และตามขนาดของภาพ B จะได้มุมทั้งสี่ของภาพ B ที่แมปกับจุดสี่จุดบนภาพ A
คะแนนที่ได้รับทั้งสี่จะถูกนำมาเปรียบเทียบกับค่าของพิกเซลมุมทั้งสี่ในรูปที่ B หากจุดทั้งสี่เหมือนกัน ให้ไปที่ขั้นตอนที่ 4 หรือกลับไปที่ขั้นตอนที่ 2 เพื่อดำเนินการต่อ
สำหรับการเปรียบเทียบเพิ่มเติม ให้เปรียบเทียบจุดทั้งหมดภายในช่วงการแมปกับจุดทั้งหมดในรูปที่ B หากเหมือนกันทั้งหมด แสดงว่าพบรูปภาพแล้ว ให้กลับไปที่ขั้นตอนที่ 2 เพื่อดำเนินการต่อ
ในที่นี้ การเปรียบเทียบระหว่างพิกเซลทำได้โดยการรับค่า RGB ของแต่ละพิกเซลผ่านวัตถุ BufferedImage ดังต่อไปนี้ แปลง BufferedImage เป็นอาร์เรย์ int สองมิติ:
/** * รับอาร์เรย์รูปภาพ RGB ตาม BufferedImage * @param bfImage * @return */ public static int[] getImageGRB(BufferedImage bfImage) { int width = bfImage.getWidth(); int height = bfImage.getHeight( ); int[] [] ผลลัพธ์ = ใหม่ int [ความสูง] [ความกว้าง]; = 0; h < height; h++) { for (int w = 0; w < width; w++) { //ใช้ getRGB(w, h) เพื่อรับค่าสีของจุดซึ่งเป็น ARGB แต่ในการใช้งานจริง มันคือ RGB ดังนั้น ARGB จึงต้องแปลงเป็น RGB นั่นคือ bufImg.getRGB(w, h) & 0xFFFFFF result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF; } } ส่งคืนผลลัพธ์; }
การเปรียบเทียบว่าค่า RGB ของพิกเซลทั้งสองจะเท่ากันหรือไม่นั้นทำได้ผ่านการดำเนินการ XOR (ซึ่งกล่าวกันว่ามีประสิทธิภาพมากกว่า ==) หากค่าที่ได้รับหลังการดำเนินการ XOR เป็น 0 แสดงว่าค่า RGB ของทั้งสองพิกเซลจะเหมือนกัน ไม่เช่นนั้นจะไม่เหมือนกัน
รหัส Java ที่สมบูรณ์ของอัลกอริทึมแนบมาด้านล่าง:
แพ็คเกจ com.jebysun.test.imagefind; นำเข้า java.awt.AWTException; นำเข้า java.awt.Robot; นำเข้า java.awt.Toolkit; นำเข้า java.awt.BufferedImage; .File; import java.io.IOException; import javax.imageio.ImageIO; /** * ค้นหารูปภาพที่ระบุบนหน้าจอ* @author Jeby Sun * @ วันที่ 2014-09-13 * @ เว็บไซต์ http://www.jebysun.com */ ImageFindDemo ระดับสาธารณะ { BufferedImage screenShotImage; // ภาพหน้าจอ BufferedImage keyImage; // ค้นหารูปภาพเป้าหมาย int scrShotImgWidth; // ความกว้างของภาพหน้าจอ; int scrShotImgHeight; // ความสูงของภาพหน้าจอ int keyImgWidth; // ค้นหาความกว้างของภาพเป้าหมาย int keyImgHeight; // ค้นหาความสูงของภาพเป้าหมาย int [] [] findImgData; // ค้นหาข้อมูล RGB ของภาพเป้าหมาย; เป้าหมาย ข้อมูลพิกัดของไอคอนที่อยู่บนภาพหน้าจอสาธารณะ ImageFindDemo(String keyImagePath) { screenShotImage = this.getFullScreenShot(); = this.getBfImageFromPath(keyImagePath); screenShotImageRGBData = this.getImageGRB(screenShotImage); keyImageRGBData = this.getImageGRB(keyImage); scrShotImage.getWidth(); keyImgWidth = keyImage.getWidth(); keyImgHeight = keyImage.getHeight(); //เริ่มมองหา this.findImage(); } /** * ภาพหน้าจอแบบเต็มหน้าจอ * @return Return BufferedImage */ public BufferedImage getFullScreenShot() { BufferedImage bfImage = null ; int ความกว้าง = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); ลอง { Robot = new Robot(); สี่เหลี่ยมผืนผ้าใหม่ (0, 0, ความกว้าง, ความสูง) } catch (AWTException e) { e.printStackTrace(); } return bfImage; } /** * อ่านรูปภาพเป้าหมายจากไฟล์ในเครื่อง * @param keyImagePath - เส้นทางสัมบูรณ์ของรูปภาพ * @return วัตถุ BufferedImage ของรูปภาพในเครื่อง */ public BufferedImage getBfImageFromPath (สตริง keyImagePath) { BufferedImage bfImage = null; ลอง { bfImage = ImageIO.read(new File(keyImagePath)); } catch (IOException e) { e.printStackTrace(); } return bfImage; } /** * รับอาร์เรย์รูปภาพ RGB ตาม BufferedImage * @param bfImage * @return */ 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) ค่าสีที่ได้รับ ณ จุดนี้คือ ARGB แต่ในการใช้งานจริงจะใช้ RGB ดังนั้น ARGB จึงต้องแปลงเป็น RGB นั่นคือ bufImg.getRGB(w, h) & 0xFFFFFF result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF; } } ส่งคืนผลลัพธ์; } /** * ค้นหารูปภาพ*/ โมฆะสาธารณะ findImage() { findImgData = new int[keyImgHeight][keyImgWidth][ 2]; //สำรวจข้อมูลพิกเซลของภาพหน้าจอสำหรับ(int y=0; y<scrShotImgHeight-keyImgHeight; y++) { for(int x=0; ค่าของจุดสี่จุดและพิกเซลมุมทั้งสี่ของรูป B เหมือนกันหรือไม่ // หากเหมือนกัน ให้เปรียบเทียบจุดทั้งหมดภายในช่วงการแมปบนภาพหน้าจอด้วย ทุกจุดในภาพเป้าหมาย ถ้า ((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) { บูลีน isFinded = isMatchAll(y, x); //หากผลการเปรียบเทียบเหมือนกันทุกประการ แสดงว่าพบรูปภาพแล้ว และข้อมูลพิกัดตำแหน่งที่พบจะถูกกรอกลงในอาร์เรย์ผลการค้นหา 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; } } กลับ; ตรวจสอบว่าจุดทั้งหมดภายในช่วงการแมปของภาพเป้าหมายบนภาพหน้าจอนั้นสอดคล้องกับจุดของภาพขนาดเล็กแบบหนึ่งต่อหนึ่งหรือไม่ * @param y - พิกัด y ของภาพหน้าจอที่ต้องการจับคู่จุดพิกเซลที่มุมซ้ายบนของภาพเป้าหมาย * @param x - พิกัด x ของภาพหน้าจอที่ต้องการจับคู่จุดพิกเซลที่มุมซ้ายบน ของภาพเป้าหมาย * @return */ บูลีนสาธารณะ isMatchAll(int y, int x) { int bigerY = 0; int xor = 0; for(int ขนาดเล็ก Y=0; ขนาดเล็ก Y<keyImgHeight; ขนาดเล็ก Y++) { bigY = y+smallerY; for(int ขนาดเล็ก X=0; ขนาดเล็ก X<keyImgWidth; ขนาดเล็กกว่า X ++) { ใหญ่กว่า X = x + ขนาดเล็ก X; ]^screenShotImageRGBData[ใหญ่ Y] [ใหญ่กว่า X]; if(xor!=0) { return false; } } bigX = x; } return true; } /** * ส่งออกข้อมูลพิกัดที่พบ*/ private void printFindData() { for(int y=0; y<keyImgHeight ; y++) { สำหรับ(int x=0; x<keyImgWidth; x++) { System.out.print("("+this.findImgData[y][x][0]+", "+this.findImgData[y][x][1]+")"); } System.out.print println(); } } โมฆะสาธารณะหลัก (สตริง [] args) { String keyImagePath = "D:/key.png"; ImageFindDemo(keyImagePath); demo.printFindData();
อัลกอริธึมนี้เป็นการเปรียบเทียบที่แม่นยำ ตราบใดที่มีความแตกต่างในหนึ่งพิกเซล ก็จะไม่พบรูปภาพ แน่นอน หากคุณต้องการระบุความแม่นยำในการเปรียบเทียบ ฉันก็มีแผนที่จะทำสถิติเมื่อเปรียบเทียบพิกเซลทั้งหมดภายในช่วงการแมปในขั้นตอนที่ 4 ของอัลกอริทึม หาก 90% ของจุดเท่ากัน นั่นหมายถึง ความแม่นยำคือ 0.9
นอกจากนี้ อาจพิจารณาปัญหาด้านประสิทธิภาพด้วย แต่ฉันไม่สนใจเกี่ยวกับประสิทธิภาพในสถานการณ์แอปพลิเคชันของฉันมากเกินไป หากเพื่อนๆ คนไหนอ่านบทความนี้แล้วมีไอเดียดีๆ ในหัวข้อนี้ ฝากข้อความไว้ได้เลยนะครับ