Esto es lo que me gustaría hacer:
Estoy tomando fotos con una cámara web a intervalos regulares. Algo así como un lapso de tiempo. Sin embargo, si nada ha cambiado realmente, es decir, la imagen se ve más o menos igual, no quiero almacenar la última instantánea.
Me imagino que hay alguna forma de cuantificar la diferencia, y tendría que determinar empíricamente un umbral.
Estoy buscando simplicidad en lugar de perfección. Estoy usando python
Respuestas:
Idea general
Opción 1: Cargue ambas imágenes como matrices (
scipy.misc.imread
) y calcule una diferencia de elemento (píxel por píxel). Calcule la norma de la diferencia.Opción 2: cargar ambas imágenes. Calcule algún vector de características para cada uno de ellos (como un histograma). Calcule la distancia entre vectores de características en lugar de imágenes.
Sin embargo, hay algunas decisiones que tomar primero.
Preguntas
Primero debe responder estas preguntas:
¿Son las imágenes de la misma forma y dimensión?
De lo contrario, es posible que deba cambiar su tamaño o recortarlos. La biblioteca PIL ayudará a hacerlo en Python.
Si se toman con la misma configuración y el mismo dispositivo, probablemente sean lo mismo.
¿Las imágenes están bien alineadas?
Si no, es posible que desee ejecutar primero la correlación cruzada, para encontrar primero la mejor alineación. SciPy tiene funciones para hacerlo.
Si la cámara y la escena están quietas, es probable que las imágenes estén bien alineadas.
¿La exposición de las imágenes es siempre la misma? (¿La luminosidad / contraste es lo mismo?)
Si no, es posible que desee normalizar las imágenes.
Pero tenga cuidado, en algunas situaciones esto puede hacer más mal que bien. Por ejemplo, un solo píxel brillante sobre un fondo oscuro hará que la imagen normalizada sea muy diferente.
¿Es importante la información de color?
Si desea notar cambios de color, tendrá un vector de valores de color por punto, en lugar de un valor escalar como en la imagen en escala de grises. Necesita más atención al escribir dicho código.
¿Hay bordes distintos en la imagen? ¿Es probable que se muevan?
En caso afirmativo, puede aplicar primero el algoritmo de detección de bordes (por ejemplo, calcular el gradiente con la transformación Sobel o Prewitt, aplicar algún umbral), luego comparar los bordes en la primera imagen con los bordes en la segunda.
¿Hay ruido en la imagen?
Todos los sensores contaminan la imagen con cierta cantidad de ruido. Los sensores de bajo costo tienen más ruido. Es posible que desee aplicar algo de reducción de ruido antes de comparar imágenes. Desenfocar es el enfoque más simple (pero no el mejor) aquí.
¿Qué tipo de cambios quieres notar?
Esto puede afectar la elección de la norma a utilizar para la diferencia entre imágenes.
Considere usar la norma de Manhattan (la suma de los valores absolutos) o la norma cero (el número de elementos que no son iguales a cero) para medir cuánto ha cambiado la imagen. El primero le dirá cuánto está apagada la imagen, el segundo le dirá cuántos píxeles difieren.
Ejemplo
Supongo que sus imágenes están bien alineadas, tienen el mismo tamaño y forma, posiblemente con diferente exposición. Para simplificar, los convierto a escala de grises incluso si son imágenes en color (RGB).
Necesitará estas importaciones:
Función principal, leer dos imágenes, convertir a escala de grises, comparar e imprimir resultados:
Cómo comparar
img1
yimg2
son matrices 2D SciPy aquí:Si el archivo es una imagen en color,
imread
devuelve una matriz 3D, canales RGB promedio (el último eje de la matriz) para obtener intensidad. No es necesario hacerlo para imágenes en escala de grises (por ejemplo.pgm
):La normalización es trivial, puede elegir normalizar a [0,1] en lugar de [0,255].
arr
es una matriz SciPy aquí, por lo que todas las operaciones son por elementos:Ejecuta la
main
función:Ahora puede poner todo esto en un script y ejecutar dos imágenes. Si comparamos la imagen consigo misma, no hay diferencia:
Si desenfocamos la imagen y la comparamos con la original, hay alguna diferencia:
PD : guión compare.py completo .
Actualización: técnicas relevantes
Como la pregunta es sobre una secuencia de video, donde es probable que los cuadros sean casi iguales, y se busca algo inusual, me gustaría mencionar algunos enfoques alternativos que pueden ser relevantes:
Recomiendo echar un vistazo al libro "Learning OpenCV", Capítulos 9 (Partes de imagen y segmentación) y 10 (Seguimiento y movimiento). El primero enseña a usar el método de sustracción de fondo, el último da información sobre los métodos de flujo óptico. Todos los métodos se implementan en la biblioteca OpenCV. Si usa Python, sugiero usar OpenCV ≥ 2.3, y su
cv2
módulo Python.La versión más simple de la resta de fondo:
Las versiones más avanzadas tienen en cuenta las series temporales para cada píxel y manejan escenas no estáticas (como mover árboles o césped).
La idea del flujo óptico es tomar dos o más cuadros y asignar un vector de velocidad a cada píxel (flujo óptico denso) o a algunos de ellos (flujo óptico disperso). Para estimar el flujo óptico disperso, puede usar el método Lucas-Kanade (también se implementa en OpenCV). Obviamente, si hay mucho flujo (promedio alto sobre los valores máximos del campo de velocidad), entonces algo se mueve en el cuadro y las imágenes posteriores son más diferentes.
La comparación de histogramas puede ayudar a detectar cambios repentinos entre cuadros consecutivos. Este enfoque se utilizó en Courbon et al, 2010 :
fuente
RuntimeWarning: invalid value encountered in double_scalars
en línea 44 (return (arr-amin)*255/rng
) y unValueError: array must not contain infs or NaNs
en línea 30 (z_norm = norm(diff.ravel(), 0)
)rng
igual a cero. Solo agregue un cheque yrng = 1
Una solución simple:
Codificar la imagen como un archivo JPEG y busque un cambio sustancial en el tamaño del archivo .
Implementé algo similar con las miniaturas de video y tuve mucho éxito y escalabilidad.
fuente
Puede comparar dos imágenes usando las funciones de PIL .
El objeto diff es una imagen en la que cada píxel es el resultado de la resta de los valores de color de ese píxel en la segunda imagen de la primera imagen. Usando la imagen diff puedes hacer varias cosas. El más simple es el
diff.getbbox()
función. Le indicará el rectángulo mínimo que contiene todos los cambios entre sus dos imágenes.Probablemente pueda implementar aproximaciones de las otras cosas mencionadas aquí usando funciones de PIL también.
fuente
Dos métodos populares y relativamente simples son: (a) la distancia euclidiana ya sugerida, o (b) la correlación cruzada normalizada. La correlación cruzada normalizada tiende a ser notablemente más robusta a los cambios de iluminación que la simple correlación cruzada. Wikipedia da una fórmula para la correlación cruzada normalizada . También existen métodos más sofisticados, pero requieren bastante más trabajo.
Usando sintaxis tipo numpy,
suponiendo eso
i1
yi2
son matrices de imágenes en escala de grises 2D.fuente
Una cosa trivial para probar:
Vuelva a muestrear ambas imágenes en miniaturas pequeñas (por ejemplo, 64 x 64) y compare las miniaturas píxel por píxel con un cierto umbral. Si las imágenes originales son casi iguales, las miniaturas muestreadas serán muy similares o incluso exactamente las mismas. Este método se encarga del ruido que puede ocurrir especialmente en escenas con poca luz. Incluso puede ser mejor si vas en escala de grises.
fuente
Me dirijo específicamente a la cuestión de cómo calcular si son "lo suficientemente diferentes". Supongo que puedes descubrir cómo restar los píxeles uno por uno.
Primero, tomaría un montón de imágenes sin cambios, y averiguaría la cantidad máxima que cualquier píxel cambia solo por las variaciones en la captura, el ruido en el sistema de imágenes, los artefactos de compresión JPEG y los cambios de iluminación momento a momento . Tal vez encuentre que se esperan diferencias de 1 o 2 bits incluso cuando nada se mueve.
Luego, para la prueba "real", desea un criterio como este:
Entonces, tal vez, si E = 0.02, P = 1000, eso significaría (aproximadamente) que sería "diferente" si cualquier píxel cambia en más de ~ 5 unidades (suponiendo imágenes de 8 bits), o si más de 1000 píxeles tenían algún error en absoluto.
Esto está pensado principalmente como una buena técnica de "triaje" para identificar rápidamente imágenes que están lo suficientemente cerca como para no necesitar un examen más detallado. Las imágenes que "fallan" pueden entonces ser más una técnica más elaborada / costosa que no tendría falsos positivos si la cámara se sacudiera un poco, por ejemplo, o fuera más robusta a los cambios de iluminación.
Ejecuto un proyecto de código abierto, OpenImageIO , que contiene una utilidad llamada "idiff" que compara las diferencias con umbrales como este (aún más elaborado, en realidad). Incluso si no desea utilizar este software, puede consultar la fuente para ver cómo lo hicimos. Se utiliza bastante comercialmente y esta técnica de umbral se desarrolló para que pudiéramos tener un conjunto de pruebas para el software de procesamiento y procesamiento de imágenes, con "imágenes de referencia" que podrían tener pequeñas diferencias de plataforma a plataforma o cuando realizamos pequeños ajustes a tha algoritmos, por lo que queríamos una operación de "coincidencia dentro de la tolerancia".
fuente
Tuve un problema similar en el trabajo, estaba reescribiendo nuestro punto final de transformación de imagen y quería comprobar que la nueva versión producía el mismo o casi el mismo resultado que la versión anterior. Entonces escribí esto:
https://github.com/nicolashahn/diffimg
El cual opera en imágenes del mismo tamaño, y en un nivel por píxel, mide la diferencia de valores en cada canal: R, G, B (, A), toma la diferencia promedio de esos canales y luego promedia la diferencia sobre todos los píxeles, y devuelve una relación.
Por ejemplo, con una imagen de 10x10 píxeles blancos, y la misma imagen pero un píxel ha cambiado a rojo, la diferencia en ese píxel es 1/3 o 0.33 ... (RGB 0,0,0 vs 255,0,0 ) y en todos los demás píxeles es 0. Con un total de 100 píxeles, 0,33 ... / 100 = una diferencia de imagen de ~ 0,33%.
Creo que esto funcionaría perfectamente para el proyecto de OP (me doy cuenta de que esta es una publicación muy antigua ahora, pero está publicando para futuros StackOverflowers que también quieren comparar imágenes en python).
fuente
La mayoría de las respuestas dadas no abordarán los niveles de iluminación.
Primero normalizaría la imagen a un nivel de luz estándar antes de hacer la comparación.
fuente
Otra forma agradable y simple de medir la similitud entre dos imágenes:
Si otros están interesados en una forma más poderosa de comparar la similitud de la imagen, preparé un tutorial imágenes, preparé y una aplicación web para medir y visualizar imágenes similares usando Tensorflow.
fuente
skimage
es realmente agradable de usar para esta aplicación. Yo usofrom skimage.measure import compare_ssim, compare_mse
mucho skimage.measure docs .¿Has visto el algoritmo para encontrar imágenes similares? pregunta ? Compruébalo para ver sugerencias.
Sugeriría una transformación wavelet de sus marcos (he escrito una extensión C para eso usando la transformación Haar); luego, al comparar los índices de los factores wavelet más grandes (proporcionalmente) entre las dos imágenes, debe obtener una aproximación de similitud numérica.
fuente
Pido disculpas si es demasiado tarde para responder, pero como he estado haciendo algo similar, pensé que podría contribuir de alguna manera.
Quizás con OpenCV podría usar la coincidencia de plantillas. Asumiendo que estás usando una cámara web como dijiste:
Consejo: max_val (o min_val dependiendo del método utilizado) le dará números, números grandes. Para obtener la diferencia en porcentaje, use una plantilla que coincida con la misma imagen; el resultado será su 100%.
Pseudocódigo para ejemplificar:
Espero eso ayude.
fuente
La distancia de los motores de la Tierra podría ser exactamente lo que necesita. Sin embargo, podría ser bastante pesado implementarlo en tiempo real.
fuente
¿Qué pasa con el cálculo de la distancia de Manhattan de las dos imágenes? Eso te da n * n valores. Entonces podría hacer algo como un promedio de fila para reducir a n valores y una función sobre eso para obtener un solo valor.
fuente
He tenido mucha suerte con las imágenes jpg tomadas con la misma cámara en un trípode al (1) simplificar enormemente (como pasar de 3000 píxeles de ancho a 100 píxeles de ancho o incluso menos) (2) aplanar cada conjunto de jpg en un solo vector (3) imágenes secuenciales que se correlacionan por pares con un algoritmo de correlación simple para obtener el coeficiente de correlación (4) coeficiente de correlación de cuadratura para obtener r-cuadrado (es decir, fracción de variabilidad en una imagen explicada por la variación en la siguiente) (5) generalmente en mi aplicación si r-cuadrado <0.9, digo que las dos imágenes son diferentes y algo sucedió en el medio.
Esto es robusto y rápido en mi implementación (Mathematica 7)
Vale la pena jugar con la parte de la imagen que le interesa y enfocarse en eso recortando todas las imágenes en esa pequeña área, de lo contrario se perderá un cambio distante de la cámara pero importante.
No sé cómo usar Python, pero estoy seguro de que también tiene correlaciones, ¿no?
fuente
puedes calcular el histograma de ambas imágenes y luego calcular el Coeficiente de Bhattacharyya , este es un algoritmo muy rápido y lo he usado para detectar cambios de disparo en un video de cricket (en C usando openCV)
fuente
Echa un vistazo a cómo isar-daemon implementa las Wavelets de Haar . Puede usar su código imgdb C ++ para calcular la diferencia entre imágenes sobre la marcha:
fuente
Tuve el mismo problema y escribí un módulo simple de Python que compara dos imágenes del mismo tamaño usando ImageChops de pillow para crear una imagen de diferencias en blanco y negro y resume los valores del histograma.
Puede obtener este puntaje directamente o un valor porcentual en comparación con una diferencia completa de blanco y negro.
También contiene una función simple is_equal, con la posibilidad de proporcionar un umbral difuso debajo (e incluido) de que la imagen pase como igual.
El enfoque no es muy elaborado, pero tal vez sea útil para otros que luchan con el mismo problema.
https://pypi.python.org/pypi/imgcompare/
fuente
Un enfoque algo más basado en principios es usar un descriptor global para comparar imágenes, como GIST o CENTRIST. Una función hash, como se describe aquí , también proporciona una solución similar.
fuente
salida:
Falso
Verdadero
image2 \ 5.jpg image1 \ 815.jpg
image2 \ 6.jpg image1 \ 819.jpg
image2 \ 7.jpg image1 \ 900.jpg
image2 \ 8.jpg image1 \ 998.jpg
image2 \ 9.jpg image1 \ 1012 .jpg
las fotos de ejemplo:
815.jpg
5.jpg
fuente
Creo que simplemente podría calcular la distancia euclidiana (es decir, sqrt (suma de cuadrados de diferencias, píxel por píxel)) entre la luminancia de las dos imágenes, y considerarlas iguales si esto cae por debajo de algún umbral empírico. Y será mejor que lo haga envolviendo una función C.
fuente
Existen muchas métricas para evaluar si se ven dos imágenes / cuánto se ven.
No entraré en ningún código aquí, porque creo que debería ser un problema científico, además de un problema técnico.
En general, la pregunta está relacionada con la percepción humana en las imágenes, por lo que cada algoritmo tiene su apoyo en los rasgos del sistema visual humano.
Los enfoques clásicos son:
Predictor de diferencias visibles: un algoritmo para la evaluación de la fidelidad de la imagen ( https://www.spiedigitallibrary.org/conference-proceedings-of-spie/1666/0000/Visible-differences-predictor--an-algorithm-for-the- evaluación-de / 10.1117 / 12.135952.short? SSO = 1 )
Evaluación de la calidad de imagen: de la visibilidad del error a la similitud estructural ( http://www.cns.nyu.edu/pub/lcv/wang03-reprint.pdf )
FSIM: un índice de similitud de funciones para la evaluación de la calidad de imagen ( https://www4.comp.polyu.edu.hk/~cslzhang/IQA/TIP_IQA_FSIM.pdf )
Entre ellos, SSIM (Evaluación de calidad de imagen: de la visibilidad del error a la similitud estructural) es el más fácil de calcular y su sobrecarga también es pequeña, como se informó en otro documento "Evaluación de la calidad de la imagen basada en la similitud de gradiente" ( https: //www.semanticscholar .org / paper / Image-Quality-Assessment-Based-on-Gradient-Liu-Lin / 2b819bef80c02d5d4cb56f27b202535e119df988 ).
Hay muchos otros enfoques más. Eche un vistazo a Google Académico y busque algo como "diferencia visual", "evaluación de calidad de imagen", etc., si está interesado / realmente se preocupa por el arte.
fuente
Hay una solución simple y rápida usando numpy calculando el error cuadrático medio:
fuente