【发布时间】:2019-12-21 02:31:40
【问题描述】:
同样根据this documentation of opencv、this link和this link:
C++:
void fastNlMeansDenoising(InputArray src, OutputArray dst, float h=3, int templateWindowSize=7, int searchWindowSize=21 )
Python:
cv2.fastNlMeansDenoising(src[, dst[, h[, templateWindowSize[, searchWindowSize]]]]) → dst
参数(简要)如下:
-
src - 输入图像。
-
dst - 输出与 src 大小和类型相同的图像。
-
templateWindowSize – 模板补丁的大小(以像素为单位)。应该是奇怪的。
-
searchWindowSize – 以像素为单位的窗口大小。应该是奇怪的。
-
h - 调节过滤强度的参数。
据我所知,在 Python 中,我们可以将 dst/output 变量从方法中取出:dst = cv2.method(input, param1, param2, ..., paramx)。而且我们不需要在方法中放置任何东西(即我们不需要这样做:dst = cv2.method(input, None, param1, param2, ..., paramx).
虽然这适用于不同的 OpenCV 方法,但不适用于 fastNlMeansDenoising。
以下代码将澄清我的问题:
import cv2
import numpy as np
def thresh(filename):
img = cv2.imread(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#without adding None instead of dst
test_1 = cv2.fastNlMeansDenoising(gray, 31, 7, 21)
cv2.imwrite('test_1.jpg', test_1)
# Adding None instead of dst
test_2 = cv2.fastNlMeansDenoising(gray, None, 31, 7, 21)
cv2.imwrite('test_2.jpg', test_2)
# putting dst inside the method
test_3 = np.empty(gray.shape, np.uint8)
cv2.fastNlMeansDenoising(gray, test_3, 31, 7, 21)
cv2.imwrite('test_3.jpg', test_3)
# Adding the input params
test_4 = cv2.fastNlMeansDenoising(gray, h=31, templateWindowSize=7,
searchWindowSize=21)
cv2.imwrite('test_4.jpg', test_4)
blur = cv2.bilateralFilter(gray, 31, 7, 21)
cv2.imwrite('blur.jpg', blur)
blur_ = cv2.bilateralFilter(gray, 31, 7, 21, None)
cv2.imwrite('blur_.jpg', blur_)
blur__ = np.empty(gray.shape, np.uint8)
cv2.bilateralFilter(gray, 31, 7, 21, blur__)
cv2.imwrite('blur__.jpg', blur__)
thresh('test.png')
这是输入图像:
如果您运行代码,您会注意到,test_2.jpg、test_3.jpg 和 test_4.jpg 是相似的。而test_1.jpg和gray一样(好像test_1没有收到fastNlMeansDenoising的输出)。
但是bilateralFilter 的情况并非如此:blur.jpg、blur_.jpg 和 blur__.jpg 都是相同的,尽管我重复了与fastNlMeansDenoising 相同的过程。
对此有什么解释吗?为什么要在fastNlMeansDenoising参数中添加None?
【问题讨论】:
-
在
bilateralFilter中,dst是第五个参数(第一个是可选的)。您使用 4 个参数调用它(所以dst是第五个,可选获取默认值,一切都很好),或者使用 5 个参数(再次确定,因为你没有混淆它们)。因此,它的行为方式相同,但由于dst在参数列表中的位置更靠后,因此混淆的可能性较小。 -
至于为什么混合不会导致显式错误 - Python 绑定以某种神秘的方式工作(特别是对于输出参数,重载函数会增加一些复杂性)。在我能够正确解释在这种特殊情况下发生了什么之前,我需要一些时间来刷新我的记忆。
-
当 C++ 参数为 Input/OutputArray 时,python 函数将接受任何 python 对象。然后它尝试将convert it 转换为
cv::Mat。 (如果失败,它会尝试转换为UMat。如果失败,并且存在重载,它会尝试以相同的方式解决它们。如果没有匹配项,则会出现错误。)现在,由于 C++ API 允许标量用于一些需要输入/输出数组的操作,转换函数也允许标量。例如,一个整数将变成一个 4x1 float64 mat,其值为.. -
在第一行,其余为零。单浮子也是一样。元组(数字)成为单列垫,其行数与元组中的元素一样多,同样是 float64。最后是数组,但我们不要讨论这个。因此,调用实际 C++ 函数之前的一切都正常。接下来是 C++ API 的一个特性。当给定的输出
cv::Mat具有不正确的形状或数据类型时,它会自动重新分配以满足要求。 -
我认为(尽管现在我有一些疑问,让我检查一下)......这种行为对 Python 有轻微的副作用。假设在
cv2.fastNlMeansDenoising(gray, test_3, 31, 7, 21)中,test_3numpy 数组的形状或类型错误。在这种情况下,函数可以正常运行,但由于新分配的Mat不再引用底层 numpy 缓冲区,test_3将保持不变。而且由于您没有捕获返回值,因此您会丢失实际结果。 |更新:检查过,是的,就是这样。
标签: python opencv parameters