Normalizing while keeping the value of 'dst' as an empty array

我是研究僧i 提交于 2021-01-29 07:55:50

问题


I was trying to normalize a simple numpy array a as follows:

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

cv2.normalize(a)

On running this, OpenCV throws an error saying TypeError: Required argument 'dst' (pos 2) not found. So I put the dst argument as also mentioned in the documentation. Here is how I did:

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

This call returns the normalized array but the value of b is still empty. Why is it so?

On the other hand, if I try the following:

b = np.copy(a)

cv2.normalize(a,b)

The values in b are now filled with normalized values. I just wanted to understand this behaviour of OpenCV. Why does it not fill b when it is empty / shape is not the same as a? Why doesn't OpenCV throw an error?


回答1:


You would need to assign the result of cv2.normalize back to a variable, in the first example. From the docs, the signature for cv2.normalize() is:

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

You'll notice that dst is both an input and return value from the function. This means that you can either input a dst array into the function, and it will be modified in-place, or, you can pass None or a blank array for that argument when calling the function, and a new array will be created and returned.


To be a little more specific, if you're not very familiar with C++: in C++, you generally only return primitives (e.g. integers) or pointers from functions. It's not as easy like Python where you can just return any number of whatever objects you want; you have to stuff them into a container and return a pointer to that container, for example. So, the more common thing is for you to pass the object to the function directly, and the function will just modify the object instead of worrying about returns and all this nonsense. Furthermore, this means that the function isn't creating objects behind the scenes that you don't know about. Instead you control object creation and instantiation, and you pass them into the function.

It is much less common (though still possible) in Python to pass mutable arguments into functions with the understanding that they will be modified.

Since the bindings for OpenCV are automatically generated from the C++ libraries, the functions have the ability to be used in either of these ways; you can initialize an array of the right size/shape, pass it in, and have it be mutated (the standard C++ way), or you can pass in None or a blank array, and it will instead return the output array (the standard Python way).

This is actually very common all throughout the OpenCV library. If you see the same input as one of the outputs and you don't need to use it to initialize the function, you can basically always send None for that argument.


I'm not sure the philosophical reason of why OpenCV chooses to not throw an error if you pass in totally bogus arrays there, though that type of question isn't really a good format for this site. Additionally, errors are not very consistent in OpenCV, where they are extremely strict on assertions for function argument checking, but will happily return a null pointer if you try and read an image that doesn't exist. Anyways, what ends up happening for the cases of the wrong shape/type is simply that the argument is ignored. The argument is only mutated if it's the correct shape/type. You can imagine the equivalent of something like this happening:

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'

But when we have the right combination of shape and 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]])


来源:https://stackoverflow.com/questions/55247508/normalizing-while-keeping-the-value-of-dst-as-an-empty-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!