Раньше я писал несколько игровых помощников с использованием мастера кнопок. Существует функция FindPic, которая ищет заданное изображение в пределах экрана и возвращает найденную координату.
Теперь Java реализует функциональность, аналогичную этой функции.
Описание алгоритма:
Сделайте снимок экрана и получите изображение А (искомое изображение — изображение Б);
Пройдите по пикселям изображения A и в соответствии с размером изображения B получите четыре угла изображения B, сопоставленные с четырьмя точками изображения A;
Четыре полученные точки сравниваются со значениями четырех угловых пикселей на рисунке Б. Если четыре точки совпадают, перейдите к шагу 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[][] result = new 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.Rectangle; импорт java.awt.Toolkit; импорт java.awt.image.BufferedImage; .File; import java.io.IOException; import javax.imageio.ImageIO /** * Найти указанное изображение на экране* @author; Jeby Sun * @date 13.09.2014 * @website http://www.jebysun.com */ public class ImageFindDemo { BufferedImage screenShotImage; // Снимок экрана BufferedImage keyImage; // Находим целевое изображение int scrShotImgWidth // Ширина снимка экрана; int scrShotImgHeight // Высота снимка экрана int keyImgWidth // Находим ширину целевого изображения int; keyImgHeight; //Находим высоту целевого изображения int[][] screenShotImageRGBData; //Данные RGB снимка экрана int[][] keyImageRGBData; //Находим данные RGB целевого изображения int[][][] findImgData; //Находим результаты, target Координаты значка, расположенного на скриншоте public ImageFindDemo(String keyImagePath) { screenShotImage = this.getFullScreenShot(); = this.getBfImageFromPath(keyImagePath); screenShotImageRGBData = this.getImageGRB(screenShotImage); keyImageRGBData = this.getImageGRB(keyImage); scrShotImgWidth = screenShotImage.getWidth(); scrShotImgHeight = screenShotImage.getHeight(); keyImgWidth = keyImage.getWidth(); keyImgHeight = keyImage.getHeight(); //Начнем поиск этого.findImage(); } /** * Скриншот полноэкранного режима* @return Return BufferedImage */ public BufferedImage getFullScreenShot() { BufferedImage bfImage = ноль ширина = (целое) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); try { Robot robot = new Robot(); bfImage = robot.createScreenCapture( новый прямоугольник (0, 0, ширина, высота)} catch (AWTException e) { e.printStackTrace(); } return bfImage; } /** * Считайте целевое изображение из локального файла * @param keyImagePath — абсолютный путь к изображению * @return объект BufferedImage локального изображения */ public BufferedImage getBfImageFromPath (String keyImagePath) {BufferedImage bfImage = null try {bfImage = ImageIO.read (новый; File(keyImagePath)); } catch (IOException e) { e.printStackTrace(); } return bfImage } /** * Получить массив изображений RGB на основе BufferedImage * @param bfImage * @return */ public int[][ ] getImageGRB (BufferedImage bfImage) { int width = bfImage.getWidth(); 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; } } return result } /** * Найти изображения*/ public void findImage() { findImgData = new int[keyImgHeight][keyImgWidth][ 2]; //Обходим данные пикселей скриншота for(int y=0; y<scrShotImgHeight-keyImgHeight; y++) { for(int x=0; Значения четырех точек и четырех угловых пикселей рисунка B одинаковы? //Если они одинаковы, сравниваем все точки в диапазоне отображения на скриншоте с все точки целевого изображения. 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+keyImgHeight-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; } } return; Определите, соответствуют ли все точки в диапазоне отображения целевого изображения на снимке экрана точкам маленького изображения один к одному. * @param y — координата y снимка экрана, которая должна соответствовать точке пикселя в верхнем левом углу целевого изображения * @param x — координата x снимка экрана, которая должна соответствовать точке пикселя в верхнем левом углу целевого изображения * @return */ public boolean isMatchAll(int y, int x) { int bigrY = 0; int bigrX = 0; int smallY=0; lessY<keyImgHeight; lessY++) { bigerY = y+smallerY; for(int lessX=0; lessX<keyImgWidth; lessX++) { bigerX = x+smallerX; if(biggerY>=scrShotImgHeight || bigerX>=scrShotImgWidth) { return false; xor = keyImageRGBData[smallerY][smallerX] ]^screenShotImageRGBData[biggerY][biggerX]; if(xor!=0) { return false; } } bigerX = 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]+")"); println(); } } public static void main(String[] args) { String keyImagePath = "D:/key.png" demo = new; ImageFindDemo(keyImagePath); demo.printFindData(); } };
Этот алгоритм представляет собой точное сравнение. Пока есть разница в один пиксель, картинка не будет найдена. Конечно, если вы хотите указать точность сравнения, у меня также есть идея: составить статистику при сравнении всех пикселей в пределах диапазона отображения на шаге 4 алгоритма. Если 90% точек совпадают, это означает, что. точность 0,9.
Кроме того, можно также учитывать вопросы эффективности, но меня не слишком заботит эффективность в моем сценарии применения. Если кто-то из друзей прочитает эту статью и у вас возникнут лучшие идеи по этой теме, оставьте сообщение.