Perubahan hasil python selama perhitungan cv2.Rodrigues

19

Jika saya menjalankan:

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

Saya mendapat:

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

Jadi hasil dari changes()perubahan.

Saya tidak mengerti mengapa itu, dan fakta bahwa itu berhenti berubah jika tvec=np.zeros(3)garis dikomentari, membuat saya merasa bahwa ini adalah bug dalam sistem.

Ian Carr-de Avelon
sumber
"e-310" adalah angka mengambang yang sangat dekat dengan 0. Sepertinya masalah umum dengan representasi angka mengambang python, yang dapat bervariasi pada setiap alokasi memori.
Aryerez
Ini benar-benar aneh ... terlihat seperti bug bagi saya juga.
Julien
1
Hal utama IMO adalah mendefinisikan tvec sebagai sebuah array (tetapi bukan sebagai int atau string) memiliki efek sama sekali ... Dan begitu Anda selesai melakukannya, tidak ada jalan untuk kembali ... Dugaan saya adalah tvec adalah keadaan internal dari cv2.Rodrigues yang tidak boleh dirusak, namun antarmuka tampaknya memungkinkan perusakan seperti efek samping ...
Julien
Ini membingungkan. Jika saya membuka gulungannya, itu akan berfungsi ketika saya menyimpan hasil np.zeros(3)dalam dua variabel yang berbeda . Jika saya tidak menyimpan hasilnya atau menggunakan variabel yang sama dua kali, itu tidak akan. Mungkin seseorang dengan pengetahuan lebih numpy dapat menjelaskan ini.
sloth
1
FYI, saya melihat hal yang sama di Python3 pada Windows ...
Julien

Jawaban:

8

Kemungkinan besar ini adalah array yang belum diinisialisasi seperti yang dikembalikan oleh np.empty. Ini bersama dengan daur ulang memori dapat menyebabkan jenis efek yang Anda lihat. Contoh minimal adalah:

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]

Amati bagaimana pada iterasi pertama yberisi sampah dan pada setiap iterasi berikutnya ia berisi nilai sebelumnya xkarena diberi memori yang telah dibebaskan sebelumnya.

Kita dapat dengan mudah memeriksa bahwa dalam contoh asli juga yang sebelumnya tvecmuncul:

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

Kami lebih lanjut berspekulasi bahwa itu adalah pilihan aneh rmatyang memicu kesalahan.

Mungkin bug yang eye(4)diterima sama sekali karena, secara resmi, rmatharus 3x1 1x3 atau 3x3. Memang, 1D rmatyang tidak memiliki 3 Elemen ditolak dengan benar oleh pembungkus Python. Kecurigaan saya adalah bahwa 2D ´rmat`s tidak diperiksa dengan benar di tingkat Python. Kode C kemudian mendeteksi bentuk yang salah tidak melakukan apa pun kecuali mengembalikan kode kesalahan yang tidak diperiksa oleh kode Python.

Memang menggunakan rmat=eye(3)efeknya hilang:

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.]]
Paul Panzer
sumber
Untuk np.emptyperilaku ini dikenal, karena dibutuhkan byte memori saat mereka datang, tanpa memperbarui nilai yang ada. Tetapi cv2.Rodriguesfungsi ini seharusnya mengembalikan beberapa nilai yang berarti, setelah perhitungan yang ketat. Selain itu, nilai-nilai aneh yang disajikan dalam OP hampir tidak dapat dianggap sebagai sampah, karena semuanya hampir nol.
sciroccorics
1
@sciroccorics tidakkah Anda setuju bahwa cuplikan kedua saya cukup menarik?
Paul Panzer
Saya telah mengirimkan PR untuk memeriksa ukuran input.
Catree
3

Jelas, ini adalah bug dalam fungsi Rodrigues ...

Jika Anda membaca dokumen terkait , Anda mungkin melihat bahwa cv2.Rodriguesmemiliki 2 antarmuka berbeda:

yang meniru antarmuka C ++, di mana vektor rotasi (dan opsional oleh jacobian) dilewatkan dengan referensi dan dimodifikasi oleh fungsi

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

dan satu (lebih Pythonic) di mana vektor rotasi dan jacobian dikembalikan sebagai tupel

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

Jika Anda menggunakan antarmuka pertama, pb menghilang ...

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

Hasil:

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

EDIT setelah penyelidikan lebih lanjut:

Fungsi ini bahkan lebih buggy seperti yang diharapkan: ketika menggunakan antarmuka pertama, parameter dstdan jacobiantidak dimodifikasi, yang merupakan kontras total dengan 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.

Dengan kata lain, ini jelas membutuhkan laporan bug ...

sciroccorics
sumber
Jawaban lain benar. Masalahnya berasal np.eye(4). Metode ini membutuhkan vektor rotasi (3x1 atau 1x3) atau (3x3) matriks rotasi. Di sini dengan np.eye (4) fungsi menciptakan dst dengan beberapa ukuran. Tetapi karena bentuk input salah, metode tidak melakukan apa-apa dan membiarkannya disatukan. Juga, Anda menunjuk ke versi OpenCV yang sudah usang. Lebih baik menggunakan versi master atau menunjuk ke versi tertentu: lihat docs.opencv.org .
Catree