【发布时间】:2020-04-08 20:51:50
【问题描述】:
我有一个使用校准的立体相机对和 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);
}
}`
这给了我一片乌云。
【问题讨论】:
-
几个问题:您是如何估计校准好的?你用了多少张图片?您是否使用 StereoSGBM 进行视差估计?你能提供校正后的图像和深度图吗?为什么不使用 reprojectImageTo3D 重新映射所有点?为什么立体声基线以米为单位而您期望毫米?一句话:fMaxDistance 是错误的(括号!),如果你将视差除以 16,你应该得到 0.590693 * 16。
-
您好,感谢您的回复。校准矩阵是根据立体相机的板载校准数据创建的(出厂校准)。我确实使用
StereoSGBM,然后使用DisparityWLSFilter。我不使用 ReprojectImageTo3d,因为我手动创建了矩阵,所以我没有Q矩阵。深度图代码很大程度上基于这个:“github.com/k22jung/stereo_vision/blob/master/src/…”我会添加一些图片。