Cómo: paquetes de píxeles en una imagen a coordenadas de puntos representativas (x, y)


7

Tengamos una imagen (escala de grises o incluso binaria) como se muestra en la siguiente figura en el lado izquierdo, el objetivo es generar una lista de puntos, es decir, coordenadas en forma de (x, y) para cada paquete del píxeles oscuros en la imagen.
¿Cuáles son las herramientas de procesamiento de imágenes adecuadas para hacer esto y dónde están disponibles?

paquetes de píxeles para coordinar puntos


Actualizaciones:
1) Aquí puede encontrar más detalles sobre el problema. (Tenga en cuenta la variación en el tamaño de los paquetes)

detalles

Puedo sugerir que se detecten paquetes para calcular el límite del casco convexo para cada uno y luego encontrar el centroide representativo {ver esto para más detalles} .

paquete de píxeles al casco convexo al punto central


2)
Aquí está el resultado producido por la aplicación de la Transformación de Distancia (sugerido por "Libor"). Tenga en cuenta mis anotaciones en la figura. ¡El método no funciona como era prometedor!

ingrese la descripción de la imagen aquí

3) ¡
La erosión elimina los paquetes pequeños!

from __future__ import division
from scipy import zeros, ndimage as dsp
from pylab import subplot,plot,matshow,show

img = zeros((30,30))
img[10:14,10:14] = 1
img[16:17,16:17] = 1
img[19:23,19] = 1
img[19,19:23] = 1

subplot(221)
matshow(img,0)

subplot(222)
y = dsp.binary_erosion(img,[[1,1],[1,1]])
matshow(y,0)

subplot(223)
y = dsp.binary_erosion(img,[[0,1,0],[1,1,1],[0,1,0]])
matshow(y,0)

subplot(224)
y = dsp.binary_erosion(img,[[1,1,1],[1,1,1],[1,1,1]])
matshow(y,0)

show()

ingrese la descripción de la imagen aquí

4)
Bueno, aquí hay una implementación de Python (es decir, el lenguaje del amor :)) de la idea de etiquetado (también propuesta por "Jean-Yves" a continuación):

subplot(221)
l,n = dsp.label(img)
sl = dsp.find_objects(l)
for s in sl:
    x = (s[1].start+s[1].stop-1)/2
    y = (s[0].start+s[0].stop-1)/2
    plot(x,y,'wo')

y el resultado:

ingrese la descripción de la imagen aquí

Tenga en cuenta que, aunque se realiza en Python tan rápido debido al rendimiento de Scipy, el procedimiento en segundo plano en labelfunción debería ser una iteración agotadora. Esto puede considerarse como una compensación. Así que por un tiempo sigo ansioso por buscar algoritmos más eficientes. Y también tenga en cuenta que en el código dado anteriormente encontré el centro de la geometría de manera tan simple, mientras que para formas complejas o asimétricas esto puede hacer que el posicionamiento sea sesgado. Es decir, es un trabajo en progreso;).

5)
Aquí hay un caso complejo (una imagen real) capturado desde aquí en el que se aplicó la propuesta de etiquetado y verá los resultados. Tenga en cuenta que solo tomó 0.015 s para todo el procedimiento, incluido el etiquetado y la búsqueda de los objetos. Chicos astutos , creo que hicieron un muy buen trabajo. ¡Guauu! {haga clic derecho en la imagen, haga clic en ver imagen para resolución completa}

ingrese la descripción de la imagen aquí


¿Sabe usted: 1) Número de paquetes. 2) Max / Min x-size de un paquete. 3) Max / Min y-size de un paquete.
Spacey

@Mohammad Given es solo una imagen. Por lo tanto, ninguna de la información requerida que mencionó está disponible.
Desarrollador

Si puede detectar el número de paquetes, lo usaría como el valor de 'k' en un algoritmo genérico de k-medias. Convergirá al centro de cada grupo, dado un valor de k. Sin embargo, no estoy seguro de cómo podrá determinar el valor de 'k'. ¿Cómo vas a determinar eso?
Spacey

Necesita precisión de subpíxeles para la transformación / erosión de la distancia para detectar máximos en los parches pequeños (por ejemplo, 2x2). Hay máximos, pero no se pueden detectar ya que los omite con su muestreo. En caso de transformación de distancia, puede aumentar la muestra de su imagen por un factor de dos o calcular la transformación para las posiciones de subpíxel (0.0, 0.5, 1.0, 1.5 ...). En caso de erosión, puede implementarlo utilizando la morfología basada en PDE (iterativa).
Libor

@Developer, esta pregunta mía en SO podría ser de interés: stackoverflow.com/questions/4087919/…
Ivo Flipse el

Respuestas:


4

Solo una sugerencia ingenua: ¿sabes sobre el etiquetado de componentes ?

La técnica consiste en encontrar trozos de píxeles "en contacto" y asignarles una etiqueta, por ejemplo , un número entero. Luego puede interrogar cada grieta por separado, buscando el píxel que comparte la misma etiqueta.

En MATLAB, aquí está la función que lo hace trivialmente: bwlabel


Gracias por la propuesta Ya me había acercado de esta manera y, como mencionaste, actualicé la publicación con una implementación en Python . Surgí algunos problemas relacionados con el uso del etiquetado en la Actualización 4 :
Desarrollador

Voté esto porque es otro enfoque para resolver el problema. Gracias por compartir :)
Desarrollador

¿Podría aclarar la actualización 4? No entiendo lo que quieres decir con intercambio y agotamiento.
Jean-Yves

Hacer el etiquetado es un trabajo iterativo que requiere muchos cálculos. Sin embargo, Scipy Boys ha hecho un excelente trabajo (¡o algunos trucos!) Para hacerlo casi de inmediato. Puse un caso realmente complejo para la evaluación y funcionó solo en 0.015 s. ¿No es asombroso? Tenga en cuenta que la segunda parte, es decir, encontrar el centro de los paquetes detectados sigue siendo una pregunta. Aparentemente, no se recomienda la aplicación de casco convexo para un conjunto de paquetes tan variado.
Desarrollador

No estoy de acuerdo: el etiquetado de los componentes conectados NO es expansivo. Se ejecuta en tiempo lineal en la mayoría de las implementaciones modernas, y algunas incluso lograron que se ejecute con subprocesos múltiples.
Jean-Yves

3

También puede ejecutar una transformación de distancia en la imagen, luego detectar máximos locales (buscando píxeles con el valor más alto / más bajo de todos los píxeles en un parche de 3x3 píxeles; puede ser mayor dependiendo de la distancia mínima esperada entre los blobs originales).

Tenga en cuenta que para detectar características de tamaño de 1 a 3 píxeles, debe duplicar su frecuencia de muestreo (aumentar la imagen de origen o realizar una transformación / erosión de distancia con precisión de subpíxel).

ACTUALIZAR:

Los enfoques de transformación de distancia y erosión suponen que las características que está detectando son convexas. Algo con forma de U, por ejemplo, puede disparar en su detector varias veces.

Un método más elaborado para dicha segmentación se basa en conjuntos de niveles y contornos activos . Comienza con una gran curva cerrada que se adapta iterativamente a sus características. Este método se ha utilizado en mi universidad para contar células y detectar cromosomas en imágenes de microscopio.


Puede ver el resultado de mi implementación de su idea en la sección Actualizaciones: 2 . Parece que no funciona como se esperaba :(
Desarrollador

OK, he extendido mi respuesta.
Libor

Voté esto porque es otro enfoque para resolver el problema. Gracias por compartir :)
Desarrollador

2

Una opción sería aplicar erosión morfológica repetida a la imagen hasta que esté completamente erosionada. En ese punto, cada uno de los blobs que se muestran arriba se reduciría a un solo píxel; podría tomar las ubicaciones de esos píxeles como la lista de puntos que está buscando.


Algunos puntos: 1) ¿cómo detener la iteración? 2) puede desaparecer esos paquetes son más pequeños. 3) se ve muy intensivo en cómputo como la iteración requerida para todo el conjunto de datos. Tenga en cuenta que la imagen podría ser grande.
Desarrollador

Rápidamente implementé tu idea en su forma actual, pero no funcionó. Elimina paquetes pequeños. Se aplican todos mis comentarios anteriores.
Desarrollador

No estoy seguro de lo que quieres decir con "paquetes pequeños". ¿Se muestra alguno en la imagen de ejemplo?
Jason R

Bueno, como se muestra, los paquetes están en diferentes tamaños y formas y cuando apliqué erosión iterativa (Python: Scipy: Spatial: Erosion), los más pequeños (o más estrechos) desaparecieron. Tenga en cuenta que, en el caso real, el paquete en la imagen de entrada podría estar en el rango de un píxel a muy grande.
Desarrollador

@Developer ¿Conoces el número de 'paquetes' antes de tiempo? Por ejemplo, aquí tienes 6.
Spacey

2

Me temo que, sea cual sea la forma en que elija hacer esto, no será sencillo porque para asignar los objetivos a los grupos, tendrá que pasar por la imagen (al menos una vez).

Supongo que obtener los puntos es el problema más fácil de los dos (probablemente ya esté aplicando alguna forma de umbral, por ejemplo).

Para recuperar los grupos en los que se agrupan los puntos y hacerlo rápido, puede crear una estructura de cuatro árboles que contenga "cadenas de píxeles conectados" que se encuentren alrededor del área de la celda de cuatro árboles.

De esta manera, podría recorrer la imagen y, una vez que se encuentre con un píxel que es un objetivo, "empujarlo" en su estructura de árbol cuádruple.

Esta operación "push" comenzaría un proceso iterativo que devolvería la celda (en otras palabras, el área específica de la imagen) donde se encuentra el píxel en particular. Luego, puede iterar a través de todas las cadenas de píxeles que están asignadas a esa celda e intentar para "empujar" (nuevamente) el píxel a la cadena de píxeles. Una cadena de píxeles acepta un nuevo píxel si está al menos 1 píxel cerca de cualquiera de sus píxeles ya asignados. Si ninguna cadena de píxeles "acepta" el nuevo píxel, cree una nueva cadena de píxeles en esta celda y asígnele el nuevo píxel.

El quad-tree aquí es una forma de limitar su búsqueda de la cadena de píxeles más cercana y sería necesario si su imagen es grande y los objetivos numerosos para que las operaciones de empuje de la cadena de píxeles se realicen rápidamente. Si sabe que no va a tratar con una gran cantidad de objetivos, incluso podría saltarse el árbol cuádruple y mantener una simple "lista de cadenas de píxeles". Cada vez que te encuentras con un "objetivo", puedes recorrer las listas e intentar "empujar" el píxel sobre ellas. Si ninguna lista "admite" el píxel, cree una nueva lista y asígnele el píxel.

De cualquier forma que elija hacerlo, al final de este proceso tendrá un conjunto de "cadenas de píxeles" conectadas (sus grupos) que luego puede pasar a otra parte de su programa que se encargará de estimar sus ubicación. Puede ser casco convexo, ajuste de modelo (por ejemplo, elipsoide u otro) o simplemente la media / mediana de las coordenadas x, y.

Espero que esto ayude.


Voté esto porque es otro enfoque para resolver el problema. Gracias por compartir :)
Desarrollador
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.