规范化,同时将'dst'的值保留为空数组

时间:2019-03-19 18:12:44

标签: python numpy opencv

我正尝试规范化一个简单的numpy数组a,如下所示:

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

cv2.normalize(a)

运行此命令时,OpenCV会引发错误,提示TypeError: Required argument 'dst' (pos 2) not found。因此,我将documentation中也提到过的dst参数作为参数。这是我的做法:

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

此调用返回归一化的数组,但是b的值仍为空。为什么会这样呢?

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

b = np.copy(a)

cv2.normalize(a,b)

b中的值现在已填充标准化值。我只是想了解OpenCV的这种行为。当空白为{/ {1}}时,为什么不填充b?为什么OpenCV不会引发错误?

1 个答案:

答案 0 :(得分:2)

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

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

您会注意到dst既是函数的输入值也是返回值。这意味着您可以在函数中输入一个dst数组,并且将对其进行原地修改,您可以为此传递None或空白数组参数,当调用函数时,将创建并返回一个新数组。


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

在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]])