Änderungen des Python-Ergebnisses während der Berechnung von cv2.Rodrigues

19

Wenn ich renne:

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

Ich bekomme:

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

Also das Ergebnis von changes()Änderungen.

Ich verstehe nicht, warum das so ist, und die Tatsache, dass es sich nicht mehr ändert, wenn die tvec=np.zeros(3)Zeile auskommentiert wird, lässt mich das Gefühl haben, dass dies ein Fehler im System ist.

Ian Carr-de Avelon
quelle
"e-310" sind schwebende Zahlen, die sehr nahe an 0 liegen. Es sieht nach dem allgemeinen Problem bei der Darstellung von schwebenden Python-Zahlen aus, das bei jeder Speicherzuweisung variieren kann.
Aryerez
Das ist ernsthaft komisch ... sieht auch für mich wie ein Käfer aus.
Julien
1
Die Hauptsache IMO ist, dass das Definieren von tvec als Array (aber nicht als int oder string) überhaupt einen Effekt hat ... Und wenn Sie es einmal getan haben, kein Zurück mehr ... Ich vermute, tvec ist ein interner Zustand von cv2.Rodrigues, die nicht manipuliert werden sollten, aber die Schnittstelle scheint solche Manipulationen durch Nebenwirkungen zu ermöglichen ...
Julien
Das ist verwirrend. Wenn ich die Schleife abrolle, funktioniert sie, wenn ich das Ergebnis von np.zeros(3)in zwei verschiedenen Variablen speichere . Wenn ich das Ergebnis nicht speichere oder dieselbe Variable nicht zweimal verwende, wird dies nicht der Fall sein. Vielleicht kann jemand mit mehr numpy Wissen etwas Licht ins Dunkel bringen.
Faultier
1
Zu Ihrer Information, ich sehe das gleiche in Python3 unter Windows ...
Julien

Antworten:

8

Dies ist sehr wahrscheinlich ein nicht initialisiertes Array, wie es von zurückgegeben wird np.empty. Dies kann zusammen mit dem Speicherrecycling zu dem Effekt führen, den Sie sehen. Ein minimales Beispiel wäre:

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]

Beobachten Sie, wie bei der ersten Iteration yMüll und bei jeder nachfolgenden Iteration der Wert der vorherigen Iteration enthalten ist, xda ihr der zuvor freigegebene Speicher zugewiesen wurde.

Wir können leicht überprüfen, ob im ursprünglichen Beispiel auch das vorherige tvecauftaucht:

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

Wir können weiter spekulieren, dass es die eigentümliche Wahl ist rmat, die den Fehler auslöst.

Es ist wahrscheinlich ein Fehler, der überhaupt eye(4)akzeptiert wird, weil offiziell rmat3x1 1x3 oder 3x3 sein sollte. In der Tat wird eine 1D rmatohne 3 Elemente vom Python-Wrapper korrekt abgelehnt. Mein Verdacht ist, dass 2D-Regeln auf Python-Ebene nicht richtig überprüft werden. Der C-Code erkennt dann, dass die falsche Form nichts anderes tut, als einen Fehlercode zurückzugeben, auf den der Python-Code nicht prüft.

In rmat=eye(3)der Tat verschwindet die Verwendung eines Effekts:

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
quelle
Für np.emptydieses Verhalten bekannt ist, weil es Speicher nimmt Bytes , wie sie kommen, ohne vorhandene Werte zu aktualisieren. Die cv2.RodriguesFunktion soll jedoch nach strenger Berechnung einige aussagekräftige Werte zurückgeben. Darüber hinaus können die im OP dargestellten seltsamen Werte kaum als Müll betrachtet werden, da sie alle sehr nahe bei Null liegen.
Sciroccorics
1
@sciroccorics würden Sie nicht zustimmen, dass mein zweites Snippet ziemlich überzeugend ist?
Paul Panzer
Ich habe eine PR eingereicht , um die Eingabegröße zu überprüfen.
Catree
3

Auf jeden Fall ist es ein Fehler in der Rodrigues-Funktion ...

Wenn Sie das entsprechende Dokument lesen , sehen Sie möglicherweise, dass cv2.Rodrigueses zwei verschiedene Schnittstellen hat:

Eine, die die C ++ - Schnittstelle nachahmt, bei der der Rotationsvektor (und optional der Jacobi) als Referenz übergeben und von der Funktion geändert werden

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

und eine (mehr Pythonic), bei der der Rotationsvektor und der Jacobi als Tupel zurückgegeben werden

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

Wenn Sie die erste Schnittstelle verwenden, verschwindet die pb ...

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

Ergebnis:

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

BEARBEITEN nach weiterer Untersuchung:

Die Funktion ist erwartungsgemäß noch fehlerhafter : Bei Verwendung der ersten Schnittstelle werden die Parameter dstund jacobiannicht geändert, was in völligem Widerspruch zur Dokumentzeichenfolge steht:

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

Mit anderen Worten, dies erfordert eindeutig einen Fehlerbericht ...

Sciroccorics
quelle
Andere Antwort ist richtig. Das Problem kommt von np.eye(4). Das Verfahren erfordert einen Rotationsvektor (3x1 oder 1x3) oder eine Rotationsmatrix (3x3). Hier mit np.eye (4) erstellt die Funktion dst mit einer gewissen Größe. Da die Eingabeform jedoch falsch ist, führt die Methode nichts aus und lässt sie einheitlich. Außerdem verweisen Sie auf eine veraltete Version von OpenCV. Es ist besser, die Master-Version zu verwenden oder auf eine bestimmte Version zu verweisen: siehe docs.opencv.org .
Catree