Python result changes during cv2.Rodrigues computation
This is very likely an uninitialized array such as returned by np.empty
. This together with memory recycling can lead to the kind of effect you are seeing. A minimal example would be:
for a in range(5): y = np.empty(3,int) x = (np.arange(3)+a)**3 print(x,y) del x# [0 1 8] [94838139529536 0 0]# [ 1 8 27] [0 1 8]# [ 8 27 64] [ 1 8 27]# [ 27 64 125] [ 8 27 64]# [ 64 125 216] [ 27 64 125]
Observe how at the first iteration y
contains garbage and at each subsequent iteration it contains the value of the previous x
because it is assigned its memory which has been freed just before.
We can easily check that in the original example it is also the previous tvec
that pops up:
def changes(): rmat=np.eye(4) tvec=np.array([4,0.0,2.5]) (rvec, jacobian)=cv2.Rodrigues(rmat) print(rvec)for i in range(3): changes() # [[4.6609787e-310]# [0.0000000e+000]# [0.0000000e+000]]# [[4. ]# [0. ]# [2.5]]# [[4. ]# [0. ]# [2.5]]
We may further speculate that it is the peculiar choice of rmat
that triggers the error.
It is probably a bug that eye(4)
is accepted at all because, officially, rmat
should be 3x1 1x3 or 3x3. Indeed, a 1D rmat
that doesn't have 3 Elements is correctly rejected by the Python wrapper. My suspicion is that 2D ´rmat`s are not properly checked at the Python level. The C code then detects the wrong shape does nothing except for returning an error code which the Python code doesn't check for.
Indeed using a rmat=eye(3)
the effect goes away:
def changes(): rmat=np.eye(3) tvec=np.array([4,0.0,2.5]) (rvec, jacobian)=cv2.Rodrigues(rmat) print(rvec)for a in range(3): changes()# [[0.]# [0.]# [0.]]# [[0.]# [0.]# [0.]]# [[0.]# [0.]# [0.]]
Definitely, it's a bug in the Rodrigues function...
If you read the corresponding doc, you may see that cv2.Rodrigues
has 2 different interfaces:
one that mimics the C++ interface, where the rotation vector (and optionaly the jacobian) are passed by reference and modified by the function
cv2.Rodrigues(src, dst[, jacobian]) --> None
and one (more Pythonic) where the rotation vector and the jacobian are returned as a tuple
cv2.Rodrigues(src) --> dst, jacobian
If you use the first interface, the pb vanishes...
import numpy as npimport cv2def changes(): rmat=np.eye(4) tvec=np.zeros(3) #(rvec, jacobian)=cv2.Rodrigues(rmat) cv2.Rodrigues(rmat, tvec) print(tvec)for i in range(2): changes()
Result:
[0. 0. 0.][0. 0. 0.]
EDIT after further investigation:
The function is even more buggy as expected: when using the first interface, parameters dst
and jacobian
are not modified, which is in total contracdiction with the docstring:
>>> help(cv2.Rodrigues)Help on built-in function Rodrigues:Rodrigues(...) Rodrigues(src[, dst[, jacobian]]) -> dst, jacobian . @brief Converts a rotation matrix to a rotation vector or vice versa. . . @param src Input rotation vector (3x1 or 1x3) or rotation matrix (3x3). . @param dst Output rotation matrix (3x3) or rotation vector (3x1 or 1x3), respectively. . @param jacobian Optional output Jacobian matrix, 3x9 or 9x3, which is a matrix of partial . derivatives of the output array components with respect to the input array components.
In other words, this clearly requires a bug report...