Método simple y rápido para comparar imágenes por similitud

Necesito una manera simple y rápida de comparar dos imágenes por similitud. Es decir, quiero obtener un gran valor si contienen exactamente lo mismo, pero pueden tener un fondo ligeramente diferente y pueden moverse / cambiar de tamaño en unos pocos píxeles.

(Más concretamente, si eso es importante: la imagen es un ícono y la otra imagen es una subárea de una captura de pantalla y quiero saber si esa subárea es exactamente el ícono o no).

Tengo OpenCV a la mano, pero todavía no estoy acostumbrado.

Una posibilidad que pensé hasta ahora: Divida ambas imágenes en celdas de 10×10 y para cada una de esas 100 celdas, compare el histogtwig de color. Entonces puedo establecer un valor de umbral compensado y si el valor que obtengo está por encima de ese umbral, supongo que son similares.

Todavía no lo he probado, qué bien funciona, pero creo que sería lo suficientemente bueno. Las imágenes ya son bastante similares (en mi caso de uso), así que puedo usar un valor de umbral bastante alto.

Supongo que hay docenas de otras posibles soluciones para esto que funcionarían más o menos (ya que la tarea en sí es bastante simple ya que solo quiero detectar similitudes si son muy similares). ¿Qué sugieres?


Hay algunas preguntas muy relacionadas / similares sobre cómo obtener una firma / huella digital / hash de una imagen:

  • OpenCV / SURF ¿Cómo generar una imagen hash / huella digital / firma de los descriptores?
  • Huella digital de imagen para comparar la similitud de muchas imágenes
  • Detección de imágenes casi duplicadas
  • OpenCV: Imagen de huella digital y comparación contra la base de datos .
  • más , más , más , más , más , más , más

Además, me encontré con estas implementaciones que tienen tales funciones para obtener una huella digital:

  • pHash
  • imgSeek ( Repo de GitHub ) (GPL) basado en el documento Consulta de imagen Fast Multiresolution
  • imagen-partido . Muy similar a lo que estaba buscando. Similar a pHash, basado en una firma de imagen para cualquier tipo de imagen, Goldberg et al . Utiliza Python y Elasticsearch.
  • iqdb
  • ImageHash . admite pHash.

Algunas discusiones sobre hashes de imagen perceptual: aquí


Un poco offtopic: existen muchos métodos para crear huellas dactilares de audio. MusicBrainz , un servicio web que ofrece búsqueda basada en huellas dactilares para canciones, tiene una buena visión general en su wiki . Están usando AcoustID ahora. Esto es para encontrar coincidencias exactas (o casi exactas). Para encontrar coincidencias similares (o si solo tiene algunos fragmentos o mucho ruido), eche un vistazo a Echoprint . Una pregunta relacionada SO está aquí . Entonces parece que esto está resuelto para el audio. Todas estas soluciones funcionan bastante bien.

Una pregunta algo más genérica sobre la búsqueda difusa en general está aquí . Por ejemplo, hay un hashing sensible a la localidad y la búsqueda del vecino más cercano .

¿Se puede transformar la captura de pantalla o el ícono (escalado, rotado, sesgado …)? Hay bastantes métodos sobre mi cabeza que podrían ayudarte:

  • Distancia euclídea simple según lo mencionado por @carlosdc (no funciona con imágenes transformadas y necesita un umbral).
  • Correlación cruzada (normalizada) : una medida simple que puede usar para comparar las áreas de imagen. Es más robusto que la simple distancia euclidiana, pero no funciona en imágenes transformadas y volverá a necesitar un umbral.
  • Comparación de histogtwigs : si usa histogtwigs normalizados, este método funciona bien y no se ve afectado por las transformaciones afines. El problema es determinar el umbral correcto. También es muy sensible a los cambios de color (brillo, contraste, etc.). Puedes combinarlo con los dos anteriores.
  • Detectores de puntos / áreas salientes , tales como MSER (regiones extremadamente estables extremas) , SURF o SIFT . Estos son algoritmos muy robustos y pueden ser demasiado complicados para su tarea simple. Lo bueno es que no tiene que tener un área exacta con un solo icono, estos detectores son lo suficientemente potentes como para encontrar la combinación adecuada. Una buena evaluación de estos métodos se encuentra en este documento: Detectores locales de características invariantes: una encuesta .

La mayoría de estos ya están implementados en OpenCV; consulte, por ejemplo, el método cvMatchTemplate (utiliza la coincidencia de histogtwigs): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Los detectores de puntos / áreas salientes también están disponibles; consulte Detección de características de OpenCV .

Me enfrento a los mismos problemas recientemente, para resolver este problema (algoritmo simple y rápido para comparar dos imágenes) de una vez por todas, contribuyo con un módulo img_hash a opencv_contrib, puede encontrar los detalles de este enlace .

El módulo img_hash proporciona seis algoritmos de hash de imagen, bastante fáciles de usar.

Ejemplo de códigos

origen lena origen lena

blur lena blur lena

cambiar el tamaño de lena cambiar el tamaño de lena

cambio lena cambio lena

#include  #include  #include  #include  #include  #include  void compute(cv::Ptr algo) { auto input = cv::imread("lena.png"); cv::Mat similar_img; //detect similiar image after blur attack cv::GaussianBlur(input, similar_img, {7,7}, 2, 2); cv::imwrite("lena_blur.png", similar_img); cv::Mat hash_input, hash_similar; algo->compute(input, hash_input); algo->compute(similar_img, hash_similar); std::cout<<"gaussian blur attack : "<< algo->compare(hash_input, hash_similar)<compute(similar_img, hash_similar); std::cout<<"shift attack : "<< algo->compare(hash_input, hash_similar)<compute(similar_img, hash_similar); std::cout<<"resize attack : "<< algo->compare(hash_input, hash_similar)< 

En este caso, ColorMomentHash nos da el mejor resultado

  • ataque borroso gaussiano: 0.567521
  • ataque de desplazamiento: 0.229728
  • cambiar el tamaño del ataque: 0.229358

Pros y contras de cada algoritmo

Rendimiento bajo diferentes ataques

El rendimiento de img_hash también es bueno

Comparación de velocidad con la biblioteca PHash (100 imágenes de ukbench) rendimiento de cálculo rendimiento de comparación

Si desea conocer los umbrales recomendados para estos algoritmos, consulte esta publicación ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Si le interesa saber cómo mido el rendimiento de los módulos img_hash (incluya velocidad y diferentes ataques), consulte este enlace ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).

¿La captura de pantalla contiene solo el ícono? Si es así, la distancia L2 de las dos imágenes podría ser suficiente. Si la distancia L2 no funciona, el siguiente paso es intentar algo simple y bien establecido, como: Lucas-Kanade . Lo que estoy seguro es que está disponible en OpenCV.

Si puede estar seguro de tener una alineación precisa de su plantilla (el ícono) con la región de prueba, entonces cualquier sum de diferencias de píxeles funcionará.

Si la alineación va a ser un poco escasa, puede pasar ambas imágenes con cv :: GaussianBlur antes de encontrar la sum de las diferencias de píxeles.

Si la calidad de la alineación es potencialmente deficiente, entonces recomendaría un histogtwig de degradados orientados o uno de los algoritmos de detección / descripción de puntos clave convenientes de OpenCV (como SIFT o SURF ).

Si desea obtener un índice sobre la similitud de las dos imágenes, le sugiero que obtenga de las métricas el índice SSIM. Es más consistente con el ojo humano. Aquí hay un artículo sobre esto: Índice de similitud estructural

También se implementa en OpenCV, y se puede acelerar con GPU: OpenCV SSIM con GPU

Si se combinan imágenes idénticas – código para la distancia L2

 // Compare two images by getting the L2 error (square-root of sum of squared error). double getSimilarity( const Mat A, const Mat B ) { if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) { // Calculate the L2 relative error between images. double errorL2 = norm( A, B, CV_L2 ); // Convert to a reasonable scale, since L2 error is summed across all pixels of the image. double similarity = errorL2 / (double)( A.rows * A.cols ); return similarity; } else { //Images have a different size return 100000000.0; // Return a bad value } 

Rápido. Pero no es robusto a los cambios en la iluminación / punto de vista, etc.

Si desea comparar la similitud de la imagen, le sugiero que use OpenCV. En OpenCV, hay pocas coincidencias de funciones y coincidencias de plantillas. Para la coincidencia de características, hay detector de SURF, SIFT, RÁPIDO y demás. Puede usar esto para detectar, describir y luego hacer coincidir la imagen. Después de eso, puede usar el índice específico para encontrar el número de coincidencias entre las dos imágenes.

    Intereting Posts