Ask Your Question
3

What format does cv2.solvePnP use for points in Python?

asked 2012-08-02 09:29:03 -0600

jasedit gravatar image

updated 2012-08-02 14:19:36 -0600

I'm using OpenCV 2.3.1 under Ubuntu 12.04, and trying to use the cv2.solvePnP function. I cannot seem to figure out what format the two point arguments are supposed to be in. The document states:

objectPoints – Array of object points in the object coordinate space, 3xN/Nx3 1-channel or 1xN/Nx1 3-channel, where N is the number of points. vector<point3f> can be also passed here.

imagePoints – Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, where N is the number of points. vector<point2f> can be also passed here.

I have so far tried the following inputs:

  • NumPy arrays with shape (N, 3) and (N, 2)
  • Numpy arrays with shape (N, 1, 3) and (N, 1, 2)
  • Python lists of NumPy arrays of (N,3) and (N,2)

The most typical error I get reads:

cv2.error: /build/buildd/opencv-2.3.1/modules/calib3d/src/solvepnp.cpp:52: error: (-215) npoints >= 0 && npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F)) in function solvePnP

What format are these two arguments supposed to be in? Is there something I'm missing?

EDIT:

Based on blue's answer, I've refactored such that this code snippet:

print opts.shape, ipts.shape, temp_cam.shape, dc.shape > print opts.dtype, ipts.dtype, temp_cam.dtype, dc.dtype > rcv, tcv = cv2.solvePnP(opts, ipts, temp_cam, dc)

Produces:

(1420, 3, 1) (1420, 2, 1) (3, 3) (5, 1)

float64 float64 float64 float64

OpenCV Error: Assertion failed (src.dims <= 2 && esz <= (size_t)32) in transpose, file /build/buildd/opencv-2.3.1/modules/core/src/matrix.cpp, line 1680 terminate called after throwing an instance of 'cv::Exception' what(): /build/buildd/opencv-2.3.1/modules/core/src/matrix.cpp:1680: error: (-215) src.dims <= 2 && esz <= (size_t)32 in function transpose

So the sizes seem right, and the types seem right, but I'm still getting an error.

If I use the example code in the answer in ipython, I get a valid answer. Is there some other constraint I'm not recognizing?

edit retag flag offensive close merge delete

Comments

If you run the ipython example with N=1420 does it work (it does for me)? Are you sure ipython and your application have the same PYTHONPATH? Perhaps the difference in behaviour is due to different version of cv2.

blue gravatar imageblue ( 2012-08-02 20:56:15 -0600 )edit

3 answers

Sort by » oldest newest most voted
5

answered 2012-08-02 11:36:30 -0600

blue gravatar image

This seems to work:

In [1]: import cv2

In [2]: objectPoints = np.random.random((10,3,1))

In [3]: imagePoints = np.random.random((10,2,1))

In [4]: cameraMatrix = np.eye(3)

In [5]: distCoeffs = np.zeros((5,1))

In [6]: cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs)

Out[6]:

(True, array([[ 0.15797798], [ 0.48352235], [-0.25566527]]), array([[ 0.36711979], [ 1.02124737], [ 1.83962556]]))

Image points of shape (N, 1, 2) and object points of shape (N,1,3) also works (your case number 2) for me. Perhaps you had a bad shape for distCoeffs?

edit flag offensive delete link more

Comments

This shows the correct arguments. My actual issue was in using reshape to pass an array into the solvePnP call with the appropriate shape. This causes problems in subsequent calls, unless a copy of the array is made.

jasedit gravatar imagejasedit ( 2012-08-04 14:24:11 -0600 )edit
1

answered 2015-02-27 01:55:15 -0600

bluejay gravatar image

I solved this in OpenCV 2.4.9.

cv2.solvePnP requires that your input object and image arrays are in contiguous memory (one of the things that the Mat::checkVector() function requires by default). Further, if you use the CV_P3P method, it relies on cv::undistortPoints, which requires the image points to be in a 2 channel type.

So solvePnP will error-fail with

World = array([[-0.5, -0.5,  3. ],
               [ 0.5, -0.5,  3. ],
               [ 0.5,  0.5,  3. ],
               [-0.5,  0. ,  3. ]])
keyPoints = array([[ 279.03286469,  139.80463604,    1.        ],
                     [ 465.40665724,  136.70519839,    1.        ],
                     [ 465.40665724,  325.1505936 ,    1.        ],
                     [ 279.03286469,  230.927896  ,    1.        ]])

objectPoints = World
imagePoints = keyPoints[:,:2] # <--- THIS SLICE IS A PROBLEM CAUSER!!!
cv2.solvePnP(objectPoints, imagePoints, np.eye(3), np.zeros(5))

but it will succeed, even in CV_P3P mode, with

imagePoints = np.ascontiguousarray(keyPoints[:,:2]).reshape((4,1,2)) # Now OpenCV is HAPPY!
retval, rvec, tvec = cv2.solvePnP(op, ip, intrinsic_mx, distortion_coefs, flags=cv2.CV_P3P)
edit flag offensive delete link more
2

answered 2013-04-04 16:39:58 -0600

bhollis gravatar image

updated 2013-04-04 16:40:18 -0600

This works for me:

numpy.array([(x,y,z), (x2,y2,y2)], dtype=numpy.float)

The key is the dtype=numpy.float.

edit flag offensive delete link more

Question Tools

Stats

Asked: 2012-08-02 09:29:03 -0600

Seen: 17,180 times

Last updated: Apr 04 '13