首页 > 解决方案 > 如何使用 Numpy 高效地执行最近邻插值

问题描述

我有一个图像,为了这个问题,它只是一个 numpy 数组。我想过滤图像以去除孤立透明像素形式的噪声(更一般地说,我也想去除线条,但这是下一个问题)。

让我们设置一个可玩的例子:

a = np.ones((10, 10), np.uint8)
a[5,5] = 0    # isolated hole
a[5,6] = 2    # the neighbour to clone

导致这个矩阵:

       [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 0, 2, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

好吧,问题在于,当矩阵中有 0 时,我希望将其替换为最近的邻居(在这种情况下为 2,但如果易于实现,也许四个的平均值会更好)。

这可以在没有显式循环的情况下完成吗?

标签: numpyimage-processingnumpy-slicing

解决方案


使用布尔数组索引检测0条目。要计算所描述的平均值,请使用with和以下内核:ascipy.signal.convolve2dmode='same'

kernel = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / 4

最后,将找到的0条目替换a为卷积结果中的相应条目。请参阅此代码段:

import numpy as np
from scipy.signal import convolve2d

a = np.ones((10, 10), np.uint8)
a[5, 5] = 0
a[5, 6] = 2
print(a)

kernel = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / 4
b = convolve2d(a, kernel, mode='same')
a[a == 0] = b[a == 0]
print(a)

结果是:

[[1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 2 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]]

由于您初始化anp.uint8,实际替换值1.25被截断为1。如果您初始化anp.float32,您会看到,它1.25被正确放置在那里。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
NumPy:         1.20.1
SciPy:         1.6.0
----------------------------------------

编辑:如果您只想计算仅有的两个/三个邻居的平均值,硬编码内核将无法正确处理角点和边界像素。也许,在没有除法的情况下设置内核,并存储三个不同的卷积结果,每个结果除以234,并根据角、边界或常规像素的存在选择正确的值。


推荐阅读