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

简介

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

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

原始立体图像

源代码

我们将使用示例应用程序中的代码片段,可以从这里下载。

解释

提供的示例有几个选项,可以在速度和生成的视差图的质量之间进行不同的权衡。如果用户提供了 ground-truth 视差图,则会测量速度和质量。在本教程中,我们将详细了解默认的 pipeline,该 pipeline 旨在在 CPU 上进行实时处理的约束下提供最佳质量。

  1. 加载左视图和右视图
    Mat left = imread(left_im ,IMREAD_COLOR);
    if ( left.empty() )
    {
    cout<<"Cannot read image file: "<<left_im;
    return -1;
    }
    Mat right = imread(right_im,IMREAD_COLOR);
    if ( right.empty() )
    {
    cout<<"Cannot read image file: "<<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 来可视化视差图。第二个参数定义了对比度(所有视差值都在可视化中按此值缩放)。

结果