OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
无匹配项
视差图后滤波

介绍

立体匹配算法,尤其是用于 CPU 上实时处理的高度优化的算法,往往会在具有挑战的序列上产生相当多的错误。这些错误通常集中在没有纹理的均匀区域、半遮挡和靠近深度不连续区域。处理立体匹配错误的一种方法是采用各种技术来检测潜在的不准确视差值并使其失效,从而使视差图变为半稀疏。立体匹配算法 StereoBM 和 StereoSGBM 现已实现了几种此类技术。另一种方法是使用某种筛选程序来对齐视差图边缘与源图像边缘,并从可信度高的区域(如半遮挡)传播视差值到可信度低的区域。边缘感知滤波方面的最新进展使得在 CPU 实时处理的限制下执行此类后滤波成为可能。

在本教程中,您将学习如何使用视差图后滤波来改善 StereoBM 和 StereoSGBM 算法的结果。

源立体图像

源代码

我们将使用示例应用程序中的代码片段,该片段可从 此处 下载。

解释

提供的示例具有多个选项,在最终视差图的速度和质量之间实现不同的权衡。如果用户提供了地面实况视差图,那么速度和质量都将得到衡量。在本教程中,我们将详细了解默认管道,该管道旨在 CPU 实时处理的限制下提供尽可能好的质量。

  1. 加载左右视图
    Mat left = imread(left_im ,IMREAD_COLOR);
    if ( left.empty() )
    {
    cout<<"无法读取图像文件: "<<left_im;
    return -1;
    }
    Mat right = imread(right_im,IMREAD_COLOR);
    if ( right.empty() )
    {
    cout<<"无法读取图像文件: "<<right_im;
    return -1;
    }
    我们首先加载源立体对。对于本教程,我们从 MPI-Sintel 数据集选取一个颇具挑战性的示例,其中包含大量的无纹理区域。
  2. 准备匹配视图
    max_disp/=2;
    if(max_disp%16!=0)
    max_disp += 16-(max_disp%16);
    resize(left ,left_for_matcher ,Size(),0.5,0.5, INTER_LINEAR_EXACT);
    resize(right,right_for_matcher,Size(),0.5,0.5, INTER_LINEAR_EXACT);
    我们执行视图降采样以为匹配阶段加速,这会以轻微的质量下降为代价。为了获得最佳可能的质量,应避免降采样。
  3. 执行匹配并创建滤波器实例
    Ptr<StereoBM> left_matcher = StereoBM::create(max_disp,wsize);
    wls_filter = createDisparityWLSFilter(left_matcher);
    Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);
    cvtColor(left_for_matcher, left_for_matcher, COLOR_BGR2GRAY);
    cvtColor(right_for_matcher, right_for_matcher, COLOR_BGR2GRAY);
    matching_time = (double)getTickCount();
    left_matcher-> compute(left_for_matcher, right_for_matcher,left_disp);
    right_matcher->compute(right_for_matcher,left_for_matcher, right_disp);
    matching_time = ((double)getTickCount() - matching_time)/getTickFrequency();
    我们使用 StereoBM 以便更快地处理。但如果速度不是关键因素,则 StereoSGBM 会提供更好的质量。通过提供我们想要使用的 StereoMatcher 实例来创建滤波器实例。createRightMatcher 函数返回其他匹配器实例。然后,这两个匹配器实例用于计算滤波器需要的左右视图视差图。
  4. 执行滤波
    wls_filter->setLambda(lambda);
    wls_filter->setSigmaColor(sigma);
    filtering_time = (double)getTickCount();
    wls_filter->filter(left_disp,left,filtered_disp,right_disp);
    filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency();
    将各自匹配器实例计算出的视差图,以及源左视图传递到滤波器。请注意我们使用原始未降采样的视图来指导滤波过程。会以感知边缘的方式自动放大视差图,以匹配原始视图分辨率。结果存储在 filtered_disp 中。
  5. 可视化视差图
    Mat raw_disp_vis;
    getDisparityVis(left_disp,raw_disp_vis,vis_mult);
    namedWindow("raw disparity", WINDOW_AUTOSIZE);
    imshow("raw disparity", raw_disp_vis);
    Mat filtered_disp_vis;
    getDisparityVis(filtered_disp,filtered_disp_vis,vis_mult);
    namedWindow("filtered disparity", WINDOW_AUTOSIZE);
    imshow("filtered disparity", filtered_disp_vis);
    if(!solved_disp.empty())
    {
    Mat solved_disp_vis;
    getDisparityVis(solved_disp,solved_disp_vis,vis_mult);
    namedWindow("solved disparity", WINDOW_AUTOSIZE);
    imshow("solved disparity", solved_disp_vis);
    Mat solved_filtered_disp_vis;
    getDisparityVis(solved_filtered_disp,solved_filtered_disp_vis,vis_mult);
    namedWindow("solved wls disparity", WINDOW_AUTOSIZE);
    imshow("solved wls disparity", solved_filtered_disp_vis);
    }
    while(1)
    {
    char key = (char)waitKey();
    if( key == 27 || key == 'q' || key == 'Q') // 'ESC'
    break;
    }
    我们使用便捷函数 getDisparityVis 来可视化视差图。第二个参数定义对比度(可视化中所有视差值都按此值缩放)。

结果