【发布时间】:2014-04-20 13:28:42
【问题描述】:
我一直在尝试使用 OpenCV 提供的 reprojectImageTo3D() 函数从视差图中计算点的真实世界坐标,但输出似乎不正确。
我有校准参数,并使用计算 Q 矩阵
stereoRectify(left_cam_matrix, left_dist_coeffs, right_cam_matrix, right_dist_coeffs, frame_size, stereo_params.R, stereo_params.T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, 0, frame_size, 0, 0);
我相信这第一步是正确的,因为立体帧得到了正确的校正,而且我正在执行的失真消除似乎也很好。视差图是用OpenCV的块匹配算法计算的,看起来也不错。
3D 点的计算方式如下:
cv::Mat XYZ(disparity8U.size(),CV_32FC3);
reprojectImageTo3D(disparity8U, XYZ, Q, false, CV_32F);
但由于某种原因,它们形成了某种锥体,考虑到视差图,甚至与我预期的不接近。我发现其他人对此功能也有类似的问题,我想知道是否有人有解决方案。
提前致谢!
[编辑]
stereoRectify(left_cam_matrix, left_dist_coeffs, right_cam_matrix, right_dist_coeffs,frame_size, stereo_params.R, stereo_params.T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, 0, frame_size, 0, 0);
initUndistortRectifyMap(left_cam_matrix, left_dist_coeffs, R1, P1, frame_size,CV_32FC1, left_undist_rect_map_x, left_undist_rect_map_y);
initUndistortRectifyMap(right_cam_matrix, right_dist_coeffs, R2, P2, frame_size, CV_32FC1, right_undist_rect_map_x, right_undist_rect_map_y);
cv::remap(left_frame, left_undist_rect, left_undist_rect_map_x, left_undist_rect_map_y, CV_INTER_CUBIC, BORDER_CONSTANT, 0);
cv::remap(right_frame, right_undist_rect, right_undist_rect_map_x, right_undist_rect_map_y, CV_INTER_CUBIC, BORDER_CONSTANT, 0);
cv::Mat imgDisparity32F = Mat( left_undist_rect.rows, left_undist_rect.cols, CV_32F );
StereoBM sbm(StereoBM::BASIC_PRESET,80,5);
sbm.state->preFilterSize = 15;
sbm.state->preFilterCap = 20;
sbm.state->SADWindowSize = 11;
sbm.state->minDisparity = 0;
sbm.state->numberOfDisparities = 80;
sbm.state->textureThreshold = 0;
sbm.state->uniquenessRatio = 8;
sbm.state->speckleWindowSize = 0;
sbm.state->speckleRange = 0;
// Compute disparity
sbm(left_undist_rect, right_undist_rect, imgDisparity32F, CV_32F );
// Compute world coordinates from the disparity image
cv::Mat XYZ(disparity32F.size(),CV_32FC3);
reprojectImageTo3D(disparity32F, XYZ, Q, false, CV_32F);
print_3D_points(disparity32F, XYZ);
[编辑]
添加用于根据视差计算 3D 坐标的代码:
cv::Vec3f *StereoFrame::compute_3D_world_coordinates(int row, int col,
shared_ptr<StereoParameters> stereo_params_sptr){
cv::Mat Q_32F;
stereo_params_sptr->Q_sptr->convertTo(Q_32F,CV_32F);
cv::Mat_<float> vec(4,1);
vec(0) = col;
vec(1) = row;
vec(2) = this->disparity_sptr->at<float>(row,col);
// Discard points with 0 disparity
if(vec(2)==0) return NULL;
vec(3)=1;
vec = Q_32F*vec;
vec /= vec(3);
// Discard points that are too far from the camera, and thus are highly
// unreliable
if(abs(vec(0))>10 || abs(vec(1))>10 || abs(vec(2))>10) return NULL;
cv::Vec3f *point3f = new cv::Vec3f();
(*point3f)[0] = vec(0);
(*point3f)[1] = vec(1);
(*point3f)[2] = vec(2);
return point3f;
}
【问题讨论】:
-
你能展示你得到的视差图和你给立体块匹配算法的参数吗?
-
当然,你可以在这里看到左帧和视差:postimg.org/image/yuimlj5u7 这些是我用来计算视差的参数: StereoBM sbm(StereoBM::BASIC_PRESET,80,5); sbm.state->preFilterSize=15; sbm.state->preFilterCap=20; sbm.state->SADWindowSize=11; sbm.state->minDisparity=0; sbm.state->numberOfDisparities=80; sbm.state->textureThreshold=0; sbm.state->uniquenessRatio=8; sbm.state->speckleWindowSize=0; sbm.state->speckleRange=0;
-
你说得对,视差图似乎还可以。重新投影到 3D 时的圆锥形状可能是由于视差图中的噪声造成的吗?你能用 3D 展示你得到的东西吗?
-
您好,感谢您迄今为止的帮助!可以在这里看到 3D 点:postimg.org/image/9lunzg917。另外,正如我在帖子中所说,有很多人有完全相同的问题。这是他们发布问题的论坛之一的链接(opencv-users.1802565.n2.nabble.com/…),以防您需要更多数据。您认为这可能与视差图像的格式有关吗? StereoBM 算法返回一个 CV_16S 图像,我将其转换为 CV_8U。这就是我进行转换的方式:
-
双 minVal;双最大值; minMaxLoc(imgDisparity16S, &minVal, &maxVal ); imgDisparity16S.convertTo(imgDisparity8U, CV_8UC1, 255/(maxVal - minVal));