首页 > 解决方案 > 规范化,同时将 'dst' 的值保持为空数组

问题描述

我试图标准化一个简单的 numpy 数组a,如下所示:

a = np.ones((3,3))

cv2.normalize(a)

在运行它时,OpenCV 会抛出一个错误,说TypeError: Required argument 'dst' (pos 2) not found. 所以我把论点放在文档dst中也提到过。这是我的做法:

b = np.asarray([])
cv2.normalize(a, b)

此调用返回标准化数组,但 的值b仍为空。为什么会这样?

另一方面,如果我尝试以下操作:

b = np.copy(a)

cv2.normalize(a,b)

中的值b现在填充了标准化值。我只是想了解 OpenCV 的这种行为。为什么b空的时候不填/形状不一样a?为什么 OpenCV 不抛出错误?

标签: pythonnumpyopencv

解决方案


在第一个示例中,您需要将结果分配cv2.normalize回变量。从docs中,签名为cv2.normalize()

dst = cv.normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]])

您会注意到dst它既是函数的输入值又是返回值。这意味着您可以dst在函数中输入一个数组,并将其就地修改,或者,您可以在调用函数时为该参数传递None一个空白数组,然后将创建并返回一个新数组。


更具体地说,如果您对 C++ 不是很熟悉:在 C++ 中,您通常只返回原语(例如整数)或函数的指针。它不像 Python 那样简单,你可以返回任意数量的任何你想要的对象;例如,您必须将它们填充到容器中并返回指向该容器的指针。所以,更常见的是你直接将对象传递给函数,函数只会修改对象,而不用担心返回和所有这些废话。此外,这意味着该函数不会在幕后创建您不知道的对象。相反,您控制对象的创建和实例化,并将它们传递给函数。

在 Python 中,将可变参数传递给函数并理解它们将被修改的情况要少得多(尽管仍然可能)。

由于 OpenCV 的绑定是从 C++ 库中自动生成的,因此这些函数可以以这两种方式中的任何一种方式使用;您可以初始化一个正确大小/形状的数组,将其传入并对其进行变异(标准 C++ 方式),或者您可以传入None一个空白数组,它会改为返回输出数组(标准 Python方法)。

这实际上在整个 OpenCV 库中都很常见。如果您看到与其中一个输出相同的输入并且不需要使用它来初始化函数,则基本上总是可以发送None该参数。


我不确定如果您在那里传入完全虚假的数组,OpenCV为什么选择不抛出错误的哲学原因,尽管这种类型的问题对于这个站点来说并不是一个很好的格式。此外,错误在 OpenCV 中不是很一致,它们对函数参数检查的断言非常严格,但是如果您尝试读取不存在的图像,它们会很高兴地返回一个空指针。无论如何,对于错误形状/类型的情况,最终发生的只是参数被忽略。只有当它是正确的形状/类型时,参数才会发生变异。你可以想象类似这样的事情发生:

In [29]: a = np.eye(3, dtype=np.float64)

In [30]: b = np.eye(3, dtype=np.uint8)  # different dtype

In [31]: c = np.eye(2)  # different shape

In [32]: d = 'asdf'  # not even an array

In [33]: cv2.normalize(a, b)
Out[33]:
array([[0.57735027, 0.        , 0.        ],
       [0.        , 0.57735027, 0.        ],
       [0.        , 0.        , 0.57735027]])

In [34]: b  # not modified because different dtype
Out[34]:
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]], dtype=uint8)

In [35]: cv2.normalize(a, c)
Out[35]:
array([[0.57735027, 0.        , 0.        ],
       [0.        , 0.57735027, 0.        ],
       [0.        , 0.        , 0.57735027]])

In [36]: c  # not modified because different shape
Out[36]:
array([[1., 0.],
       [0., 1.]])

In [37]: cv2.normalize(a, d)  # error because it's not convertible to a `cv::UMat`
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-37-642f9bb78a6b> in <module>
----> 1 cv2.normalize(a, d)

TypeError: Expected cv::UMat for argument 'dst'

但是当我们有正确的 shape 和 dtype 组合时:

In [38]: e = np.empty_like(a)   # same dtype/shape as a

In [39]: cv2.normalize(a, e)
Out[39]:
array([[0.57735027, 0.        , 0.        ],
       [0.        , 0.57735027, 0.        ],
       [0.        , 0.        , 0.57735027]])

In [40]: e  # mutated
Out[40]:
array([[0.57735027, 0.        , 0.        ],
       [0.        , 0.57735027, 0.        ],
       [0.        , 0.        , 0.57735027]])

推荐阅读