没有任何padding-opencv Python的卷积

Har*_*dia 4 python opencv numpy image-processing

Opencv-python中是否有任何函数可以将图像与内核卷积而无需填充?基本上,我希望只在其中内核与图像部分完全重叠的区域中进行卷积的图像。

ray*_*ica 6

OpenCV仅支持卷积图像,其中返回的输出与输入图像的大小相同。这样,您仍然可以使用OpenCV的过滤器功能,而只是忽略内核未完全将自身封装在图像内部的边缘的那些像素。假设您的图像内核是奇数,则可以将每个维度简单地除以一半,取整(或向下取整),然后使用它们切掉无效的信息并返回剩余的信息。正如Divakar所提到的,这与使用带有选项scipy的2D卷积方法相同'valid'

这样,假设您的映像存储在中A,内核存储在中B,则只需执行以下操作即可获取过滤后的映像,其中内核已完全封装在映像中。请注意,我们将假设内核为奇数,并且输出存储在中C

import cv2
import numpy as np

A = cv2.imread('...') # Load in image here
B = (1.0/25.0)*np.ones((5,5)) # Specify kernel here
C = cv2.filter2D(A, -1, B) # Convolve

H = np.floor(np.array(B.shape)/2).astype(np.int) # Find half dims of kernel
C = C[H[0]:-H[0],H[1]:-H[1]] # Cut away unwanted information
Run Code Online (Sandbox Code Playgroud)

注意cv2.filter2D执行相关,而不是卷积。但是,如果内核是对称的(也就是说,如果您进行了转置并且等于自身),则相关性和卷积是等效的。如果不是这种情况,则在使用之前,您需要对内核执行180度旋转cv2.filter2D。您只需执行以下操作即可:

B = B[::-1,::-1]
Run Code Online (Sandbox Code Playgroud)

为了进行比较,我们可以证明上面的代码等效于use scipyconvolve2D函数。这是一个可重现的IPython会话,向我们展示了这一点:

In [41]: import cv2

In [42]: import numpy as np

In [43]: from scipy.signal import convolve2d

In [44]: A = np.reshape(np.arange(49), (7,7)).astype(np.float32)

In [45]: A
Out[45]:
array([[  0.,   1.,   2.,   3.,   4.,   5.,   6.],
       [  7.,   8.,   9.,  10.,  11.,  12.,  13.],
       [ 14.,  15.,  16.,  17.,  18.,  19.,  20.],
       [ 21.,  22.,  23.,  24.,  25.,  26.,  27.],
       [ 28.,  29.,  30.,  31.,  32.,  33.,  34.],
       [ 35.,  36.,  37.,  38.,  39.,  40.,  41.],
       [ 42.,  43.,  44.,  45.,  46.,  47.,  48.]], dtype=float32)

In [46]: B = (1.0/25.0)*np.ones((5,5), dtype=np.float32)

In [47]: B
Out[47]:
array([[ 0.04,  0.04,  0.04,  0.04,  0.04],
       [ 0.04,  0.04,  0.04,  0.04,  0.04],
       [ 0.04,  0.04,  0.04,  0.04,  0.04],
       [ 0.04,  0.04,  0.04,  0.04,  0.04],
       [ 0.04,  0.04,  0.04,  0.04,  0.04]], dtype=float32)

In [48]: C = cv2.filter2D(A, -1, B)

In [49]: H = np.floor(np.array(B.shape)/2).astype(np.int)

In [50]: C = C[H[0]:-H[0],H[1]:-H[1]]

In [51]: C
Out[51]:
array([[ 15.99999809,  16.99999809,  18.        ],
       [ 22.99999809,  24.        ,  24.99999809],
       [ 29.99999809,  30.99999809,  31.99999809]], dtype=float32)

In [52]: C2 = convolve2d(A, B, mode='valid')

In [53]: C2
Out[53]:
array([[ 15.99999905,  17.00000191,  18.00000191],
       [ 22.99999809,  23.99999809,  24.99999809],
       [ 29.99999809,  30.99999809,  31.99999809]], dtype=float32)
Run Code Online (Sandbox Code Playgroud)

这个例子很容易理解。我声明一个7 x 7的虚拟矩阵,其中值从0逐行增加到48。我还(1/25)为每个元素声明了一个5 x 5的内核,因此这实际上将实现5 x 5的平均滤波器。因此cv2.filter2D,我们scipy.signal.convolve2d仅使用和提取卷积结果的有效部分。至于精度变,C这是的输出cv2.filter2DC2其输出convolve2d都是等效的。要特别注意不仅实际内容,还要注意两个输出数组的形状。

但是,如果您希望保留原始图像的大小并用过滤后的结果替换受影响的像素,则只需复制原始图像并使用与删除替换时无效的信息相同的索引逻辑具有卷积结果的副本中的那些像素:

C_copy = A.copy()
C_copy[H[0]:-H[0],H[1]:-H[1]] = C 
Run Code Online (Sandbox Code Playgroud)