解决 cv2::filter2D() 中抑制负值的问题
Resolve supression of negative values in cv2::filter2D()
我正在使用卷积来计算图像中的梯度。为此,我使用了在 Python 中实现的 OpenCV 的 cv2.filter2D()
函数。我还编写了一个(缓慢的)实现,它简单地遍历所有像素。输入图像 img
是使用 cv2.cvtColor()
从 RGB 转换为 YUV 并使用 OpenCV 函数 cv2.split()
分割的 .JPG 图像。我的代码摘要(只计算一个颜色通道)是:
imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
clr1, clr2, cl3 = cv2.split(imgYUV)
(iH,iW) = clr1.shape[:2]
pad=1
paddedImg = cv2.copyMakeBorder(clr1,pad,pad,pad,pad,cv2.BORDER_REPLICATE)
outputMyImplementation = np.zeros((iH,iW), dtype='int32')
kernel = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
for y in np.arange(pad, iH+pad):
for x in np.arange(pad, iW+pad):
roi = paddedImg[y-pad:y+pad+1, x-pad:x+pad+1]
k = (roi*kernel).sum()
outputMyImplementation[y-pad,x-pad] = k
outputCV2 = cv2.filter2D(clr1,-1,kernel)
但是,filter2D 似乎 trim 来自输入图像的负值:
- 使用 filter2D() 的最大值:66
- 使用我的实现的最大值():66
- 使用 filter2D() 的最小值:0
- 使用我的实现的最小值():-146
使用翻转内核kernel = np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
结果是:
- 使用 filter2D() 的最大值:146
- 使用我的实现的最大值():146
- 使用 filter2D() 的最小值:0
- 使用我的实现的最小值():-66
很明显,负值被抑制了。 cv2.filter2D()
中的所有默认设置对我来说都很好,这就是我使用最少参数的原因。该文档未提及此行为,并且多个论坛建议不应抑制负值。有人知道为什么会发生这种情况,以及如何解决?我有一个解决方法,通过总结内核的结果和它的翻转变体,但是对于一个简单的问题,这似乎是一个糟糕的解决方案。
版本信息:
openCV
版本 4.4.0.44
numpy
版本 1.19.2
python
版本 3.8.5
解决办法在于输出的深度。通过将其设置为 -1,输入图像的深度用于输出。由于输入图像很可能是uchar,它饱和为0。饱和为零的问题可以通过将输出类型设置为cv2.[=21=来解决] 使用:
outputCV2 = cv2.filter2D(img, cv2.CV_64F, kernel)
要获得与 outputMyImplementation 完全相同的答案,必须将内核翻转 180 度。当查看绝对值时,这不是必需的,代码可以按提供的方式使用。
我正在使用卷积来计算图像中的梯度。为此,我使用了在 Python 中实现的 OpenCV 的 cv2.filter2D()
函数。我还编写了一个(缓慢的)实现,它简单地遍历所有像素。输入图像 img
是使用 cv2.cvtColor()
从 RGB 转换为 YUV 并使用 OpenCV 函数 cv2.split()
分割的 .JPG 图像。我的代码摘要(只计算一个颜色通道)是:
imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
clr1, clr2, cl3 = cv2.split(imgYUV)
(iH,iW) = clr1.shape[:2]
pad=1
paddedImg = cv2.copyMakeBorder(clr1,pad,pad,pad,pad,cv2.BORDER_REPLICATE)
outputMyImplementation = np.zeros((iH,iW), dtype='int32')
kernel = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
for y in np.arange(pad, iH+pad):
for x in np.arange(pad, iW+pad):
roi = paddedImg[y-pad:y+pad+1, x-pad:x+pad+1]
k = (roi*kernel).sum()
outputMyImplementation[y-pad,x-pad] = k
outputCV2 = cv2.filter2D(clr1,-1,kernel)
但是,filter2D 似乎 trim 来自输入图像的负值:
- 使用 filter2D() 的最大值:66
- 使用我的实现的最大值():66
- 使用 filter2D() 的最小值:0
- 使用我的实现的最小值():-146
使用翻转内核kernel = np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
结果是:
- 使用 filter2D() 的最大值:146
- 使用我的实现的最大值():146
- 使用 filter2D() 的最小值:0
- 使用我的实现的最小值():-66
很明显,负值被抑制了。 cv2.filter2D()
中的所有默认设置对我来说都很好,这就是我使用最少参数的原因。该文档未提及此行为,并且多个论坛建议不应抑制负值。有人知道为什么会发生这种情况,以及如何解决?我有一个解决方法,通过总结内核的结果和它的翻转变体,但是对于一个简单的问题,这似乎是一个糟糕的解决方案。
版本信息:
openCV
版本 4.4.0.44numpy
版本 1.19.2python
版本 3.8.5
解决办法在于输出的深度。通过将其设置为 -1,输入图像的深度用于输出。由于输入图像很可能是uchar,它饱和为0。饱和为零的问题可以通过将输出类型设置为cv2.[=21=来解决] 使用:
outputCV2 = cv2.filter2D(img, cv2.CV_64F, kernel)
要获得与 outputMyImplementation 完全相同的答案,必须将内核翻转 180 度。当查看绝对值时,这不是必需的,代码可以按提供的方式使用。