使用NumPy和SciPy填补图像中的空缺

14

附带了图像(test.tif)。 np.nan值是最白的区域。 如何使用一些间隙填充算法填充这些最白的区域,这些算法使用邻居的值?

import scipy.ndimage

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

1
查看scipy interpolate库以找到适合您需求的函数。http://docs.scipy.org/doc/scipy/reference/interpolate.html - M4rtini
4个回答

22

正如其他人建议的那样,可以使用scipy.interpolate。但是,需要相当广泛的索引操作才能使其正常工作。

完整示例:

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

输出:

在此输入图片描述

这会将我们所有的值传递给内插器,而不仅仅是丢失值旁边的值(这可能有点低效)。它还会内插输出中的每个点,而不仅仅是缺失的值(这非常低效)。更好的方法是仅内插缺失的值,然后将其补丁到原始图像中。这只是一个快速的工作示例,可供参考 :)


10

我认为viena的问题更与修复图像有关。

以下是一些想法:

  • 为了填补黑白图像中的空白,可以使用一些填充算法,例如scipy.ndimage.morphology.binary_fill_holes。但你有一张灰度图像,所以不能使用它。

  • 我想你不想使用复杂的修复算法。我的第一个建议是:不要尝试使用最近的灰度值(你不知道NaN像素的真实值)。使用最近的值会产生一个脏算法。相反,我建议你用其他值(例如行的平均值)来填补缺口。你可以使用scikit-learn而不需要编码:

来源:

>>> 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]])
  • 使用最近值的“肮脏解决方案”可能是这样的: 1)找到NaN区域的周长点 2)计算NaN点和周长之间的所有距离 3)用最近点的灰度值替换NaN值

1
对于那些寻找sklearn.preprocessing.Imputer的人:其功能已经转移到sklearn.impute.SimpleImputer下,可参见此处。最近邻居(“肮脏的解决方案”)也被实现在了sklearn.impute.KNNImputer中,可以在此处找到该文档。 - mjkvaak

8
如果您想要最近邻居的值,可以使用scipy.interpolate中的NearestNDInterpolator。还有其他插值器也可以考虑。
您可以使用以下方法找到NaN值的X、Y索引值:
import numpy as np

nan_locs = np.where(np.isnan(data))

还有其他一些插值选项。其中之一是使用中位数滤波器的结果替换NaN值(但您的区域有点大)。另一个选项可能是灰度膨胀。正确的插值取决于您的最终领域。

如果您以前没有使用过SciPy ND插值器,则需要提供X、Y和值数据来适应插值器,然后提供X和Y数据进行插值。您可以使用上面的where示例作为模板。


4

OpenCV拥有一些图像修复算法,您可以使用它们。您只需要提供一个二进制掩码,指示哪些像素应该进行修复。

import cv2
import numpy as np
import scipy.ndimage

data = ndimage.imread("test.tif")
mask = np.isnan(data)
inpainted_img = cv2.inpaint(img, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接