首页 > 解决方案 > cv2.Rodrigues 计算期间的 Python 结果更改

问题描述

如果我运行:

import numpy as np
import cv2

def changes():
    rmat=np.eye(4)
    tvec=np.zeros(3)
    (rvec, jacobian)=cv2.Rodrigues(rmat)
    print rvec

for i in range(2):
    changes()

我得到:

[[6.92798859e-310]
 [2.19380404e-316]
 [1.58101007e-322]]
[[0.]
 [0.]
 [0.]]

所以changes()变化的结果。

我不明白为什么会这样,如果该 tvec=np.zeros(3)行被注释掉,它就会停止变化,这让我觉得这是系统中的一个错误。

标签: pythonnumpyopencvdebuggingopencv3.0

解决方案


这很可能是一个未初始化的数组,例如由np.empty. 这与内存回收一起可以导致您看到的那种效果。一个最小的例子是:

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]

观察第一次迭代是如何y包含垃圾的,并且在每次后续迭代中它都包含前一次的值,x因为它被分配了之前已释放的内存。

我们可以很容易地检查在原始示例中它也是tvec弹出的先前示例:

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

我们可以进一步推测rmat触发错误的是特殊选择。

这可能是一个完全eye(4)被接受的错误,因为官方rmat应该是 3x1 1x3 或 3x3。rmat实际上,没有 3 个元素的 1D会被 Python 包装器正确拒绝。我怀疑 2D 'rmat`s 没有在 Python 级别正确检查。然后,C 代码检测到错误的形状,除了返回 Python 代码不检查的错误代码外,什么都不做。

确实使用rmat=eye(3)效果消失了:

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.]]

推荐阅读