Python: tomando el GLCM de una región no rectangular

He estado usando la implementación SLIC de skimage para segmentar imágenes en superpíxeles. Me gustaría usar GLCMs para extraer funciones adicionales de estos superpíxeles para un problema de clasificación. Estos superpíxeles no son rectangulares. En MATLAB puede establecer píxeles en NaN y serán ignorados por el algoritmo ( enlace ). Podría usar esto para hacer cuadros delimitadores alrededor de los súper píxeles y luego simplemente establecer los píxeles no utilizados en NaN.

Sin embargo, la función greycomatrix en skimage no funciona del mismo modo que la implementación de MATLAB. Al configurar los píxeles en NaN, la función falla en una aserción para verificar si todos los valores son mayores que 0.

¿Hay alguna implementación de Python disponible que pueda funcionar con ROI no rectangulares?

Aunque mahotas es también una excelente biblioteca de visión artificial, no es necesario dejar de usar skimage para hacer esto.

Lo que es necesario, como lo señaló @Tonechas, es establecer esos valores de NaN en un entero, ya que np.nan tiene el tipo float y la función greycomatrix requiere una matriz de enteros.

La opción más fácil sería establecer esos NaN en cero, pero si ya tiene cero valores en sus píxeles y no desea mezclarlos, puede elegir cualquier otra constante. Después de eso, todo lo que tiene que hacer es filtrar el valor elegido (una vez más, generalmente cero) fuera del GLCM.

Para entender lo que esto significa, veamos lo que skimage nos dice acerca de la salida de la función greycomatrix :

Ndarray 4-D

[…] El valor P [i, j, d, theta] es el número de veces que se produce el nivel de gris j a una distancia dy en el ángulo theta desde el nivel de gris i. Si Normed es False, la salida es de tipo uint32, de lo contrario es float64. Las dimensiones son: niveles x niveles x número de distancias x número de angularjs.

En otras palabras, las dos primeras dimensiones de la matriz definen una matriz que nos dice cuántas veces dos valores diferentes están separados por cierta distancia. Tenga en cuenta que el GLCM no mantiene la forma de la matriz de entrada. Esas filas y columnas nos dicen cómo se relacionan los valores.

Sabiendo esto, es fácil filtrar los valores fuera de nuestro ROI (imagina que hemos establecido esos NaN en cero):

 glcm = greycomatrix(img, [1], [0]) # Calculate the GLCM "one pixel to the right" filt_glcm = glcm[1:, 1:, :, :] # Filter out the first row and column 

Ahora puede calcular fácilmente las propiedades Haralick de su GLCM filtrado. Por ejemplo:

 greycoprops(filt_glcm, prop='contrast') 

El problema es que tienes que pasar una matriz de enteros a greycomatrix , pero np.nan tiene el tipo float (mira este hilo para más detalles). Como resultado, no puede codificar los píxeles fuera del ROI como NaN .

Una solución aproximada para tratar con ROI no rectangulares sería establecer los píxeles fuera del ROI en 0 y usar la función haralick from mahotas library. Esta función devuelve 13 características de Haralick extraídas de cuatro GLCM diferentes, correspondientes a las cuatro orientaciones 2-D y al valor particular del parámetro de distancia.

De la documentación:

ignore_zeros puede usar ignore_zeros para que la función ignore los píxeles de valor cero (como fondo).

En resumen, debe enmascarar aquellos píxeles que quedan fuera del ROI y establecer ignore_zeros en True en la llamada a haralick .


MANIFESTACIÓN

Para empezar, vamos a generar algunos datos simulados:

 In [213]: import numpy as np In [214]: shape = (3, 4) In [215]: levels = 8 In [216]: np.random.seed(2017) In [217]: x = np.random.randint(0, levels, size=shape) In [218]: x Out[218]: array([[3, 1, 6, 5], [2, 0, 2, 2], [3, 7, 7, 7]]) 

Luego tenemos que eliminar todos los ceros de la imagen, ya que en este enfoque el nivel de intensidad cero está reservado para los píxeles fuera del ROI. Vale la pena señalar que la combinación de las intensidades 0 y 1 en una sola intensidad 1 introduce imprecisiones en los resultados.

 In [219]: x[x == 0] = 1 In [220]: x Out[220]: array([[3, 1, 6, 5], [2, 1, 2, 2], [3, 7, 7, 7]]) 

El siguiente paso consiste en definir una máscara para los píxeles fuera del ROI (en este ejemplo de juguete, las cuatro esquinas de la imagen) y establecer esos píxeles en 0 .

 In [221]: non_roi = np.zeros(shape=shape, dtype=np.bool) In [222]: non_roi[np.ix_([0, -1], [0, -1])] = True In [223]: non_roi Out[223]: array([[ True, False, False, True], [False, False, False, False], [ True, False, False, True]], dtype=bool) In [224]: x[non_roi] = 0 In [225]: x Out[225]: array([[0, 1, 6, 0], [2, 1, 2, 2], [0, 7, 7, 0]]) 

Ahora podemos realizar la extracción de características de los GLCM de un retorno de la inversión no rectangular:

 In [226]: import mahotas.features.texture as mht In [227]: features = mht.haralick(x, ignore_zeros=True) In [228]: features.size Out[228]: 52 In [229]: features.ravel() Out[229]: array([ 0.18 , 5.4 , 0.5254833 , ..., 0.81127812, -0.68810414, 0.96300727]) 

Puede ser útil verificar cómo se ven las matrices de co-ocurrencia. Por ejemplo, el GLCM de “píxel a la derecha” sería:

 In [230]: mht.cooccurence(x, 0) Out[230]: array([[0, 1, 0, ..., 0, 1, 2], [1, 0, 2, ..., 0, 1, 0], [0, 2, 2, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [1, 1, 0, ..., 0, 0, 0], [2, 0, 0, ..., 0, 0, 2]])