5

我有一个相当于棋盘的相机。我知道点的世界 3d 位置以及相机图像上相应投影点的 2d 位置。所有的世界点都属于同一个平面。我使用solvePnP:

Matx33d camMat;
Matx41d distCoeffs;
Matx31d rvec;
Matx31d tvec;
std::vector<Point3f> objPoints;
std::vector<Point2f> imgPoints;
solvePnP(objPoints, imgPoints, camMat, distCoeffs, rvec, tvec);

然后我可以使用 projectPoints 从 3d 世界点转到 2d 图像点:

std::vector<Point2f> projPoints;
projectPoints(objPoints, rvec, tvec, camMat, distCoeffs, projPoints);

projPoints 非常接近 imgPoints。

如何使用对应于属于同一平面的 3d 世界点的屏幕点进行反向操作。我知道从一个单一的角度来看,重建 3d 位置是不可能的,但在这里我在同一个平面上,所以这确实是一个 2d 问题。我可以计算反向旋转矩阵以及反向平移向量,但是我该如何进行呢?

Matx33d rot;
Rodrigues(rvec, rot);
Matx33d camera_rotation_vector;
Rodrigues(rot.t(), camera_rotation_vector);
Matx31d camera_translation_vector = -rot.t() * tvec;
4

2 回答 2

2

假设您通过 objpoints-imgpoints 对校准您的相机。注意第一个是校准板上特征点的真实世界 3-d 坐标,第二个是每个图像中特征点的 2-d 像素位置。因此,它们都应该是具有校准板图像元素数量的列表。在遵循 Python 代码行之后,您将获得校准矩阵 mtx、每个校准板的旋转 rvecs 及其平移 tvecs。

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, np.zeros(5,'float32'),flags=cv2.CALIB_USE_INTRINSIC_GUESS ) 

现在我们可以在假设下找到任何像素的 3D 坐标。这个假设是我们需要定义一些参考点。假设我们的参考是第 0 个(第一个)校准板,其轴心点位于 0,0,校准板的长轴为 x,短轴为 y 轴,校准板的表面也显示 Z= 0 飞机。这是我们如何创建投影矩阵的方法。

# projection matrix
Lcam=mtx.dot(np.hstack((cv2.Rodrigues(rvecs[0])[0],tvecs[0])))

现在我们可以定义任何像素位置和所需的 Z 值。请注意,由于我想在参考校准板上投影 (100,100) 像素位置,因此我设置 Z=0。

px=100
py=100
Z=0
X=np.linalg.inv(np.hstack((Lcam[:,0:2],np.array([[-1*px],[-1*py],[-1]])))).dot((-Z*Lcam[:,2]-Lcam[:,3]))

现在我们有了 (px,py) 像素的 X 和 Y 坐标,它是 X[0], X[1] 。X 的最后一个元素是 lambda 因子。结果我们可以说,(px,py) 位置上的像素落在第 0 个校准板表面上的 X[0],X[1] 坐标上。

于 2019-06-24T15:19:29.863 回答
1

这个问题似乎是另一个 Stackoverflow 问题的副本,其中提问者很好地提供了解决方案。这是链接:答案在这里:从图像点计算 x,y 坐标 (3D)

于 2015-12-09T18:52:36.990 回答