Verificando las imágenes por similitud con OpenCV

¿OpenCV admite la comparación de dos imágenes, devolviendo algún valor (tal vez un porcentaje) que indique qué tan similares son estas imágenes? Por ejemplo, se devolvería el 100% si se pasara la misma imagen dos veces, se devolvería el 0% si las imágenes fueran totalmente diferentes.

Ya leí muchos temas similares aquí en StackOverflow. También hice bastante Google. Tristemente no pude encontrar una respuesta satisfactoria.

    Este es un tema realmente grande, con respuestas de 3 líneas de código a revistas de investigación completas.

    Esbozaré las técnicas más comunes y sus resultados.

    Comparando histogtwigs

    Uno de los métodos más simples y rápidos. Hace décadas propuestas como un medio para encontrar similitudes de imágenes. La idea es que un bosque tendrá mucho verde, y un rostro humano con mucho rosado, o lo que sea. Entonces, si comparas dos imágenes con bosques, obtendrás cierta similitud entre los histogtwigs, porque tienes mucho verde en ambos.

    Desventaja: es demasiado simplista. Un plátano y una playa se verán igual, ya que ambos son amarillos.

    Método OpenCV: compareHist ()

    Comparación de plantillas

    Un buen ejemplo aquí coincide con la plantilla para encontrar una buena coincidencia . Convuela la imagen de búsqueda con la que está buscando. Por lo general, se usa para encontrar partes de imágenes más pequeñas en una más grande.

    Desventajas: solo devuelve buenos resultados con imágenes idénticas, del mismo tamaño y orientación.
    Método OpenCV: matchTemplate ()

    Función de coincidencia

    Considerado una de las formas más eficientes de hacer búsqueda de imágenes. Se extraen varias características de una imagen, de modo que se garantice que las mismas características se vuelvan a reconocer incluso si se rotan / escalan / sesgan. Las características extraídas de esta manera se pueden comparar con otros conjuntos de características de imagen. Otra imagen que tiene una alta proporción de las características en la primera probablemente está representando el mismo objeto / escena. Se puede usar para encontrar la diferencia relativa en el ángulo de disparo entre las imágenes, o la cantidad de superposición.

    Hay una serie de tutoriales / muestras de OpenCV sobre esto, y un buen video aquí . Todo un módulo OpenCV (features2d) está dedicado a él.
    Desventajas: puede ser lento. No es perfecto

    Si para hacer coincidir imágenes idénticas (mismo tamaño / orientación)

    // 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 } 

    Fuente

    La solución de Sam debería ser suficiente. He usado la combinación de la diferencia de histogtwig y la coincidencia de plantillas porque ningún método me funcionaba el 100% de las veces. Sin embargo, he dado menos importancia al método de histogtwig. Así es como lo he implementado en script de Python simple.

     import cv2 class CompareImage(object): def __init__(self, image_1_path, image_2_path): self.minimum_commutative_image_diff = 1 self.image_1_path = image_1_path self.image_2_path = image_2_path def compare_image(self): image_1 = cv2.imread(self.image_1_path, 0) image_2 = cv2.imread(self.image_2_path, 0) commutative_image_diff = self.get_image_difference(image_1, image_2) if commutative_image_diff < self.minimum_commutative_image_diff: print "Matched" return commutative_image_diff return 10000 //random failure value @staticmethod def get_image_difference(image_1, image_2): first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256]) second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256]) img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA) img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0] img_template_diff = 1 - img_template_probability_match # taking only 10% of histogram diff, since it's less accurate than template method commutative_image_diff = (img_hist_diff / 10) + img_template_diff return commutative_image_diff if __name__ == '__main__': compare_image = CompareImage('image1/path', 'image2/path') image_difference = compare_image.compare_image() print image_difference 

    Un poco fuera de tema, pero útil es el enfoque nudo numpy . Es robusto y rápido, pero simplemente compara píxeles y no los objetos o datos que contiene la imagen (y requiere imágenes del mismo tamaño y forma):

    Un enfoque muy simple y rápido para hacer esto sin openCV y cualquier biblioteca para visión artificial es estandarizar las matrices de imágenes

     import numpy as np picture1 = np.random.rand(100,100) picture2 = np.random.rand(100,100) picture1_norm = picture1/np.sqrt(np.sum(picture1**2)) picture2_norm = picture2/np.sqrt(np.sum(picture2**2)) 

    Después de definir ambas imágenes normadas (o matrices), puede resumir la multiplicación de las imágenes que desea comparar:

    1) Si compara imágenes similares, la sum devolverá 1:

     In[1]: np.sum(picture1_norm**2) Out[1]: 1.0 

    2) Si no son similares, obtendrás un valor entre 0 y 1 (un porcentaje si multiplicas por 100):

     In[2]: np.sum(picture2_norm*picture1_norm) Out[2]: 0.75389941124629822 

    Tenga en cuenta que si tiene imágenes en color, debe hacerlo en las 3 dimensiones o simplemente comparar una versión greyscaled. A menudo tengo que comparar grandes cantidades de imágenes con contenido arbitrario y esa es una forma realmente rápida de hacerlo.