我正在尝试使用立体声相机获取3D坐标。
第一种方法是直接使用此公式进行计算。
第二种方法是在opencv中使用reprojectImageTo3D。
但是我不知道这种方法的原理。
结果不是以毫米为单位,因此很难匹配大小。
请告诉我两种方法之间的区别。
(这些代码中的第一个是在匹配后将点要素转换为3D坐标。)
(第二个代码是使用SGBM计算整个立体图像的视差,并使用reprojectImageTo3D计算点特征的3d坐标。)
*第一种方法
cv::Mat depth(m_input.m_leftImg.size(), CV_32FC3, cv::Scalar::all(0));
int size = feOutput.m_leftKp.size();
for (int i = 0; i < size; i++)
{
cv::Point pt = cv::Point((int)(feOutput.m_leftKp.at(i).pt.x + 0.5f), (int)(feOutput.m_leftKp.at(i).pt.y + 0.5f));
depth.at<cv::Vec3f>(pt)[2] = fX * baseLine / (feOutput.m_leftKp.at(i).pt.x - feOutput.m_rightKp.at(i).pt.x); // Z
depth.at<cv::Vec3f>(pt)[0] = (feOutput.m_leftKp.at(i).pt.x - cX) * depth.at<cv::Vec3f>(pt)[2] / fX; // X
depth.at<cv::Vec3f>(pt)[1] = (feOutput.m_leftKp.at(i).pt.y - cY) * depth.at<cv::Vec3f>(pt)[2] / fY; // Y
}
depth /= 1000.f; //milli-meter to meter
*第二种方法
cv::Mat disparity16S(m_input.m_leftImg.size(), CV_16S);
sgbm->compute(m_input.m_leftImg, m_input.m_rightImg, disparity16S);
cv::Mat xyz;
cv::Matx44d Q = cv::Matx44d(
1.0, 0.0, 0.0, -cX,
0.0, 1.0, 0.0, -cY,
0.0, 0.0, 0.0, fX,
0.0, 0.0, -1.0 / baseLine, 0/*(CX - CX) / baseLine*/
);
cv::reprojectImageTo3D(disparity16S, xyz, Q, true);
cv::Mat pointXYZ(xyz.size(), xyz.type(), cv::Scalar::all(0));
for (int i = 0; i < size; i++)
{
cv::Point pt = cv::Point((int)(feOutput.m_leftKp.at(i).pt.x + 0.5f), (int)(feOutput.m_leftKp.at(i).pt.y + 0.5f));
pointXYZ.at<cv::Vec3f>(pt) = xyz.at<cv::Vec3f>(pt) / 1000.f;
}
添加+
粉色是reprojectImageTo3D方法的大小,缩放为1/100,黄色是第一种方法的1/1000(毫米2米)。
如果两种方法相同,为什么规模不同?
最佳答案
理论上没有什么区别,只是方法上没有区别。
您可以使用sgbm opencv方法(不执行任何匹配但可以解决最小化问题)来计算单个匹配点(您的第一种方法)或图像中每个像素的视差。
一旦有了视差D,就可以从三角剖分中获取深度Z的第一个公式。这应该是与引用图像平面的“距离”(通常是:左摄像机)。
z = f*b/d
一旦有了Z,就知道投影方程式说明了主摄像机的状态(伪代码)
f, 0 , cX, 0
K = 0 , f, cY, 0
0 , 0, 1, 0
[x y 1] = 1/Z * K * [X Y Z 1]
你可以扭转。
[X Y Z 1] = inv(K)* [Z*x Z*y Z] /*Z is known from disparity */
发现您的x,y就像第一张图片的第一列所示。
这些在主(左)相机引用系统中,但是如果您想在右相机中使用已发布的图像,请进行2个假设
b is all along x
the two camera planes are perfectly parallel
通常,对于其他摄像机,您假设b是已知 vector 。这两个引用系统之间可能会发生旋转,因此还必须定义R矩阵。我认为所有这些情况都是由不同的Q矩阵表示的(从立体摄像机校准中获取,例如
stereoRectify
)。cv::reprojectImageTo3D
只是“身份验证方法”。他需要相机参数和连续的视差图。它可以处理奇异选择点的差异。