OpenCV 4.11.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("原始视差", WINDOW_AUTOSIZE);
    imshow("原始视差", raw_disp_vis);
    Mat filtered_disp_vis;
    getDisparityVis(filtered_disp,filtered_disp_vis,vis_mult);
    namedWindow("滤波后的视差", WINDOW_AUTOSIZE);
    imshow("滤波后的视差", filtered_disp_vis);
    if(!solved_disp.empty())
    {
    Mat solved_disp_vis;
    getDisparityVis(solved_disp,solved_disp_vis,vis_mult);
    namedWindow("已解决的视差", WINDOW_AUTOSIZE);
    imshow("已解决的视差", solved_disp_vis);
    Mat solved_filtered_disp_vis;
    getDisparityVis(solved_filtered_disp,solved_filtered_disp_vis,vis_mult);
    namedWindow("已解决的WLS视差", WINDOW_AUTOSIZE);
    imshow("已解决的WLS视差", solved_filtered_disp_vis);
    }
    while(1)
    {
    char key = (char)waitKey();
    if( key == 27 || key == 'q' || key == 'Q') // 'ESC'
    break;
    }
    我们使用一个方便的函数 getDisparityVis 来显示视差图。第二个参数定义对比度(所有视差值在可视化中都按此值缩放)。

结果