下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo
欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角star一下!感谢!

算法效果图镇楼:

上一篇博客随机初始化中,我们讲解了算法的第一个步骤:随机初始化 的实现代码,按照步骤,后面一步应该是迭代传播优化,但是我们不得不先讲另外一部分,它非常关键,贯穿于迭代优化步骤全程,它就是:PatchMatchStereo(PMS)的代价计算

【码上实战】【立体匹配系列】经典PatchMatch: (4)代价计算

PMS代价计算的理论知识,我们早在理论恒叨的第一篇中有所介绍:

【理论恒叨】【立体匹配系列】经典PatchMatch: (1)Slanted support windows倾斜支持窗模型

细节再不多言。

PMS计算两个像素的匹配代价公式为:( q q q为左视图像素, q ′ q' q′为右视图像素)

式中, ∣ ∣ I p − I q ∣ ∣ ||I_p-I_q|| ∣∣Ip​−Iq​∣∣为像素 q q q和 q ′ q' q′在RGB空间的L1-distance(就是 ∣ r − r ∣ + ∣ g − g ∣ + ∣ b − b ∣ |r-r|+|g-g|+|b-b| ∣r−r∣+∣g−g∣+∣b−b∣),
∣ ∣ ▽ I p − ▽ I q ′ ∣ ∣ ||▽I_p-▽I_{q'}|| ∣∣▽Ip​−▽Iq′​∣∣为 q q q和 q ′ q' q′的梯度之差的绝对值,该式的含义就是两个像素的颜色相差越大、梯度相差越大,则不相似的程度越大,匹配代价就越大, α α α参数为自定义参数,在颜色和梯度之间做一个平衡。注意到根据平面算出来的视差值是小数值,所以像素 q ′ q' q′的位置不是整数而是小数,它的颜色值和梯度值通过线性内插得到。

如何计算左视图像素 p p p 在视差平面为 f ( a f , b f , c f ) f(a_f,b_f,c_f) f(af​,bf​,cf​)时的代价呢?

以 p p p为中心,作一个适当大小的窗口,通过窗口内每个像素在视差平面为 f ( a f , b f , c f ) f(a_f,b_f,c_f) f(af​,bf​,cf​)时的代价加权聚合得到:

式中, W p W_p Wp​是一个以 p p p为中心的方形窗口, w ( p , q ) w(p,q) w(p,q)是自适应的权值,计算公式如下:

总结一下就是,像素 p p p在视差平面为 f ( a f , b f , c f ) f(a_f,b_f,c_f) f(af​,bf​,cf​)时的聚合代价,是把同样的视差平面赋给窗口内所有其他像素后得到的代价加权得到的。换句话说:最适合我的,也是适合你们的!

我们来看代码。

我把代价计算相关的代码都放到一个hpp文件中:cost_computer.hpp,文件名一看便知其意。我写了一个代价计算基类:

/*** \brief 代价计算器基类*/
class CostComputer {public:/** \brief 代价计算器默认构造 */CostComputer(): img_left_(nullptr), img_right_(nullptr), width_(0), height_(0), patch_size_(0), min_disp_(0),max_disp_(0) {}
}

以派生子类的方式实现具体的代价计算类,这样便于扩展其他不同的代价计算方法,而不用过多的修改频繁使用代价计算类的迭代传播函数体。

而代码里实现了PMS论文中的方法,也就是上面提到的代价计算方法,放到类CostComputerPMS 中:

/*** \brief 代价计算器:PatchMatchStero原文代价计算器*/
class CostComputerPMS : public CostComputer {public:/** \brief PMS代价计算器默认构造 */CostComputerPMS(): grad_left_(nullptr), grad_right_(nullptr), gamma_(0), alpha_(0), tau_col_(0), tau_grad_(0) {} ;
}

我们重点介绍它。

一些简单的不必要重点介绍的代码本文就略过了,比如成员函数、构造函数之类的,重点介绍下它的成员函数。

首先是Compute函数,它就是我上面最先说到的计算两个像素之间的匹配代价。我们看代码:

/*** \brief 计算左影像p点视差为d时的代价值,未做边界判定* \param x     p点x坐标* \param y     p点y坐标* \param d     视差值* \return 代价值*/
inline float32 Compute(const sint32& x, const sint32& y, const float32& d) override
{const float32 xr = x - d;if (xr < 0.0f || xr >= static_cast<float32>(width_)) {return (1 - alpha_) * tau_col_ + alpha_ * tau_grad_;}// 颜色空间距离const auto col_p = GetColor(img_left_, x, y);const auto col_q = GetColor(img_right_, xr, y);const auto dc = std::min(abs(col_p.b - col_q.x) + abs(col_p.g - col_q.y) + abs(col_p.r - col_q.z), tau_col_);// 梯度空间距离const auto grad_p = GetGradient(grad_left_, x, y);const auto grad_q = GetGradient(grad_right_, xr, y);const auto dg = std::min(abs(grad_p.x - grad_q.x)+ abs(grad_p.y - grad_q.y), tau_grad_);// 代价值return (1 - alpha_) * dc + alpha_ * dg;
}

函数输入看注释就明白,将像素的坐标和视差值作为输入。函数体代码前三行是右视图的 x x x坐标计算(因为是核线像对所以 y y y坐标和输入一致)以及边界处理。首先通过两个像素的位置获取像素的颜色值和梯度值,并计算两者的L1-distance,然后代价值等于两空间距离的加权和,权值alpha_是PMS的参数,一开始就被指定了。

以上只是计算了两个像素之间的匹配代价,再来看聚合代价的计算代码:

/*** \brief 计算左影像p点视差平面为p时的聚合代价值* \param x       p点x坐标* \param y     p点y坐标* \param p     平面参数* \return 聚合代价值*/
inline float32 ComputeA(const sint32& x, const sint32& y, const DisparityPlane& p) const
{const auto pat = patch_size_ / 2;const auto& col_p = GetColor(img_left_, x, y);float32 cost = 0.0f;for (sint32 r = -pat; r <= pat; r++) {const sint32 yr = y + r;for (sint32 c = -pat; c <= pat; c++) {const sint32 xc = x + c;if (yr < 0 || yr > height_ - 1 || xc < 0 || xc > width_ - 1) {continue;}// 计算视差值const float32 d = p.to_disparity(xc,yr);if (d < min_disp_ || d > max_disp_) {cost += COST_PUNISH;continue;}// 计算权值const auto& col_q = GetColor(img_left_, xc, yr);const auto dc = abs(col_p.r - col_q.r) + abs(col_p.g - col_q.g) + abs(col_p.b - col_q.b);
#ifdef USE_FAST_EXPconst auto w = fast_exp(double(-dc / gamma_));
#elseconst auto w = exp(-dc / gamma_);
#endif// 聚合代价const auto grad_q = GetGradient(grad_left_, xc, yr);cost += w * Compute(col_q, grad_q, xc, yr, d);}}return cost;
}

如前所述,聚合代价是以 ( x , y ) (x,y) (x,y)为中心的窗口内所有像素在同一个视差平面 p p p下的代价加权和,所以代码里对窗口内的所有像素进行遍历,计算(1)权值(2)每个像素在视差平面p下的视差d,及视差为d时的匹配代价。匹配代价计算是调用上面的代价计算函数(代码里用的是另外一个等价函数,为了避免重复获取在函数外先获取了左视图像素的颜色和梯度)。最后将每个像素计算的代价进行加权求和,就得到像素 ( x , y ) (x,y) (x,y)的聚合代价。

代码里的USE_FAST_EXP是一种快速计算exp的算法,是为了给算法加速,和算法主题无关,不作多说。

另外,还有几个关于获取像素颜色和梯度数据的函数,他们是基于线性内插法,原理十分简单,这里也不做细说,大家看看代码即可。

/**
* \brief 获取像素点的颜色值
* \param img_data   颜色数组
* \param x          像素x坐标,实数,线性内插得到颜色值
* \param y          像素y坐标
* \return 像素(x,y)的颜色值
*/
inline PVector3f GetColor(const uint8* img_data, const float32& x,const sint32& y) const
/**
* \brief 获取像素点的梯度值
* \param grad_data  梯度数组
* \param x          像素x坐标,实数,线性内插得到梯度值
* \param y          像素y坐标
* \return 像素(x,y)的梯度值
*/
inline PVector2f GetGradient(const PGradient* grad_data, const float32& x, const sint32& y) const

好了,今天就到这里啦,我知道大家可能更想学习迭代传播,但还是下一篇再介绍吧,代价计算也是PMS的核心,要先掌握才能往后。放心,不会等太久!

下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo.git
欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,给颗小星星,Follow 我!感激不尽!

码上实战系列

【码上实战】【立体匹配系列】经典PatchMatch: (1)框架
【码上实战】【立体匹配系列】经典PatchMatch: (2)主类
【码上实战】【立体匹配系列】经典PatchMatch: (3)随机初始化
【码上实战】【立体匹配系列】经典PatchMatch: (4)代价计算
【码上实战】【立体匹配系列】经典PatchMatch: (5)迭代传播
【码上实战】【立体匹配系列】经典PatchMatch: (6)后处理

博主简介:
Ethan Li 李迎松(知乎:李迎松)
武汉大学 摄影测量与遥感专业博士

主方向立体匹配、三维重建

2019年获测绘科技进步一等奖(省部级)

爱三维,爱分享,爱开源
GitHub: https://github.com/ethan-li-coding
邮箱:ethan.li.whu@gmail.com

个人微信:

欢迎交流!

关注博主不迷路,感谢!
博客主页:https://ethanli.blog.csdn.net

【码上实战】【立体匹配系列】经典PatchMatch: (4)代价计算相关推荐

  1. 【码上实战】【立体匹配系列】经典SGM:(2)代价计算

    码上教学系列 [码上实战][立体匹配系列]经典SGM:(1)框架与类设计 [码上实战][立体匹配系列]经典SGM:(2)代价计算 [码上实战][立体匹配系列]经典SGM:(3)代价聚合 [码上实战][ ...

  2. 【码上实战】【立体匹配系列】经典SGM:(4)代价聚合2

    昔人已乘黄鹤去,此地空余黄鹤楼. 2020对武汉.对中国.对世界来说是异常艰难的一年.武汉壮士扼腕,封一城而救一国,引得八方救援,举国抗疫.中国人在灾难面前总是空前团结,勇往直前!中华民族几千年来从未 ...

  3. 【码上实战】【立体匹配系列】经典PatchMatch: (1)框架

    下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo 欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角s ...

  4. 【码上实战】【立体匹配系列】经典PatchMatch: (2)主类

    下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo 欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角s ...

  5. 【码上实战】【立体匹配系列】经典PatchMatch: (6)后处理

    下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo 欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角s ...

  6. 【码上实战】【立体匹配系列】经典PatchMatch: (3)随机初始化

    下载完整源码,点击进入: https://github.com/ethan-li-coding/PatchMatchStereo 欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角s ...

  7. 【码上实战】【立体匹配系列】经典AD-Census: (1)框架

    下载AD-Census完整源码,点击进入: https://github.com/ethan-li-coding/AD-Census 欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上 ...

  8. 【码上实战】【立体匹配系列】经典AD-Census: (6)多步骤视差优化

    同学们好久不见! 下载完整源码,点击进入: https://github.com/ethan-li-coding/AD-Census 欢迎同学们在Github项目里讨论! 在实战的上一篇,我们对AD- ...

  9. 【码上实战】【立体匹配系列】经典SGM:(5)视差优化

    千呼万唤始出来,犹抱琵琶半遮面. 抱歉让大家久等,最近事儿繁多,导致更新推迟,实在抱歉. 码上教学系列 [码上实战][立体匹配系列]经典SGM:(1)框架与类设计 [码上实战][立体匹配系列]经典SG ...

最新文章

  1. 200行代码,一行行教你自制微信机器人
  2. Python 字符串判断字母 数字 大小写
  3. windows 下 logstash 安装启动
  4. 《魔鸟》:上帝可以宽恕,魔鬼却一个都不放过
  5. 图片服务 - thumbor安装
  6. VS中的多线程(/MT)、多线程调试(/MTd)、多线程DLL(/MD)、多线程调试DLL(/MDd)的区别(转载)
  7. java requestparams_详解在Spring MVC中使用注解的方式校验RequestParams
  8. git 基础用法梳理
  9. NS3学习之整体介绍
  10. 北通G3游戏手柄开箱体验,原来手游高手都是这么成就的
  11. DGPS与RTK的区别
  12. C语言程序判断一个数是否是素数,C语言中怎么判断一个数是否是素数(即质数)...
  13. QQ消息自动发送器(自动发广告、聊天,支持群,支持最新的QQ2008II Beta1) C# 版...
  14. 华三防火墙透明模式典型组网配置实例
  15. 1.Linux基本简介和使用
  16. 人工神经网络的训练步骤,神经网络训练过程图解
  17. A Survey of Shape Feature Extraction Techniques中文翻译
  18. 2022数维杯数学建模A题
  19. php pdo 事物类,一个基于PDO的数据库操作类(新) 一个PDO事务实例
  20. git push失败:Unable to access 'https://gitee.com/Lmui/proxy.git/': Could not resolve host: gitee.com

热门文章

  1. 节能燃气蒸汽发生器点火失败,异常熄火故障原因
  2. 快付生态开发积分交易核心源码段
  3. 每日一题(十)function showCase(value){ switch(value){ case 'A': console.log('case
  4. 使用python代码画折线图【matplotlib】
  5. JavaSE专栏导航
  6. ubuntu 中使用Docker 安装Tyk3.0.0
  7. 找一个机器学习的工作,学历重要吗?
  8. IP分片--为什么单次最大传输1472个字节
  9. IOS 特定于设备的开发:使用加速器启动屏幕上的对象
  10. 阿里云峰会 | 深化城市计算场景能力,为企业数智化建设提供助推力