Kết quả Python thay đổi trong quá trình tính toán cv2.Rodrigues


19

Nếu tôi chạy:

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

Tôi có:

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

Vì vậy, kết quả từ changes()những thay đổi.

Tôi không hiểu tại sao lại như vậy và thực tế là nó sẽ ngừng thay đổi nếu tvec=np.zeros(3)dòng được nhận xét, khiến tôi cảm thấy rằng đây là một lỗi trong hệ thống.


"E-310" là các số trôi nổi rất gần với 0. Có vẻ như vấn đề chung với biểu diễn số nổi python, có thể thay đổi trên mỗi lần cấp phát bộ nhớ.
Aryerez

Điều này thực sự kỳ lạ ... có vẻ như là một lỗi với tôi.
Julien

1
Điều chính IMO là việc xác định tvec là một mảng (nhưng không phải là int hoặc chuỗi) có ảnh hưởng gì cả ... Và một khi bạn đã thực hiện nó, không quay lại ... Tôi đoán là tvec là một trạng thái nội bộ của cv2.Rodoursues không nên bị giả mạo, nhưng giao diện dường như cho phép giả mạo như vậy bởi tác dụng phụ ...
Julien

Điều này thật khó hiểu. Nếu tôi cuộn vòng lặp, nó sẽ hoạt động khi tôi lưu trữ các kết quả của np.zeros(3)trong hai khác nhau biến. Nếu tôi không lưu trữ kết quả hoặc sử dụng cùng một biến hai lần, nó sẽ không. Có lẽ ai đó có kiến ​​thức gọn gàng hơn có thể làm sáng tỏ điều này.
lười

1
FYI, tôi thấy điều tương tự trong Python3 trên Windows ...
Julien

Câu trả lời:


8

Đây rất có thể là một mảng chưa được khởi tạo như được trả về bởi np.empty. Điều này cùng với tái chế bộ nhớ có thể dẫn đến loại hiệu ứng bạn đang thấy. Một ví dụ tối thiểu sẽ là:

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]

Quan sát làm thế nào ở lần lặp đầu tiên ychứa rác và ở mỗi lần lặp tiếp theo, nó chứa giá trị của lần lặp trước xvì nó được gán bộ nhớ của nó đã được giải phóng ngay trước đó.

Chúng ta có thể dễ dàng kiểm tra xem trong ví dụ ban đầu, nó cũng là cái trước tvecđó bật lên:

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

Chúng tôi có thể suy đoán thêm rằng đó là sự lựa chọn đặc biệt của rmatnguyên nhân gây ra lỗi.

Đây có thể là một lỗi eye(4)được chấp nhận bởi vì, chính thức, rmatnên là 3x1 1x3 hoặc 3x3. Thật vậy, 1D rmatkhông có 3 yếu tố bị từ chối chính xác bởi trình bao bọc Python. Sự nghi ngờ của tôi là 2D átrmat `không được kiểm tra chính xác ở cấp độ Python. Mã C sau đó phát hiện hình dạng sai không làm gì ngoài việc trả về mã lỗi mà mã Python không kiểm tra.

Thực sự sử dụng một rmat=eye(3)hiệu ứng biến mất:

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

Đối với np.emptyhành vi này là nổi tiếng, bởi vì nó lấy byte bộ nhớ khi chúng đến, mà không cập nhật các giá trị hiện có. Nhưng cv2.Rodrigueschức năng được cho là trả về một số giá trị có ý nghĩa, sau khi tính toán nghiêm ngặt. Hơn nữa, các giá trị lạ được trình bày trong OP khó có thể được coi là rác, vì tất cả chúng đều rất gần với không.
sciroccorics

1
@sciroccorics bạn có đồng ý rằng đoạn trích thứ hai của tôi khá hấp dẫn không?
Paul Panzer

Tôi đã gửi một PR để kiểm tra kích thước đầu vào.
Catree

3

Chắc chắn, đó là một lỗi trong chức năng Coleues ...

Nếu bạn đọc tài liệu tương ứng , bạn có thể thấy cv2.Rodriguescó 2 giao diện khác nhau:

một giao diện bắt chước giao diện C ++, trong đó vectơ xoay (và tùy chọn jacobian) được truyền bằng tham chiếu và được sửa đổi bởi hàm

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

và một (thêm Pythonic) trong đó vectơ xoay và jacobian được trả về dưới dạng một tuple

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

Nếu bạn sử dụng giao diện đầu tiên, pb sẽ biến mất ...

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

Kết quả:

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

EDIT sau khi điều tra thêm:

Chức năng thậm chí còn nhiều lỗi hơn như mong đợi: khi sử dụng giao diện, tham số đầu tiên dstjacobian không được sửa đổi, đó là hoàn toàn tránh thai với chuỗi doc:

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

Nói cách khác, điều này rõ ràng đòi hỏi một báo cáo lỗi ...


Câu trả lời khác là chính xác. Vấn đề đến từ np.eye(4). Phương pháp yêu cầu vectơ xoay (3x1 hoặc 1x3) hoặc ma trận xoay (3x3). Ở đây với np.eye (4) hàm tạo dst với một số kích thước. Nhưng vì hình dạng đầu vào là sai, phương thức không làm gì cả và để nó được đơn vị hóa. Ngoài ra, bạn đang chỉ đến một phiên bản lỗi thời của OpenCV. Tốt hơn là sử dụng phiên bản chính hoặc trỏ đến một phiên bản cụ thể: xem docs.opencv.org .
Catree
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.