Изменения результата Python во время вычисления cv2.Rodrigues


19

Если я бегу:

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)строка закомментирована, заставляет меня чувствовать, что это ошибка в системе.


«e-310» - это плавающие числа, очень близкие к 0. Это похоже на общую проблему с представлением плавающих чисел в Python, которая может варьироваться при каждом выделении памяти.
Арьерез

Это серьезно странно ... мне тоже кажется ошибкой.
Жюльен

1
Главное, IMO, это то, что определение tvec как массива (но не как int или строки) имеет эффект вообще ... И как только вы это сделаете, не будет возврата назад ... Я предполагаю, что tvec является внутренним состоянием из cv2.Rodrigues, которые не должны быть подделаны, но интерфейс, кажется, позволяет такое вмешательство побочным эффектом ...
Julien

Это смущает. Если я разверну цикл, он будет работать, когда я сохраню результат np.zeros(3)в двух разных переменных. Если я не сохраню результат или не использую одну и ту же переменную дважды, это не произойдет. Может быть, кто-то с более глубокими знаниями может пролить свет на это.
ленивец

1
К вашему сведению, я вижу то же самое в Python3 на Windows ...
Julien

Ответы:


8

Скорее всего, это неинициализированный массив, такой как возвращаемый 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должна быть 3х1, 1х3 или 3х3. Действительно, 1D rmat, у которого нет 3 элементов, корректно отклоняется оболочкой Python. Я подозреваю, что 2D-карты не проверены должным образом на уровне 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.]]

Для np.emptyэтого поведение хорошо известно, поскольку она занимает память байт , как они приходят, не обновляя существующие значения. Но cv2.Rodriguesфункция должна возвращать некоторые значимые значения после тщательного вычисления. Более того, странные значения, представленные в ОП, вряд ли можно считать мусором, поскольку все они очень близки к нулю.
sciroccorics

1
@sciroccorics ты не согласен, что мой второй фрагмент довольно убедительный?
Пол Панцер

Я представил PR, чтобы проверить размер ввода.
Catree

3

Определенно, это ошибка в функции Родригеса ...

Если вы прочитаете соответствующий документ , вы увидите, что он cv2.Rodriguesимеет 2 разных интерфейса:

тот, который имитирует интерфейс C ++, где вектор вращения (и, возможно, якобиан) передается по ссылке и изменяется функцией

cv2.Rodrigues(src, dst[, jacobian]) --> None

и один (более Pythonic), где вектор вращения и якобиан возвращаются как кортеж

cv2.Rodrigues(src) --> dst, jacobian

Если вы используете первый интерфейс, пб исчезает ...

import numpy as np
import cv2

def 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()

Результат:

[0. 0. 0.]
[0. 0. 0.]

РЕДАКТИРОВАТЬ после дальнейшего расследования:

Функция еще более глючная , как и ожидалось: при использовании первого интерфейса, параметры dstи jacobianне изменяются, что в общем contracdiction с строку документации:

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

Другими словами, это явно требует сообщения об ошибке ...


Другой ответ правильный. Проблема исходит от np.eye(4). Метод требует (3x1 или 1x3) вектора вращения или (3x3) матрицы вращения. Здесь с помощью np.eye (4) функция создает dst с некоторым размером. Но поскольку форма ввода неверна, метод ничего не делает и оставляет его унифицированным. Кроме того, вы указываете на устаревшую версию OpenCV. Лучше использовать основную версию или указать конкретную версию: см. Docs.opencv.org .
Catree
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.