【SLAM】双目图像视差图填充

由于不同视角的遮挡或者错误的匹配,经过SGBM算法计算的视差图存在一些无效区。为了获得稠密的视差图,或者对关键点的无效视差进行近似,我们需要填充这些无效区。
请添加图片描述
这些乌漆嘛黑的区域就是需要填充的无效区

这里不讨论遮挡与误匹配的判定,有需要请移步大佬的博客:
【码上实战】【立体匹配系列】经典SGM:(6)视差填充
这篇博客也提供了视差填充的方法和代码,我这里提供原理上更简易(简陋)的实现

等角度往外发射8条射线进行采样,计算均值

在这里插入图片描述

原理很简单,直接放代码,就是写的很丑。。。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    cv::Mat image = cv::imread("../disparity/000000.png", 0);
    const int width = image.cols;
    const int height = image.rows;
    cv::Mat newImage = cv::Mat::zeros(cv::Size(width, height), CV_8UC1);
    std::vector<float> disp_collects;
    for(int col = 0; col < width; ++col)
    {
        for(int row = 0; row < height; ++row)
        {
            // cout << "col: " << col << ", row: " << row << endl;
            if(image.at<uchar>(row, col) == 0)
            {
               int usefulPoint = 0, sumPixel = 0;
               int v = col, u = row;
               // 0
               while(v < width)
               {
                   ++v;
                   if(image.at<uchar>(u, v) > 0)
                   {
                       sumPixel += image.at<uchar>(u, v);
                       ++usefulPoint;
                       break;
                   }
               }

               // pi/4
               v = col, u = row;
               while(v < width && u < height)
               {
                   ++v;
                   ++u;
                   if(image.at<uchar>(u, v) > 0)
                   {
                       sumPixel += image.at<uchar>(u, v);
                       ++usefulPoint;
                       break;
                   }
               }

                // pi/2
                v = col, u = row;
                while(u < height)
                {
                    ++u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }

                // pi*3/4
                v = col, u = row;
                while(v > 0 && u < height)
                {
                    --v;
                    ++u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }

                // pi
                v = col, u = row;
                while(v > 0)
                {
                    --v;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }

                // pi*5/4
                v = col, u = row;
                while(v > 0 && u > 0)
                {
                    --v;
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }

                // pi*3/2
                v = col, u = row;
                while(u > 0)
                {
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }

                // pi*7/4
                v = col, u = row;
                while(v < width && u > 0)
                {
                    ++v;
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        sumPixel += image.at<uchar>(u, v);
                        ++usefulPoint;
                        break;
                    }
                }
                // cout << sumPixel / usefulPoint << " and " << (unsigned char)(sumPixel / usefulPoint) << endl;
                newImage.at<uchar>(row, col) = (unsigned char)(sumPixel / usefulPoint);
            }
            else newImage.at<uchar>(row, col) = image.at<uchar>(row, col);
        }
    }
    cv::Mat saveImage;
    cv::medianBlur(newImage, saveImage, 3);
    cv::imwrite("../test.png", saveImage);
    return 0;
}

请添加图片描述
这是用这种方法填充的效果,一片原本的无效区域内的值都差不多,缺乏过渡
在这里插入图片描述

等角度往外发射8条射线进行采样,进行线性插值

为了获取有更好过渡的视差填充,可以在采样后做4次简单的单线性插值,再算平均值
首先把8个方向的射线分为4组,0和π,π/4和5π/4,π/2和3π/2, 3π/4和7π/4
这4组方向都在一条直线上,对这条直线的两个端点进行采样插值,可以使填充的过渡效果更好一些
这里再简单推导一下单线性插值的算法:
请添加图片描述
代码如下:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include "math.h"

using namespace std;

int main()
{
    cv::Mat image = cv::imread("../disparity/000000.png", 0);
    const int width = image.cols;
    const int height = image.rows;
    cv::Mat newImage = cv::Mat::zeros(cv::Size(width, height), CV_8UC1);
    bool flag = false;
    for(int col = 0; col < width; ++col)
    {
        for(int row = 0; row < height; ++row)
        {
            cout << "col: " << col << ", row: " << row << endl;
            if(image.at<uchar>(row, col) == 0)
            {
               double sumPixel = 0;
               double x;
               int v = col, u = row;
               int y_1, y_2, x_length;
               int coordX_1, coordX_2, coordY_1, coordY_2;

               // Group 1 --------------------------------------------------------------------------------------
               // 0
               flag = false;
               while(v < width)
               {
                   ++v;
                   if(image.at<uchar>(u, v) > 0)
                   {
                       y_1 = image.at<uchar>(u, v);
                       flag = true;
                       break;
                   }
               }
               if(!flag) y_1 = 0;
               coordX_1 = v;
               coordY_1 = u;

                // pi
                flag = false;
                v = col, u = row;
                while(v > 0)
                {
                    --v;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_2 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_2 = 0;
                coordX_2 = v;
                coordY_2 = u;

                // compute line 1
                x_length = sqrt(pow((coordX_2 - coordX_1), 2) + pow((coordY_2 - coordY_1), 2));
                x = sqrt(pow((col - coordX_1), 2) + pow((row - coordY_1), 2)) / x_length;
                sumPixel += (1 - x) * (y_1 - y_2) + y_2;
//                cout << "col: " << col << ", row: " << row << ", coordX_1: " << coordX_1 << ", coordY_1: " << coordY_1 << ", coordX_2: " << coordX_2 << ", coordY_2: " << coordY_2 << endl;
//                cout << "x_length: " << x_length << ", x: " << x << ", y_1: " << y_1 << ", y_2: " << y_2 << endl;
//                cout << "result: " << (1 - x) * (y_1 - y_2) + y_2 << endl;

                // Group 2 --------------------------------------------------------------------------------------
                // pi/4
                flag = false;
                v = col, u = row;
                while(v < width && u < height)
                {
                    ++v;
                    ++u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_1 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_1 = 0;
                coordX_1 = v;
                coordY_1 = u;

                // pi*5/4
                flag = false;
                v = col, u = row;
                while(v > 0 && u > 0)
                {
                    --v;
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_2 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_2 = 0;
                coordX_2 = v;
                coordY_2 = u;

                // compute line 2
                x_length = sqrt(pow((coordX_2 - coordX_1), 2) + pow((coordY_2 - coordY_1), 2));
                x = sqrt(pow((col - coordX_1), 2) + pow((row - coordY_1), 2)) / x_length;
                sumPixel += (1 - x) * (y_1 - y_2) + y_2;

                // Group 3 --------------------------------------------------------------------------------------
                // pi/2
                flag = false;
                v = col, u = row;
                while(u < height)
                {
                    ++u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_1 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_1 = 0;
                coordX_1 = v;
                coordY_1 = u;

                // pi*3/2
                flag = false;
                v = col, u = row;
                while(u > 0)
                {
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_2 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_2 = 0;
                coordX_2 = v;
                coordY_2 = u;

                // compute line 3
                x_length = sqrt(pow((coordX_2 - coordX_1), 2) + pow((coordY_2 - coordY_1), 2));
                x = sqrt(pow((col - coordX_1), 2) + pow((row - coordY_1), 2)) / x_length;
                sumPixel += (1 - x) * (y_1 - y_2) + y_2;

                // Group 4 --------------------------------------------------------------------------------------
                // pi*3/4
                v = col, u = row;
                flag = false;
                while(v > 0 && u < height)
                {
                    --v;
                    ++u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_1 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_1 = 0;
                coordX_1 = v;
                coordY_1 = u;

                // pi*7/4
                v = col, u = row;
                flag = false;
                while(v < width && u > 0)
                {
                    ++v;
                    --u;
                    if(image.at<uchar>(u, v) > 0)
                    {
                        y_2 = image.at<uchar>(u, v);
                        flag = true;
                        break;
                    }
                }
                if(!flag) y_2 = 0;
                coordX_2 = v;
                coordY_2 = u;

                // compute line 4
                x_length = sqrt(pow((coordX_2 - coordX_1), 2) + pow((coordY_2 - coordY_1), 2));
                x = sqrt(pow((col - coordX_1), 2) + pow((row - coordY_1), 2)) / x_length;
                sumPixel += (1 - x) * (y_1 - y_2) + y_2;

                // cout << sumPixel / usefulPoint << " and " << (unsigned char)(sumPixel / usefulPoint) << endl;
                newImage.at<uchar>(row, col) = (unsigned char)(sumPixel / 4);
            }
            else newImage.at<uchar>(row, col) = image.at<uchar>(row, col);
        }
    }
    cv::Mat saveImage;
    cv::medianBlur(newImage, saveImage, 3);
    cv::imwrite("../test.png", saveImage);
    return 0;
}

效果如下:
在这里插入图片描述
可以看到过渡好了一些
在这里插入图片描述

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值