tipo ruta recuperar mostrar imagenes imagen guardar desde datos dato cargar java image-recognition

ruta - recuperar imagen de base de datos java



¿Encontrar una imagen en una imagen con java? (2)

Lo que quiero es analizar la entrada de la pantalla en forma de imágenes. Quiero poder identificar una parte de una imagen en una imagen más grande y obtener sus coordenadas dentro de la imagen más grande. Ejemplo:

tendría que estar ubicado en

Y el resultado sería la esquina superior derecha de la imagen en la imagen grande y la parte inferior izquierda de la parte en la imagen grande. Como puede ver, la parte blanca de la imagen es irrelevante, lo que básicamente necesito es solo el marco verde. ¿Hay una biblioteca que pueda hacer algo como esto por mí? El tiempo de ejecución no es realmente un problema.

Lo que quiero hacer con esto es generar unas pocas coordenadas de píxeles aleatorias y reconocer el color en la imagen general en esa posición, para reconocer el cuadro verde más tarde. ¿Y cómo disminuiría el rendimiento, si el cuadro blanco en el medio es transparente?

La pregunta se ha formulado varias veces en SO como parece sin una sola respuesta. Encontré que encontré una solución en http://werner.yellowcouch.org/Papers/subimg/index.html . Desafortunadamente está en C ++ y no entiendo nada. Sería bueno tener una implementación de Java en SO.


El problema es difícil de responder en general porque las personas a menudo tienen diferentes requisitos para lo que cuenta como coincidencia de imagen. Es posible que algunas personas deseen buscar una imagen que tenga un tamaño u orientación diferente a la imagen de la plantilla que proporcionan, en cuyo caso se necesita un enfoque invariable de escala o rotación. Hay varias opciones, como buscar texturas, características o formas similares, pero me centraré en los enfoques que solo busquen píxeles de un color similar que estén exactamente en las mismas posiciones que la imagen de la plantilla. Esto parece más adecuado para su ejemplo, que parece caer en la categoría de coincidencia de plantillas .

Posibles enfoques

En este caso, el problema está estrechamente relacionado con los conceptos de procesamiento de señales de cross-correlation y convolution , que a menudo se implementan utilizando una FFT ya que es muy rápido (¡está en el nombre!). Esto es lo que se usó en el enfoque al que se http://werner.yellowcouch.org/Papers/subimg/index.html , y la biblioteca FFTW podría ser útil al intentar una implementación de este tipo, ya que tiene envoltorios para Java. El uso de la correlación cruzada funciona bastante bien, como se ve en this pregunta, así como la famosa pregunta waldo .

Otra opción es no usar todos los píxeles para la comparación, sino solo las características que son más fáciles de encontrar y que es más probable que sean únicas. Esto requeriría un descriptor de características como SIFT , SURF o uno de muchos others . Necesitará encontrar todas las características en ambas imágenes y luego buscar características que tengan posiciones similares a las de la imagen de la plantilla. Con este enfoque te sugiero que uses JavaCV .

El enfoque de adivinación aleatoria que mencionó debería funcionar rápido cuando sea posible, pero desafortunadamente no es generalmente aplicable ya que solo será útil con ciertas combinaciones de imágenes que producen una coincidencia cercana cerca de la ubicación correcta.

A menos que use una biblioteca externa, el método más simple en Java sería lo que yo llamaría un enfoque de fuerza bruta, aunque es un poco lento. El enfoque de fuerza bruta simplemente implica buscar en la imagen completa la subregión que mejor se adapte a la imagen que está buscando. Voy a explicar este enfoque más adelante. Primero debe definir cómo determinar la similitud entre dos imágenes de igual tamaño. Esto se puede hacer sumando las diferencias entre los colores del píxel, lo que requiere una definición para la diferencia entre los valores RGB.

Similitud de colores

Una forma de determinar la diferencia entre dos valores RGB es usar la distancia euclidiana:

sqrt( (r1-r2)^2 + (g1-g2)^2 + (b1-b2)^2 )

Hay diferentes espacios de color que RGB que se pueden usar, pero como su subimagen es casi idéntica (en lugar de solo visualmente similar), esto debería funcionar bien. Si tiene un espacio de color ARGB y no desea que los píxeles semitransparentes influyan tanto en sus resultados, puede utilizar:

a1 * a2 * sqrt( (r1-r2)^2 + (g1-g2)^2 + (b1-b2)^2 )

lo que dará un valor más pequeño si los colores tienen transparencia (asumiendo que a1 y a2 están entre 0 y 1). Le sugiero que use transparencia en lugar de áreas blancas y que utilice el formato de archivo PNG, ya que no utiliza la compresión con pérdida que distorsiona sutilmente los colores de la imagen.

Comparando imagenes

Para comparar imágenes de igual tamaño, puede sumar la diferencia entre sus píxeles individuales. Esta suma es entonces una medida de la diferencia y puede buscar la región en la imagen con la medida de diferencia más baja. Se vuelve más difícil si ni siquiera sabe si la imagen contiene la subimagen, pero esto se indicaría por la mejor coincidencia que tenga una medida de diferencia alta. Si lo desea, también puede normalizar la medida de la diferencia entre 0 y 1 dividiéndola entre el tamaño de la subimagen y la máxima diferencia RGB posible (sqrt (3) con la distancia euclidiana y los valores RGB de 0 a 1 ). Cero sería una coincidencia idéntica y cualquier cosa parecida a una sería lo más diferente posible.

Implementacion de fuerza bruta

Aquí hay una implementación simple que utiliza el enfoque de fuerza bruta para buscar la imagen. Con sus imágenes de ejemplo, encontró que la ubicación en (139,55) es la ubicación superior izquierda de la región con la mejor coincidencia (que parece correcta). Tardé entre 10 y 15 segundos en ejecutarse en mi PC y la medida de diferencia normalizada de la ubicación fue de alrededor de 0,57.

/** * Finds the a region in one image that best matches another, smaller, image. */ public static int[] findSubimage(BufferedImage im1, BufferedImage im2){ int w1 = im1.getWidth(); int h1 = im1.getHeight(); int w2 = im2.getWidth(); int h2 = im2.getHeight(); assert(w2 <= w1 && h2 <= h1); // will keep track of best position found int bestX = 0; int bestY = 0; double lowestDiff = Double.POSITIVE_INFINITY; // brute-force search through whole image (slow...) for(int x = 0;x < w1-w2;x++){ for(int y = 0;y < h1-h2;y++){ double comp = compareImages(im1.getSubimage(x,y,w2,h2),im2); if(comp < lowestDiff){ bestX = x; bestY = y; lowestDiff = comp; } } } // output similarity measure from 0 to 1, with 0 being identical System.out.println(lowestDiff); // return best location return new int[]{bestX,bestY}; } /** * Determines how different two identically sized regions are. */ public static double compareImages(BufferedImage im1, BufferedImage im2){ assert(im1.getHeight() == im2.getHeight() && im1.getWidth() == im2.getWidth()); double variation = 0.0; for(int x = 0;x < im1.getWidth();x++){ for(int y = 0;y < im1.getHeight();y++){ variation += compareARGB(im1.getRGB(x,y),im2.getRGB(x,y))/Math.sqrt(3); } } return variation/(im1.getWidth()*im1.getHeight()); } /** * Calculates the difference between two ARGB colours (BufferedImage.TYPE_INT_ARGB). */ public static double compareARGB(int rgb1, int rgb2){ double r1 = ((rgb1 >> 16) & 0xFF)/255.0; double r2 = ((rgb2 >> 16) & 0xFF)/255.0; double g1 = ((rgb1 >> 8) & 0xFF)/255.0; double g2 = ((rgb2 >> 8) & 0xFF)/255.0; double b1 = (rgb1 & 0xFF)/255.0; double b2 = (rgb2 & 0xFF)/255.0; double a1 = ((rgb1 >> 24) & 0xFF)/255.0; double a2 = ((rgb2 >> 24) & 0xFF)/255.0; // if there is transparency, the alpha values will make difference smaller return a1*a2*Math.sqrt((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)); }

No he mirado, pero quizás una de estas bibliotecas de procesamiento de imágenes Java también podría ser de alguna utilidad:

Si la velocidad es realmente importante, creo que el mejor enfoque sería una implementación que use correlación cruzada o descriptores de características que usen una biblioteca externa.


Lo que quieres es encontrar bloque de imágenes por máscara / límites.

Se puede hacer sin biblioteca externa. En el nivel bajo, cada imagen es una matriz de números, su máscara también es la matriz de números. Solo puede escanear linealmente una gran matriz y encontrar el área que sigue las reglas definidas por su máscara.

Ejemplo :

Matriz grande

1 0 1 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0

Máscara:

1 1 1 1 0 0 1 1 1

Aplica este algoritmo para detectar un bloque coincidente en una matriz grande en la esquina superior derecha, que le proporciona índices de matriz de inicio / fin y puede calcular estos valores en píxeles.

En el problema real, no tendrá un número establecido [0, 1] sino un byte mucho más grande, por ejemplo ( [0, 256] ). Para hacer que el algoritmo funcione mejor, emparejado significa que no es un número exacto, pero es posible con algunas desviaciones + -5 o algo así.