solvePnP object_points / image_points形状?

时间:2017-10-02 21:40:44

标签: python opencv numpy

我正在尝试使用以下参数调用solvePnP。

apriltag_object_points = np.array([(-1, -1, 0), (-1, 1, 0), (1, 1, 0), (1, -1, 0)], dtype=np.float)

camera_matrix_left = np.eye(3)

dist_left = np.zeros((5, 1))

image_points = np.array(detection.position, dtype=np.float)

cv2.solvePnPRansac(apriltag_object_points, image_points, camera_matrix_left, dist_left)

但是,我收到以下错误:

OpenCV Error: Assertion failed (CV_IS_MAT(_src) && CV_IS_MAT(_dst) && (_src->rows == 1 || _src->cols == 1) && (_dst->rows == 1 || _dst->cols == 1) && _src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 && (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) && (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2)) in cvUndistortPoints, file /Users/travis/miniconda3/conda-bld/opencv_1506476120161/work/opencv-3.3.0/modules/imgproc/src/undistort.cpp, line 312
Traceback (most recent call last):
  File "/Users/me/Documents/Code/project/file.py", line 139, in <module>
    ret = cv2.solvePnPRansac(apriltag_object_points, image_points, camera_matrix_left, dist_left)
cv2.error: /Users/travis/miniconda3/conda-bld/opencv_1506476120161/work/opencv-3.3.0/modules/imgproc/src/undistort.cpp:312: error: (-215) CV_IS_MAT(_src) && CV_IS_MAT(_dst) && (_src->rows == 1 || _src->cols == 1) && (_dst->rows == 1 || _dst->cols == 1) && _src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 && (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) && (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2) in function cvUndistortPoints

看起来我的论点的形状有问题,但它们看起来很好......

apriltag_object_points.shape == (4, 3)
image_points.shape == (4, 2)

图像点必须是同质的吗?我是否必须hstack 1的{​​{1}}的列向量?{/ p>

1 个答案:

答案 0 :(得分:2)

这个函数的文档只是错误,因为它是用Python实现的。 solvePnP()solvePnPRansac()的文档均声明:

  

参数:

     

objectPoints - 对象坐标空间中的对象点数组,3xN / Nx3 1通道或1xN / Nx1 3通道,其中N是点数。 vector<Point3f>也可以在这里传递。

     

imagePoints - 相应图像点的阵列,2xN / Nx2 1通道或1xN / Nx1 2通道,其中N是点数。 vector<Point2f>也可以在这里传递。

所以你认为你很好地使用(N,3)和(N,2)数组作为你的输入。但是,错误代码另有说明。让我们分解一下:

  

CV_IS_MAT(_src)&amp;&amp; CV_IS_MAT(_dst)&amp;&amp; (_src-&gt; rows == 1 || _src-&gt; cols == 1)&amp;&amp; (_dst-&gt; rows == 1 || _dst-&gt; cols == 1)&amp;&amp; _src-&gt; cols + _src-&gt; rows - 1 == _dst-&gt; rows + _dst-&gt; cols - 1&amp;&amp; (CV_MAT_TYPE(_src-&gt; type)== CV_32FC2 || CV_MAT_TYPE(_src-&gt; type)== CV_64FC2)&amp;&amp; (CV_MAT_TYPE(_dst-&gt; type)== CV_32FC2 || CV_MAT_TYPE(_dst-&gt; type)== CV_64FC2)

好吧,他们的阵列很小,所以我们可能会放弃前两个。但接下来的检查中我们看到了一些有趣的东西:

  

(_ src-&gt; rows == 1 || _src-&gt; cols == 1)&amp;&amp; (_dst-&gt; rows == 1 || _dst-&gt; cols == 1)

检查srcdst中只有一行或一列。换句话说,它严格按照它在文档中声明的第二个版本来期待您的积分;它想要一个多通道点阵。这意味着第一个坐标位于矩阵的一个通道上,第二个坐标位于下一个通道中,等等。

因此,如果我们只是将您的点重塑为多通道数组:

>>> apriltag_object_points = apriltag_object_points.reshape(4,1,3)
>>> image_points = image_points.reshape(4,1,2)
>>> it_works, rvec, tvec, inliers = cv2.solvePnPRansac(apriltag_object_points, image_points, camera_matrix_left, dist_left)
>>> it_works
True

有效!

未来的专业提示:在OpenCV 允许点数为(npoints, ncoords)格式的每个函数中,它还以(npoints, 1, ncoords)格式AFAIK接受它们。但是,某些函数使用后一种格式。因此,如果您在OpenCV中使用Python中的点坐标,那么最好假设您的点应该在多通道数组中,其中通道数是坐标轴的数量。