Encontrando regiones en blanco en la imagen

Esta pregunta es un tanto agnóstica del lenguaje, pero mi herramienta de elección es una matriz numpy.

Lo que estoy haciendo es tomar la diferencia de dos imágenes a través de PIL:

img = ImageChops.difference(img1, img2) 

Y quiero encontrar las regiones rectangulares que contienen cambios de una imagen a otra. Por supuesto, existe el método incorporado en .getbbox() , pero si hay dos regiones con cambios, devolverá un cuadro de una región a otra, y si solo hay cambios de 1 píxel en cada esquina, devolverá la imagen completa.

Por ejemplo, considere lo siguiente donde o es un píxel distinto de cero:

 ______________________ |o ooo | | oooo ooo | | o | | oo | | | | oo o | | oo ooo | | oo ooooo | | ooo | | o | |____________________| 

Me gustaría obtener tuplas 4×4 que contienen los cuadros delimitadores para cada región que no sea cero. Para el caso del borde de la

 oooo o oo 

No me preocupa mucho cómo se maneja, ya sea que las dos secciones estén separadas o juntas, porque los límites de la forma de L invertida se superpondrán completamente con los de un solo píxel.

Nunca he hecho nada tan avanzado en el procesamiento de imágenes, así que quería obtener algo de entrada antes de escribir algo (y si hay métodos preexistentes en los módulos que ya estoy usando, ¡les doy la bienvenida!).

Mi versión psuedocode-ish es algo como esto:

 for line in image: started = False for pixel in line: if pixel and not started: started = True save start coords elif started and not pixel: started = False save end coords (x - 1 of course) 

Esto debería darme una lista de coordenadas, pero luego tengo que determinar si las regiones son contiguas. ¿Podría hacer eso con una búsqueda de tipo gráfico? (Hicimos un montón de DFS y BFS en Algoritmos el semestre pasado) ¿Por supuesto, supongo que podría hacerlo en lugar de mis bucles anteriores?

No haré esto en imágenes “grandes”; se extraen de una cámara web y la mejor que tengo actualmente es de 640×480. A lo sumo estaría haciendo 720p o 1080p, pero eso es lo suficientemente lejano en el futuro que no es una preocupación real.

Así que mi (s) pregunta (s): ¿Me dirijo al camino correcto o me alejé? Y, lo que es más importante, ¿hay funciones integradas que me impidan reinventar la rueda? Y, finalmente, ¿hay algún buen recurso que deba consultar (tutoriales, documentos, etc.) que ayude aquí?

¡Gracias!

Creo que el módulo ndimage de scipy tiene todo lo que necesitas …

Aquí hay un ejemplo rápido

 import numpy as np import scipy as sp import scipy.ndimage.morphology # The array you gave above data = np.array( [ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], ]) # Fill holes to make sure we get nice clusters filled = sp.ndimage.morphology.binary_fill_holes(data) # Now seperate each group of contigous ones into a distinct value # This will be an array of values from 1 - num_objects, with zeros # outside of any contigous object objects, num_objects = sp.ndimage.label(filled) # Now return a list of slices around each object # (This is effectively the tuple that you wanted) object_slices = sp.ndimage.find_objects(objects) # Just to illustrate using the object_slices for obj_slice in object_slices: print data[obj_slice] 

Esto produce:

 [[1]] [[1 1 1] [1 1 1]] [[1 1 1 1] [1 0 0 0] [1 0 0 1]] [[1]] [[0 1 1 0] [1 0 0 1] [0 1 1 0]] [[0 0 1 0 0] [0 1 1 1 0] [1 1 1 1 1] [0 1 1 1 0] [0 0 1 0 0]] 

Tenga en cuenta que los “object_slices” son básicamente lo que solicitó originalmente, si necesita las indicaciones reales.

Edición: Solo quería señalar que a pesar de que parece manejar adecuadamente el caso de borde de

 [[1 1 1 1] [1 0 0 0] [1 0 0 1]] 

en realidad no lo hace (por lo tanto, el solitario adicional [[1]]). Puede ver esto si imprime la matriz de “objetos” y observa los objetos 3 y 4.

 [[1 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0] [0 0 0 0 0 0 3 3 3 3 0 0 0 2 2 2 0 0 0 0] [0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 3 0 0 4 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 5 5 0 0 0 0 0 0 0 6 0 0 0 0 0] [0 0 0 0 5 5 5 5 0 0 0 0 0 6 6 6 0 0 0 0] [0 0 0 0 0 5 5 0 0 0 0 0 6 6 6 6 6 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0]] 

¡Espero que ayude!

[ 1 ]

Puede buscar componentes conectados en la imagen y luego determinar los cuadros delimitadores de estos componentes.

Un paquete de agrupación en clúster ( es decir, esto ) debe poder realizar la mayor parte del trabajo (encontrar píxeles conectados). Encontrar el cuadro delimitador para un clúster es trivial.