OpenCV projectPoints 的逆向
Reverse of OpenCV projectPoints
我有一个面向相当于棋盘的相机。我知道点的世界 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;
这个问题似乎与另一个 Whosebug 问题重复,提问者在其中提供了很好的解决方案。这是 link:答案在这里:Computing x,y coordinate (3D) from image point
假设您通过 objpoints-imgpoints 对校准相机。注意第一个是校准板上特征点的真实世界三维坐标,第二个是每个图像中特征点的二维像素位置。所以它们都应该是包含校准板图像元素数量的列表。在 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-axis,校准板的表面也显示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] 坐标上。
我有一个面向相当于棋盘的相机。我知道点的世界 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;
这个问题似乎与另一个 Whosebug 问题重复,提问者在其中提供了很好的解决方案。这是 link:答案在这里:Computing x,y coordinate (3D) from image point
假设您通过 objpoints-imgpoints 对校准相机。注意第一个是校准板上特征点的真实世界三维坐标,第二个是每个图像中特征点的二维像素位置。所以它们都应该是包含校准板图像元素数量的列表。在 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-axis,校准板的表面也显示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] 坐标上。