Cv2 sırasında Python sonucu değişir.


19

Eğer koşarsam:

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

Alırım:

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

Yani sonucu changes() değişikliklerin .

Bunun neden olduğunu ve tvec=np.zeros(3)satır yorumlanırsa değişmeyi bıraktığını anlamıyorum , bunun sistemdeki bir hata olduğunu hissettiriyor.


"e-310", 0'a çok yakın kayan sayılardır. Her bellek tahsisinde değişebilen python kayan sayı gösterimi ile ilgili genel bir sorun gibi görünüyor.
Aryerez

Bu çok garip ... benim için de bir böcek gibi görünüyor.
Julien

1
IMO'nun en önemli yanı, tvec'i bir dizi olarak tanımlamak (ancak int veya dize olarak değil) bir etkiye sahiptir ... Ve bir kez yaptıktan sonra geri dönüş yok ... Tahminim tvec dahili bir durumdur Kurcalanmaması gereken rodrigues, ancak arayüz yan etki tarafından bu tür kurcalamaya izin veriyor gibi görünüyor ...
Julien

Bu kafa karıştırıyor. Ben döngü göz önüne sermek ben sonucunu depolamak zaman, işe yarayacak np.zeros(3)içinde iki farklı değişkenler. Sonucu saklamıyorsam ya da aynı değişkeni iki kez kullanmam, olmayacak. Belki daha fazla bilgi sahibi olan biri buna biraz ışık tutabilir.
tembellik

1
FYI, Windows'da Python3'te de aynı şeyi görüyorum ...
Julien

Yanıtlar:


8

Bu, büyük olasılıkla döndürülen gibi başlatılmamış bir dizidir np.empty. Bu, bellek geri dönüşümü ile birlikte gördüğünüz etki türüne yol açabilir. Minimal bir örnek:

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]

İlk yinelemede nasıl yçöp içerdiğini ve sonraki her yinelemede öncekinin değerini nasıl içerdiğini gözlemleyin , xçünkü daha önce serbest bırakılmış belleğine atandı.

Orijinal örnekte ortaya çıkan bir önceki örnek olup olmadığını kolayca kontrol edebiliriz 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]]

Ayrıca rmat, hatayı tetikleyen şeyin kendine özgü bir seçim olduğunu düşünebiliriz .

Muhtemelen eye(4)kabul edilen bir hatadır çünkü resmi rmatolarak 3x1 1x3 veya 3x3 olmalıdır. Gerçekten de, 1Drmat 3 Öğesi olmayan , Python sarıcı tarafından doğru bir şekilde reddedilir. Benim şüphem 2D ´rmat`ların Python düzeyinde düzgün kontrol edilmemesidir. C kodu daha sonra yanlış şeklin Python kodunun kontrol etmediği bir hata kodu döndürmek dışında hiçbir şey yapmadığını algılar.

Aslında bir rmat=eye(3)efekt kullanmak ortadan kalkar:

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

İçin np.emptybu davranış iyi bilinmektedir hafızayı alır çünkü onlar geldikleri gibi, varolan değerleri güncellemeden, bayt. Ancak cv2.Rodriguesfonksiyonun, sıkı hesaplamadan sonra bazı anlamlı değerler döndürmesi gerekiyor. Dahası, OP'de sunulan garip değerlerin hepsi sıfıra çok yakın olduğu için çöp olarak kabul edilemez.
sciroccorics

1
@sciroccorics ikinci pasajımın oldukça çekici olduğunu kabul etmiyor musunuz?
Paul Panzer

Giriş boyutunu kontrol etmek için bir PR gönderdim .
Catree

3

Kesinlikle, Rodrigues fonksiyonunda bir hata ...

İlgili dokümanı okursanız, cv2.Rodriguesbunun 2 farklı arayüzü olduğunu görebilirsiniz :

C ++ arayüzünü taklit eden, burada dönme vektörü (ve isteğe bağlı olarak jacobian) referans ile geçirilir ve fonksiyon tarafından değiştirilir

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

ve bir (daha fazla Pythonic) burada dönme vektörü ve jacobian bir demet olarak döndürülür

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

İlk arayüzü kullanırsanız, pb yok olur ...

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

Sonuç:

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

Daha fazla araştırmadan sonra DÜZENLE:

İşlev beklendiği gibi daha da hatalıdır: ilk arayüzü kullanırken, parametreler dstve jacobiandeğiştirilmemiştir, bu da docstring ile tamamen kasılıdır:

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

Başka bir deyişle, bu açıkça bir hata raporu gerektirir ...


Diğer cevap doğrudur. Sorun geliyor np.eye(4). Yöntem, (3x1 veya 1x3) rotasyon vektörü veya (3x3) rotasyon matrisi gerektirir. Burada np.eye (4) ile fonksiyon bazı boyutlarda dst oluşturur. Ancak giriş şekli yanlış olduğundan, yöntem hiçbir şey yapmaz ve birimize bırakır. Ayrıca, eski bir OpenCV sürümüne işaret ediyorsunuz. Ana sürümü kullanmak veya belirli bir sürüme işaret etmek daha iyidir: bkz. Docs.opencv.org .
Catree
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.