我有一个用校准的立体摄像机对和opencv创建的视差图像。看起来不错,我的校准数据也不错。
我需要计算一个像素的真实距离。
从关于stackoverflow的其他问题来看,我认为该方法是:
depth = baseline * focal / disparity
使用功能:
setMouseCallback("disparity", onMouse, &disp);
static void onMouse(int event, int x, int y, int flags, void* param)
{
cv::Mat &xyz = *((cv::Mat*)param); //cast and deref the param
if (event == cv::EVENT_LBUTTONDOWN)
{
unsigned int val = xyz.at<uchar>(y, x);
double depth = (camera_matrixL.at<float>(0, 0)*T.at<float>(0, 0)) / val;
cout << "x= " << x << " y= " << y << " val= " << val << " distance: " << depth<< endl;
}
}
我单击一个测得距立体相机3米的点。 我得到的是:
val = 31距离:0.590693
深度垫的值在0到255之间,深度垫的类型为0
或CV_8UC1
。
立体声基准为0.0643654
(以米为单位)。
焦距为284.493
我也尝试过: (来自OpenCV - compute real distance from disparity map)
float fMaxDistance = static_cast<float>((1. / T.at<float>(0, 0) * camera_matrixL.at<float>(0, 0)));
//outputDisparityValue is single 16-bit value from disparityMap
float fDisparity = val / (float)cv::StereoMatcher::DISP_SCALE;
float fDistance = fMaxDistance / fDisparity;
这给了我val= 31 distance: 2281.27
的距离(更接近真相,如果我们以毫米为单位)
但是仍然不正确。
以下哪种方法是正确的?而且我要去哪里错了?
编辑:基于一个答案,我正在尝试:
`std :: vector pointcloud;
float fx = 284.492615;
float fy = 285.683197;
float cx = 424;// 425.807709;
float cy = 400;// 395.494293;
cv::Mat Q = cv::Mat(4,4, CV_32F);
Q.at<float>(0, 0) = 1.0;
Q.at<float>(0, 1) = 0.0;
Q.at<float>(0, 2) = 0.0;
Q.at<float>(0, 3) = -cx; //cx
Q.at<float>(1, 0) = 0.0;
Q.at<float>(1, 1) = 1.0;
Q.at<float>(1, 2) = 0.0;
Q.at<float>(1, 3) = -cy; //cy
Q.at<float>(2, 0) = 0.0;
Q.at<float>(2, 1) = 0.0;
Q.at<float>(2, 2) = 0.0;
Q.at<float>(2, 3) = -fx; //Focal
Q.at<float>(3, 0) = 0.0;
Q.at<float>(3, 1) = 0.0;
Q.at<float>(3, 2) = -1.0 / 6; //1.0/BaseLine
Q.at<float>(3, 3) = 0.0; //cx - cx'
//
cv::Mat XYZcv(depth_image.size(), CV_32FC3);
reprojectImageTo3D(depth_image, XYZcv, Q, false, CV_32F);
for (int y = 0; y < XYZcv.rows; y++)
{
for (int x = 0; x < XYZcv.cols; x++)
{
cv::Point3f pointOcv = XYZcv.at<cv::Point3f>(y, x);
Eigen::Vector4d pointEigen(0, 0, 0, left.at<uchar>(y, x) / 255.0);
pointEigen[0] = pointOcv.x;
pointEigen[1] = pointOcv.y;
pointEigen[2] = pointOcv.z;
pointcloud.push_back(pointEigen);
}
}`
那给了我一片乌云。
答案 0 :(得分:1)
我建议使用OpenCV的reprojectImageTo3D
来重建视差距离。请注意,使用此功能时,确实必须将StereoSGBM的输出除以16。您应该已经具有所有参数f
,cx
,cy
,Tx
。注意将f和Tx设置为相同的单位。 cx,cy以像素为单位。
由于问题在于您需要Q矩阵,因此我认为this link或this one应该可以帮助您构建它。如果您不想使用reprojectImageTo3D
,则强烈建议您使用第一个链接!
我希望这会有所帮助!
答案 1 :(得分:0)
要从相机中查找对象的基于点的深度,请使用下面的相机。
深度=(基线x焦距)/视差
我希望您根据自己的问题正确使用它。
尝试使用下面的神经计算器计算理论误差。
https://nerian.com/support/resources/calculator/
此外,在代码中使用亚像素插值。
确保要识别的深度对象具有良好的质感。
主要两个项目的深度错误:
您的校准,相机分辨率和镜头类型(焦距)的RMS值是多少 长度)。为程序提供更好的数据。