Pregunta

He aquí lo que me gustaría hacer:

Estoy tomando fotos con una cámara web a intervalos regulares.Como una especie de time lapse cosa.Sin embargo, si no ha cambiado nada, es decir, la imagen bastante se ve el mismo, no quiero guardar la instantánea más reciente.

Me imagino que hay alguna manera de cuantificar la diferencia, y yo tendría que determinar empíricamente un umbral.

Estoy buscando la simplicidad en vez de la perfección.Estoy usando python.

¿Fue útil?

Solución

En General, la idea

Opción 1:Cargar imágenes como matrices (scipy.misc.imread) y calcular un elemento sabio (píxel a píxel) de diferencia.Calcular la norma de la diferencia.

Opción 2:De carga de ambas imágenes.Calcular algunas disponen de vector para cada uno de ellos (como un histograma).Calcular la distancia entre la función de los vectores en lugar de imágenes.

Sin embargo, hay algunas decisiones que tomar primero.

Preguntas

Usted debe responder estas preguntas, la primera:

  • Son imágenes de la misma forma y dimensión?

    Si no, usted puede necesitar cambiar el tamaño o recortar.PIL biblioteca ayudará a hacerlo en Python.

    Si se toman con la misma configuración y el mismo dispositivo, es probable que sean de la misma.

  • Son imágenes bien alineados?

    Si no, puede que desee ejecutar de correlación cruzada en primer lugar, para encontrar la mejor alineación de la primera.SciPy tiene funciones para hacerlo.

    Si la cámara y la escena aún, las imágenes son propensos a estar bien alineados.

  • Es la exposición de las imágenes siempre el mismo?(Es la luminosidad/contraste de la misma?)

    Si no, puede que desee para normalizar imágenes.

    Pero cuidado, en algunas situaciones esto puede hacer más mal que bien.Por ejemplo, un solo pixel brillante sobre un fondo oscuro hará que la normalizado imagen muy diferente.

  • Es el color de la información importante?

    Si desea aviso de los cambios de color, usted tendrá un vector de valores de color de cada punto, en lugar de un valor escalar como en escala de grises de la imagen.Necesita más atención al escribir dicho código.

  • Hay distintos bordes de la imagen?Es probable que se mueva?

    Si sí, usted puede solicitar borde algoritmo de detección de primera (por ejemplo,calcular el gradiente de con Sobel o Prewitt, transformar, aplicar un poco de umbral), a continuación, compare los bordes en la primera imagen a los bordes en el segundo.

  • Hay ruido en la imagen?

    Todos los sensores de contaminar la imagen con cierta cantidad de ruido.Sensores de bajo coste más ruido.Puede solicitar algunos de reducción de ruido antes de comparar imágenes.Blur es el más simple (pero no el mejor) enfoque de aquí.

  • ¿Qué tipo de cambios ¿quieres ver?

    Esto puede afectar a la elección de la norma a utilizar para la diferencia entre las imágenes.

    Considere el uso de Manhattan norma (la suma de los valores absolutos) o cero norma (el número de elementos no es igual a cero) para medir la cantidad de la imagen ha cambiado.A la primera se le diga lo mucho que la imagen está apagado, éste le indicará sólo el número de píxeles de diferentes.

Ejemplo

Puedo asumir que sus imágenes están bien alineados, el mismo tamaño y forma, posiblemente con diferente exposición.Para la simplicidad, convertir a escala de grises, incluso si son de color (RGB) de las imágenes.

Usted tendrá la importación de estos productos:

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

Función principal, la lectura de dos imágenes, convertir a escala de grises, comparar y resultados de impresión:

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

Cómo comparar. img1 y img2 son 2D SciPy matrices de aquí:

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

Si el archivo es una imagen en color, imread devuelve una matriz 3D, el promedio de los canales RGB (la última matriz de ejes) para obtener la intensidad.No es necesario hacerlo para imágenes en escala de grises (por ejemplo, .pgm):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
    else:
        return arr

La normalización es trivial, usted puede elegir para normalizar a [0,1] en lugar de [0,255]. arr es un SciPy matriz de aquí, así que todas las operaciones se elemento-sabio:

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

Ejecutar el main función:

if __name__ == "__main__":
    main()

Ahora usted puede poner todo esto en un script y ejecutar en contra de dos imágenes.Si comparamos la imagen de sí mismo, no hay ninguna diferencia:

$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

Si nos desenfoque de la imagen y comparar con el original, hay algunas diferencias:

$ python compare.py one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

P. S.Todo compare.py secuencia de comandos.

Actualización:las técnicas pertinentes

Como la pregunta es acerca de una secuencia de vídeo, en el que los marcos son propensos a ser casi el mismo, y busca algo inusual, me gustaría mencionar algunos de los enfoques alternativos que podrían ser de interés:

  • la sustracción de fondo y la segmentación (para detectar los objetos en primer plano)
  • dispersa el flujo óptico (para detectar movimiento)
  • la comparación de histogramas o algunas otras estadísticas en lugar de imágenes

Os recomiendo echar un vistazo a "el Aprendizaje de OpenCV" libro, los Capítulos 9 (Imagen piezas y segmentación) y 10 (Seguimiento y movimiento).El ex enseña a utilizar de Fondo método de sustracción, la última le da algo de información sobre el flujo óptico métodos.Todos los métodos se implementan en la biblioteca OpenCV.Si el uso de Python, yo sugiero usar OpenCV ≥ 2.3, y su cv2 Módulo de Python.

La versión más simple de la sustracción de fondo:

  • aprender el valor medio µ y desviación estándar σ para cada píxel del fondo
  • comparar actual de los valores de los píxeles para el rango de (μ-2σ,μ+2σ) o (µ-σ,μ+σ)

Versiones más avanzadas asegúrese de tomar en cuenta las series de tiempo para cada píxel y manejar no escenas estáticas (como el movimiento de los árboles o césped).

La idea de flujo óptico es tomar dos o más fotogramas, y asignar el vector de velocidad para cada píxel (denso flujo óptico) o a algunos de ellos (escaso flujo óptico).A escasa estimación de flujo óptico, usted puede usar Lucas-Kanade método (también es implementado en OpenCV).Obviamente, si hay una gran cantidad de flujo (alto promedio de más de valores máximos de la velocidad), entonces algo se está moviendo en el marco, y las imágenes posteriores son más diferentes.

La comparación de los histogramas pueden ayudar a detectar cambios bruscos entre fotogramas consecutivos.Este enfoque fue utilizado en Courbon et al, 2010:

La similitud de los fotogramas consecutivos. La distancia entre dos frames consecutivos se mide.Si es demasiado alto, esto significa que el segundo fotograma está dañado y por lo tanto la imagen es eliminada.El De Kullback–Leibler distancia, o mutua de la entropía, en los histogramas de los dos marcos:

$$ d(p,q) = \sum_i p(i) \log (p(i)/q(i)) $$

donde p y q son los histogramas de los marcos se utilizan.El umbral se fija en 0.2.

Otros consejos

Una solución simple:

Codifique la imagen como jpeg y busque un cambio sustancial en el tamaño de archivo .

Implementé algo similar con las miniaturas de video y tuve mucho éxito y escalabilidad.

Puede comparar dos imágenes utilizando funciones de PIL .

import Image
import ImageChops

im1 = Image.open("splash.png")
im2 = Image.open("splash2.png")

diff = ImageChops.difference(im2, im1)

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. La más simple es la función diff.getbbox(). 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.

Dos de los más conocidos y métodos relativamente sencillos son:(a) la distancia Euclidiana ya se ha sugerido, o (b) normalizado de correlación cruzada.Normalizado de correlación cruzada tiende a ser notablemente más robusto a cambios de luz que una simple correlación cruzada.Wikipedia da una fórmula para la normalizado de correlación cruzada.Métodos más sofisticados que existen, pero requieren un poco más de trabajo.

El uso de numpy-como la sintaxis,

dist_euclidean = sqrt(sum((i1 - i2)^2)) / i1.size

dist_manhattan = sum(abs(i1 - i2)) / i1.size

dist_ncc = sum( (i1 - mean(i1)) * (i2 - mean(i2)) ) / (
  (i1.size - 1) * stdev(i1) * stdev(i2) )

suponiendo que i1 y i2 son 2D imagen en escala de grises de matrices.

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.

Me dirijo específicamente a la cuestión de cómo calcular si son " suficientemente diferentes " ;. Supongo que puedes descubrir cómo restar los píxeles uno por uno.

Primero, tomaría un montón de imágenes con nada cambiando, y averiguaría la cantidad máxima que cualquier píxel cambia solo debido a variaciones en la captura, ruido en el sistema de imágenes, artefactos de compresión JPEG , y cambios de iluminación momento a momento. Tal vez encuentre que se esperan diferencias de 1 o 2 bits incluso cuando nada se mueve.

Entonces para " real " prueba, desea un criterio como este:

  • igual si hasta P píxeles difieren en no más de E.

Entonces, quizás, si E = 0.02, P = 1000, eso significaría (aproximadamente) que sería " diferente " si un solo píxel cambia en más de ~ 5 unidades (suponiendo imágenes de 8 bits), o si más de 1000 píxeles tuvieron algún error.

Esto está destinado principalmente como un buen & "; triaje &"; técnica para identificar rápidamente imágenes lo suficientemente cercanas como para no necesitar un examen más detallado. Las imágenes que & Quot; fail & Quot; puede 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 quot; 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 & Quot; imágenes de referencia & Quot; eso podría tener pequeñas diferencias de plataforma a plataforma o cuando realizamos pequeños ajustes a los algoritmos, por lo que queríamos una " coincidencia dentro de la tolerancia " operación.

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.

Otra buena manera simple para medir la similitud entre dos imágenes:

import sys
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread

# get two images - resize both to 1024 x 1024
img_a = resize(imread(sys.argv[1]), (2**10, 2**10))
img_b = resize(imread(sys.argv[2]), (2**10, 2**10))

# score: {-1:1} measure of the structural similarity between the images
score, diff = compare_ssim(img_a, img_b, full=True)
print(score)

Si otros están interesados en una forma más poderosa para comparar la semejanza de la imagen, puse una tutorial y web aplicación para la medición y la visualización de imágenes similares utilizando Tensorflow.

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

Que 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 100 píxeles en total, 0,33 ... / 100 = una diferencia de ~ 0,33% en la imagen.

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).

¿Has visto el Algoritmo para encontrar imágenes similares ? 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.

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:

  1. Simplifique las imágenes (¿umbral quizás?)
  2. Aplicar coincidencia de plantillas y verificar max_val con minMaxLoc

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:

previous_screenshot = ...
current_screenshot = ...

# simplify both images somehow

# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)

# hundred_p_val is now the 100%

res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)

difference_percentage = max_val / hundred_p_val

# the tolerance is now up to you

Espero que ayude.

La distancia de los cambiadores de tierra podría ser exactamente lo que necesita. Sin embargo, podría ser abit pesado implementarlo en tiempo real.

¿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.

He tenido mucha suerte con imágenes jpg tomadas con la misma cámara en un trípode por (1) simplificando enormemente (como pasar de 3000 píxeles de ancho a 100 píxeles de ancho o incluso menos) (2) aplanar cada matriz jpg en un solo vector (3) imágenes secuenciales de correlación 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 solicitud si r-cuadrado & Lt; 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?

puede 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 en el tiro en un video de cricket (en C usando openCV)

Vea cómo las isk-daemon implementan las Haar Wavelets. Puede usar su código imgdb C ++ para calcular la diferencia entre imágenes sobre la marcha:

  

isk-daemon es un servidor de base de datos de código abierto capaz de agregar búsquedas de imágenes (visuales) basadas en contenido a cualquier sitio web o software relacionado con imágenes.

     

Esta tecnología permite a los usuarios de cualquier sitio web o software relacionado con imágenes dibujar en un widget qué imagen desean encontrar y hacer que el sitio web les responda las imágenes más similares o simplemente soliciten fotos más similares en cada página de detalles de imagen.

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

Un enfoque algo más basado en principios es utilizar 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.

import os
from PIL import Image
from PIL import ImageFile
import imagehash

#just use to the size diferent picture
def compare_image(img_file1, img_file2):
    if img_file1 == img_file2:
        return True
    fp1 = open(img_file1, 'rb')
    fp2 = open(img_file2, 'rb')

    img1 = Image.open(fp1)
    img2 = Image.open(fp2)

    ImageFile.LOAD_TRUNCATED_IMAGES = True
    b = img1 == img2

    fp1.close()
    fp2.close()

    return b





#through picturu hash to compare
def get_hash_dict(dir):
    hash_dict = {}
    image_quantity = 0
    for _, _, files in os.walk(dir):
        for i, fileName in enumerate(files):
            with open(dir + fileName, 'rb') as fp:
                hash_dict[dir + fileName] = imagehash.average_hash(Image.open(fp))
                image_quantity += 1

    return hash_dict, image_quantity

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.
    recommend to use
    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_1 = None
    hash_2 = None
    with open(image_file_name_1, 'rb') as fp:
        hash_1 = imagehash.average_hash(Image.open(fp))
    with open(image_file_name_2, 'rb') as fp:
        hash_2 = imagehash.average_hash(Image.open(fp))
    dif = hash_1 - hash_2
    if dif < 0:
        dif = -dif
    if dif <= max_dif:
        return True
    else:
        return False


def compare_image_dir_with_hash(dir_1, dir_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.

    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_dict_1, image_quantity_1 = get_hash_dict(dir_1)
    hash_dict_2, image_quantity_2 = get_hash_dict(dir_2)

    if image_quantity_1 > image_quantity_2:
        tmp = image_quantity_1
        image_quantity_1 = image_quantity_2
        image_quantity_2 = tmp

        tmp = hash_dict_1
        hash_dict_1 = hash_dict_2
        hash_dict_2 = tmp

    result_dict = {}

    for k in hash_dict_1.keys():
        result_dict[k] = None

    for dif_i in range(0, max_dif + 1):
        have_none = False

        for k_1 in result_dict.keys():
            if result_dict.get(k_1) is None:
                have_none = True

        if not have_none:
            return result_dict

        for k_1, v_1 in hash_dict_1.items():
            for k_2, v_2 in hash_dict_2.items():
                sub = (v_1 - v_2)
                if sub < 0:
                    sub = -sub
                if sub == dif_i and result_dict.get(k_1) is None:
                    result_dict[k_1] = k_2
                    break
    return result_dict


def main():
    print(compare_image('image1\\815.jpg', 'image2\\5.jpg'))
    print(compare_image_with_hash('image1\\815.jpg', 'image2\\5.jpg', 6))
    r = compare_image_dir_with_hash('image1\\', image2\\', 10)
    for k in r.keys():
        print(k, r.get(k))


if __name__ == '__main__':
    main()
  • 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 imágenes de ejemplo:

    • 815.jpg
      815.jpg

    • 5.jpg
      5.jpg

Creo que podría simplemente 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.

Existen muchas métricas para evaluar si dos imágenes se ven / 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.

Generalmente, 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-assessment-of/10.1117/12.135952.short?SSO=1 )

Evaluación de 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 características para la evaluación de calidad de imagen ( https : //www4.comp.polyu.edu.hk/~cslzhang/IQA/TIP_IQA_FSIM.pdf )

Entre ellos, SSIM (Evaluación de calidad de imagen: desde la visibilidad del error hasta la similitud estructural) es el más fácil de calcular y su sobrecarga también es pequeña, como se informó en otro artículo " Evaluación de calidad de imagen basada en la similitud de gradiente quot; ( httpslar: https: //www.semant .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 & Quot; diferencia visual & Quot ;, & Quot; evaluación de calidad de imagen & Quot ;, etc., si está interesado / realmente le importa el arte .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top