Rellenando huecos en una imagen usando Numpy y Scipy

La imagen (test.tif) está adjunta. Los valores np.nan son la región más blanca. ¿Cómo llenar esas regiones más blancas utilizando algunos algoritmos de relleno de huecos que usan valores de los vecinos?

introduzca la descripción de la imagen aquí

import scipy.ndimage data = ndimage.imread('test.tif') 

Creo que la pregunta de la viena está más relacionada con un problema de pintura .

Aquí hay algunas ideas:

  • Para llenar los huecos en las imágenes en blanco y negro, puede usar algún algoritmo de llenado como scipy.ndimage.morphology.binary_fill_holes . Pero tienes una imagen de nivel gris, así que no puedes usarla.

  • Supongo que no quieres usar un algoritmo de pintura complejo. Mi primera sugerencia es: No intente utilizar el valor de gris más cercano (no conoce el valor real de los píxeles de NaN). El uso del valor NEarest generará un algoritmo sucio. En su lugar, le sugiero que llene los huecos con algún otro valor (por ejemplo, la media de la fila). Puedes hacerlo sin encoding usando scikit-learn :

Fuente:

 >>> from sklearn.preprocessing import Imputer >>> imp = Imputer(strategy="mean") >>> a = np.random.random((5,5)) >>> a[(1,4,0,3),(2,4,2,0)] = np.nan >>> a array([[ 0.77473361, 0.62987193, nan, 0.11367791, 0.17633671], [ 0.68555944, 0.54680378, nan, 0.64186838, 0.15563309], [ 0.37784422, 0.59678177, 0.08103329, 0.60760487, 0.65288022], [ nan, 0.54097945, 0.30680838, 0.82303869, 0.22784574], [ 0.21223024, 0.06426663, 0.34254093, 0.22115931, nan]]) >>> a = imp.fit_transform(a) >>> a array([[ 0.77473361, 0.62987193, 0.24346087, 0.11367791, 0.17633671], [ 0.68555944, 0.54680378, 0.24346087, 0.64186838, 0.15563309], [ 0.37784422, 0.59678177, 0.08103329, 0.60760487, 0.65288022], [ 0.51259188, 0.54097945, 0.30680838, 0.82303869, 0.22784574], [ 0.21223024, 0.06426663, 0.34254093, 0.22115931, 0.30317394]]) 
  • La solución sucia que utiliza los valores más cercanos puede ser esta: 1) Encuentre los puntos perimetrales de las regiones NaN 2) Calcule todas las distancias entre los puntos NaN y el perímetro 3) Reemplace los NaNs con el valor del punto gris más cercano

Como otros han sugerido, scipy.interpolate puede ser usado. Sin embargo, requiere una manipulación de índice bastante extensa para que esto funcione.

Ejemplo completo:

 from pylab import * import numpy import scipy.ndimage import scipy.interpolate import pdb data = scipy.ndimage.imread('data.png') # a boolean array of (width, height) which False where there are missing values and True where there are valid (non-missing) values mask = ~( (data[:,:,0] == 255) & (data[:,:,1] == 255) & (data[:,:,2] == 255) ) # array of (number of points, 2) containing the x,y coordinates of the valid values only xx, yy = numpy.meshgrid(numpy.arange(data.shape[1]), numpy.arange(data.shape[0])) xym = numpy.vstack( (numpy.ravel(xx[mask]), numpy.ravel(yy[mask])) ).T # the valid values in the first, second, third color channel, as 1D arrays (in the same order as their coordinates in xym) data0 = numpy.ravel( data[:,:,0][mask] ) data1 = numpy.ravel( data[:,:,1][mask] ) data2 = numpy.ravel( data[:,:,2][mask] ) # three separate interpolators for the separate color channels interp0 = scipy.interpolate.NearestNDInterpolator( xym, data0 ) interp1 = scipy.interpolate.NearestNDInterpolator( xym, data1 ) interp2 = scipy.interpolate.NearestNDInterpolator( xym, data2 ) # interpolate the whole image, one color channel at a time result0 = interp0(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape ) result1 = interp1(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape ) result2 = interp2(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape ) # combine them into an output image result = numpy.dstack( (result0, result1, result2) ) imshow(result) show() 

Salida:

introduzca la descripción de la imagen aquí

Esto le pasa al interpolador todos los valores que tenemos, no solo los que están junto a los valores faltantes (que pueden ser algo ineficientes). También interpola cada punto en la salida, no solo los valores faltantes (que es extremadamente ineficiente). Una mejor manera es interpolar solo los valores faltantes y luego parchearlos en la imagen original. Este es solo un ejemplo de trabajo rápido para comenzar 🙂

Si desea valores de los vecinos más cercanos, puede usar el Interceptor de NearestND desde scipy.interpolate. También hay otros interpoladores , así que puede considerar.

Puede ubicar los valores de índice X, Y para los valores de NaN con:

 import numpy as np nan_locs = np.where(np.isnan(data)) 

También hay algunas otras opciones para la interpolación. Una opción es reemplazar los valores de NaN con los resultados de un filtro de mediana (pero sus áreas son un poco grandes para esto). Otra opción podría ser la dilatación en escala de grises . La interpolación correcta depende de su dominio final.

Si no ha utilizado un interpolador SciPy ND anteriormente, deberá proporcionar X, Y y datos de valores para ajustar el interpolador a los datos X e Y para que los valores se puedan interpolar. Puedes hacer esto usando el ejemplo anterior como plantilla.