C/C++终端游戏开发:数据结构与Dijkstra算法实战解析
2026/5/14 8:31:07
先把“双目差异”变成“深度/视差”,再用深度做分割,这样“存在”就变得非常清晰。
标定 + 极线校正(Rectify)
没有这一步,后面的视差会非常飘,轮廓会抖,动态更没法做。
计算视差图(Stereo Matching)
用 OpenCVStereoSGBM(通常比 BM 好)得到 disparity。
视差后处理
ximgproc::DisparityWLSFilter会明显更干净按深度分割存在(生成存在mask)
从mask提轮廓findContours得到轮廓;需要更精细就用 depth 边界 + 图像边缘(Canny)做融合细化。
// 1) 假设你已经做完标定&校正,拿到了 rectLeft, rectRight (灰度)cv::Ptr<cv::StereoSGBM>sgbm=cv::StereoSGBM::create(/*minDisparity*/0,/*numDisparities*/128,// 必须是16的倍数:64/96/128.../*blockSize*/5);sgbm->setP1(8*1*5*5);sgbm->setP2(32*1*5*5);sgbm->setUniquenessRatio(10);sgbm->setSpeckleWindowSize(100);sgbm->setSpeckleRange(2);sgbm->setDisp12MaxDiff(1);sgbm->setMode(cv::StereoSGBM::MODE_SGBM_3WAY);cv::Mat disp16S;sgbm->compute(rectLeft,rectRight,disp16S);// 2) disparity 转 float(OpenCV 输出通常是 *16 的定点)cv::Mat disp;disp16S.convertTo(disp,CV_32F,1.0/16.0);// 3) 基于视差阈值做“近物体”mask(阈值要结合你的基线/分辨率调)floatnearDispTh=8.0f;// 例:>8 认为更靠近(需要你现场调)cv::Mat mask=disp>nearDispTh;// 4) 去噪&填洞mask.convertTo(mask,CV_8U,255);cv::morphologyEx(mask,mask,cv::MORPH_OPEN,cv::getStructuringElement(cv::MORPH_ELLIPSE,{3,3}));cv::morphologyEx(mask,mask,cv::MORPH_CLOSE,cv::getStructuringElement(cv::MORPH_ELLIPSE,{7,7}));// 5) 连通域过滤掉小碎片cv::Mat labels,stats,centroids;intn=cv::connectedComponentsWithStats(mask,labels,stats,centroids,8,CV_32S);cv::Mat clean=cv::Mat::zeros(mask.size(),CV_8U);for(inti=1;i<n;i++){intarea=stats.at<int>(i,cv::CC_STAT_AREA);if(area>500){// 过滤阈值按分辨率调clean.setTo(255,labels==i);}}// 6) 轮廓std::vector<std::vector<cv::Point>>contours;cv::findContours(clean,contours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);只有在你满足这些条件时它才可能“凑合”:
但一旦你要为“动态”服务(连续帧稳定追踪、速度/位移估计、轮廓编码记忆),深度分割几乎是必选项。