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 มากดูเหมือนว่าปัญหาทั่วไปกับการแสดงตัวเลขไพ ธ อนซึ่งสามารถแตกต่างกันไปในการจัดสรรหน่วยความจำทุกครั้ง
Aryerez

นี่มันแปลก ๆ จริง ๆ ...
Julien

1
สิ่งสำคัญ IMO คือการกำหนด tvec เป็นอาร์เรย์ (แต่ไม่เหมือน int หรือ string) มีผลเลย ... และเมื่อคุณทำเสร็จแล้วจะไม่หันหลังกลับ ... ฉันเดาว่า tvec เป็นสถานะภายใน ของ cv2.Rodrigues ที่ไม่ควรดัดแปลง แต่ดูเหมือนว่าอินเตอร์เฟสจะอนุญาตให้ยุ่งเกี่ยวกับผลข้างเคียงเช่นนั้น ...
Julien

นี่คือความสับสน ถ้าฉันคลี่วงมันจะทำงานเมื่อฉันเก็บผลลัพธ์np.zeros(3)ไว้ในตัวแปรที่ต่างกันสองตัว หากฉันไม่เก็บผลลัพธ์หรือใช้ตัวแปรเดียวกันสองครั้งจะไม่เกิดขึ้น บางทีใครบางคนที่มีความรู้ numpy มากขึ้นสามารถทำให้เข้าใจผิดเกี่ยวกับเรื่องนี้
เฉื่อยชา

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ควรเป็น 3x1 1x3 หรือ 3x3 อันที่จริงแล้ว 1D rmatที่ไม่มี 3 องค์ประกอบจะถูกปฏิเสธอย่างถูกต้องโดยเครื่องห่องูหลาม ความสงสัยของฉันคือ 2D matrmat`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.]]

สำหรับnp.emptyพฤติกรรมนี้เป็นที่รู้จักกันดีเพราะใช้หน่วยความจำไบต์ตามมาโดยไม่ต้องอัพเดทค่าที่มีอยู่ แต่cv2.Rodriguesฟังก์ชันควรจะคืนค่าที่มีความหมายบางอย่างหลังจากการคำนวณที่เข้มงวด ยิ่งไปกว่านั้นค่าแปลก ๆ ที่นำเสนอใน OP นั้นแทบจะไม่ถือว่าเป็นขยะเพราะมันใกล้เคียงกับศูนย์มาก
sciroccorics

1
@sciroccorics คุณไม่เห็นด้วยไหมว่าข้อมูลโค้ดที่สองของฉันน่าสนใจใช่ไหม
Paul Panzer

ฉันส่งPRเพื่อตรวจสอบขนาดอินพุต
Catree

3

แน่นอนมันเป็นข้อผิดพลาดในฟังก์ชั่น Rodrigues ...

หากคุณอ่านเอกสารที่เกี่ยวข้องคุณอาจเห็นว่าcv2.Rodriguesมีอินเตอร์เฟซที่แตกต่างกัน 2 รายการ:

อันที่เลียนแบบอินเตอร์เฟส C ++ โดยที่เวกเตอร์การหมุน (และเป็นตัวเลือกจาโคเบียน) ถูกส่งผ่านโดยการอ้างอิงและแก้ไขโดยฟังก์ชัน

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

และอีกหนึ่ง (Pythonic เพิ่มเติม) ที่เวกเตอร์การหมุนและจาโคเบียนกลับมาเป็น tuple

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

หากคุณใช้อินเตอร์เฟสแรก 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()

ผลลัพธ์:

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

แก้ไขหลังจากทำการสอบสวนเพิ่มเติม:

ฟังก์ชั่นนี้เป็นรถบั๊กกี้มากขึ้นตามที่คาดไว้: เมื่อใช้อินเทอร์เฟซแรกพารามิเตอร์dstและjacobianไม่ได้รับการแก้ไขซึ่งอยู่ใน contracdiction ทั้งหมดด้วย 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.

กล่าวอีกนัยหนึ่งสิ่งนี้ต้องการรายงานข้อผิดพลาดอย่างชัดเจน ...


คำตอบอื่น ๆนั้นถูกต้อง np.eye(4)ปัญหาที่เกิดขึ้นมาจาก วิธีการนี้ต้องใช้เวกเตอร์การหมุน (3x1 หรือ 1x3) หรือเมทริกซ์การหมุน (3x3) ที่นี่ด้วย np.eye (4) ฟังก์ชั่นสร้าง dst ด้วยขนาดบาง แต่เนื่องจากรูปร่างอินพุตไม่ถูกต้องวิธีนี้จึงไม่ทำสิ่งใดและทิ้งไว้เป็นหน่วย นอกจากนี้คุณกำลังชี้ไปที่ OpenCV รุ่นที่ล้าสมัย มันจะดีกว่าที่จะใช้รุ่นต้นแบบหรือชี้ไปที่รุ่นที่เฉพาะเจาะจง: ดูdocs.opencv.org
Catree
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.