图像融合后: 参考博文:从泊松方程的解法,聊到泊松图像融合 - 知乎

参考论文:Pérez P, Gangnet M, Blake A. Poisson image editing[M]//ACM SIGGRAPH 2003 Papers. 2003: 313-318.

参考代码:GitHub - cheind/poisson-image-editing: Poisson image editing for seamless cloning and other operations(注意:代码中的梯度场拉普拉斯滤波核有误)

问题分析

在图像融合任务中,前景放置在背景上时,需要保证两点:

  • 前景本身主要内容相比于背景而言,尽量平滑

  • 边界处无缝,即前景、背景在边界点位置上的像素值,需要保持边界一致

重点关注两个词:内容平滑、边界一致。

平滑是什么?可以理解成图像前景、背景梯度尽可能接近。

边界一致是指什么?可以理解成在边界上像素值相同。

用一张图来说明:

连续的泊松求解器

离散的泊松求解器

对于计算机中的图像定义域是离散的,因此我们需要将连续问题转化为离散问题

其中,重要变量的具体计算如下所示:

梯度场v的散度

For example, 
x方向的梯度kernelx可以是:
 `cv::Mat kernelx = (cv::Mat_<float>(1, 3) << 0 , -1, 1);`
 然后,再求拉普拉斯kernelx可以是:
 `cv::Mat kernelx = (cv::Mat_<float>(1, 3) << -1 , 1, 0);`

那么因为,
 `f = vxx + vyy`
以及根据对应的拉普拉斯kernelx
 `vxx(p.x, p.y) = vx(p.x, p.y) - vx(p.(x-1), p.y)`
以及,对应的梯度kernelx
 `vx(p.x, p.y) = g(p.(x+1), p.y)-g(p.x, p.y)  `
 `vx(p.(x-1), p.y) =g(p.x, p.y)-g(p.(x-1), p.y)`
因此,
 `vxx(p.x, p.y) = g(p.(x+1), p.y)-g(p.x, p.y)-g(p.x, p.y)+g(p.(x-1), p.y)`
 `vxx(p.x, p.y) = g(p.(x+1), p.y)+g(p.(x-1), p.y)-2*g(p.x, p.y)`
同理计算vyy,
 `vyy(p.x, p.y) = g(p.x, p.(y+1)))+g(p.y, p.(y-1))-2*g(p.x, p.y)`
因此可得梯度场的散度,
 `f =g(p.(x+1), p.y)+g(p.(x-1), p.y)+g(p.x, p.(y+1)))+g(p.y, p.(y-1))-4*g(p.x, p.y) `

参考:https://github.com/cheind/poisson-image-editing/issues/7

这里据一个错误的梯度场求散度的例子,也是参考代码中的一个疏漏:

如果,x方向的梯度kernelx和拉普拉斯kernelx都为 `cv::Mat kernelx = (cv::Mat_<float>(1, 3) << -0.5 , 0, 0.5);`

那么因为,
 `f = vxx + vyy`
以及根据对应的拉普拉斯kernelx
 `vxx(p.x, p.y) = 0.5*(-vx(p.(x-1), p.y) + vx(p.(x+1), p.y))`
以及,对应的梯度kernelx
 `vx(p.(x-1), p.y) = 0.5(-g(p.(x-2), p.y) + g(p.x, p.y))`
 `vx(p.(x+1), p.y) = 0.5(-g(p.x, p.y) + g(p.(x+2), p.y))`
因此,
 `vxx(p.x, p.y) = 0.5*( -0.5(-g(p.(x-2), p.y) + g(p.x, p.y)) + 0.5( -g(p.x, p.y) + g(p.(x+2), p.y)) )`
 `vxx(p.x, p.y) = 0.25*( g(p.(x-2), p.y) - g(p.x, p.y) - g(p.x, p.y) + g(p.(x+2), p.y) )`
 `vxx(p.x, p.y) = 0.25*(  - 2*g(p.x, p.y) + g(p.(x-2), p.y) + g(p.(x+2), p.y) )`
同理计算vyy,
 `vyy(p.x, p.y) = 0.25*(  - 2*g(p.x, p.y) + g(p.x, p.(y-2)) + g(p.x, p.(y+2)) )`
因此可得梯度场的散度,
 `f = 0.25*(  - 4*g(p.x, p.y) + g(p.x, p.(y-2)) + g(p.x, p.(y+2)) + g(p.(x-2), p.y) + g(p.(x+2), p.y)  )`

方向仍然是正确的,唯一的问题是0.25比例,而且它不完全是 p 的 4 邻居,而是 +2 和 -2 邻居。

但由于 4-neighbor 本身只是离散梯度的近似值,因此这段代码的结果与论文非常相似,只不过还原出来的结果会略有模糊。

矩阵A的构建

其中,这个矩阵A是正方形矩阵,即宽和高相等;每一行代表图像中mask区域的每一个像素点;

对角线的绝对值表示该点的4-neighbor的实际数量,比如-4表示该点4-neighbor的实际数量为4,比如图像边缘点的4-neighbor的实际数量可能为3或者2;非图像边缘点的默认应该都是-4;

若该点的4-neighbor中存在边界点,即mask边缘点,则在`该点对应行`中的`邻点对应列`置为0,否则置为1。

矩阵B的构建

代码中的一些关键参数:

// Directional indices
const int center = 0;
const int north = 1;
const int east = 2;
const int south = 3;
const int west = 4;// Neighbor offsets in all directions
const int offsets[5][2] = { { 0, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };//4-neighbor的偏移量// Directional opposite
const int opposite[5] = { center, south, west, north, east };float lhs[] = { -4.f, 1.f, 1.f, 1.f, 1.f };//nUnknowns为mask区域中总的像素点数量
std::vector< Eigen::Triplet<float> > lhsTriplets;//矩阵A
lhsTriplets.reserve(nUnknowns * 5);Eigen::MatrixXf rhs(nUnknowns, channels);//矩阵BEigen::SparseLU< Eigen::SparseMatrix<float> > solver;//求解器

矩阵A和矩阵B构建过程的对应代码:

for (int n = 1; n < 5; ++n) {const cv::Point q(x + offsets[n][0], y + offsets[n][1]);const bool hasNeighbor = bounds.contains(q);const bool isNeighborDirichlet = hasNeighbor && (bm(q) == constants::DIRICHLET_BD);if (!hasNeumann && !hasNeighbor) {lhs[center] += lhs[n];lhs[n] = 0.f;} else if (isNeighborDirichlet) {rhs.row(pid) -= lhs[n] * Eigen::Map<Eigen::VectorXf>(bv.ptr<float>(q.y, q.x), channels);//rhs对应矩阵Blhs[n] = 0.f;}
}
// Add f to rhs.
rhs.row(pid) += Eigen::Map<Eigen::VectorXf>(f.ptr<float>(p.y, p.x), channels);//f对应梯度场的散度 div(v)// Build triplets for row
for (int n = 0; n < 5; ++n) {if (lhs[n] != 0.f) {const cv::Point q(x + offsets[n][0], y + offsets[n][1]);lhsTriplets.push_back(Eigen::Triplet<float>(pid, unknownIdx(q), lhs[n]));//lhsTriplets对应矩阵A}
}

求解AX=B

求解矩阵方程AX=B(比如,LU分解、高斯消元、最速梯度下降法、共轭梯度法等)

代码中采用Eigen::SparseMatrix构建矩阵A,因为这是个稀疏矩阵。

采用Eigen::SparseLU建立求解器solver,

将矩阵A分解为LU,即A=LU(L为下三角矩阵,U为上三角矩阵),然后就可以将问题转换为高斯消元法

Eigen::SparseMatrix<float> A(nUnknowns, nUnknowns);
A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());Eigen::SparseLU< Eigen::SparseMatrix<float> > solver;
solver.analyzePattern(A);
solver.factorize(A);Eigen::MatrixXf result(nUnknowns, channels);for (int c = 0; c < channels; ++c)result.col(c) = solver.solve(rhs.col(c));

*后续可以尝试其他求解方法,包括但不限于矩阵A分块求逆、最速梯度下降法、共轭梯度法等

梯度场的定义:混合梯度

实例测试

参考代码:GitHub - cheind/poisson-image-editing: Poisson image editing for seamless cloning and other operations(注意:代码中的梯度场拉普拉斯滤波核有误)

速度会比opencv实现的版本更快一点

简单贴图

需要准备好,背景图bg,前景图fg,掩膜图mask

其中,前景图和mask图的尺寸要一致

命令行参数(参考):

seamless_cloning ./images/bg2.bmp ./images/fg2.bmp ./images/mask2.bmp 0 0

梯度损失——图像模糊问题

对比原图和图像融合后的相同位置的梯度分布

原图:

图像融合后:

可以很明显地看到融合后的图像变模糊了。

原因分析:梯度场散度的离散求解精度(如果是8-neighbor会更加准确)、边界条件(Dirichlet 边界过于简单,但是也要综合考虑效率)以及泊松编辑原理本身需要考虑到边缘的过渡,模糊也是必然会发生的了。

总结

1.泊松编辑不适用于多线程,更适用于在线融合(对比多波段融合和羽化融合可以多线程处理,适用于半离线或离线处理)

2.当前的泊松编辑方法效率仍然比较慢,后续需要考虑矩阵方程AX=B的其他更高效的求解方法

3.存在编辑区域的图像模糊问题,可以尽量减少模糊至肉眼难以辨别,但是仍然存在。

【学习体会】图像泊松融合相关推荐

  1. 泊松融合vs图像和谐化

    大的方向来说图像融合可分为三个层次:像素级融合.特征级融合和决策级融合. 传统的融合算法有Alpha blending .Laplacian Pyramid blending.Poisson Blen ...

  2. 泊松图像融合(泊松融合)

    泊松图像融合(泊松融合) from: http://blog.csdn.net/baimafujinji/article/details/46787837 在之前的文章中,我们详细介绍了基于泊松方程的 ...

  3. 图像的泊松(Poisson)编辑、泊松融合完全详解

    图像的泊松(Poisson)编辑.泊松融合完全详解(1) --泊松方程的理论推导       图像的泊松(Poisson)编辑.泊松融合完全详解(2) --从物理模型跨入图像模型以及算法详解     ...

  4. 深度学习图像融合_基于深度学习的图像超分辨率最新进展与趋势【附PDF】

    因PDF资源在微信公众号关注公众号:人工智能前沿讲习回复"超分辨"获取文章PDF 1.主题简介 图像超分辨率是计算机视觉和图像处理领域一个非常重要的研究问题,在医疗图像分析.生物特 ...

  5. 图像融合之泊松融合,原理讲解及C++代码实现(特别适合新手)

    本篇文章主要为讲解图像处理的泊松融合的原理及实现. 泊松融合原理来源于这篇文章:<Poisson Image Editing> 本人为图像处理的小白,在机缘巧合下,看到了泊松融合的图像处理 ...

  6. 帮推|基于深度学习的图像融合方法综述

    基于深度学习的图像融合方法综述 博主朋友关于图像融合的综述论文基于深度学习的图像融合方法综述已被<中国图象图形学报>正式接收! 极力推荐想要入门图像融合领域的小伙伴下载学习,此外希望在图像 ...

  7. 关于图像梯度、散度、泊松融合

    在看泊松融合的时候复习了一下梯度.散度(大学学的全还给老师了-- 图像梯度计算 图像中的梯度和散度 看完上面两篇文章大致可以理解如何求梯度,为什么对梯度求偏导再相加的和为散度,然后可以看图像融合之泊松 ...

  8. 计算机视觉预备知识,计算机视觉:泊松融合

    Poisson Blending4:更多用途 Poisson Blending0:预备知识(图像的梯度.泊松方程) 进入正题之前,我们先补充一下基础知识.图像的梯度 什么是图像的梯度?我们可以把图像看 ...

  9. 结合深度学习的图像修复怎么实现?

    作者:QZhang 链接:https://www.zhihu.com/question/56801298/answer/155891603 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非 ...

最新文章

  1. MoviePy - 中文文档4-MoviePy实战案例-把多个clip放置在一个画面中(超美)
  2. 数字证书——密码学笔记(六)
  3. linux 域账户密码忘记,linux基础命令-用户域用户组管理
  4. 精选30个优秀的CSS技术和实例
  5. git 部分常用命令记录
  6. mysql(mariadb)重装
  7. LPC1768的USB-相关结构体定义
  8. Mybatis selectKey标签的keyProperty属性报错,关键字间隔不能有空格
  9. HRM人力资源管理平台技术总结
  10. 8uftp怎么使用,小编教你8uftp怎么使用
  11. adams2015怎么把工具栏打开_怎么合并音乐?教大家3种快速完成音频合并的办法!...
  12. golang中slice切片使用的误区
  13. EXCEL:摒弃千篇一律,修改工作表中网络线的颜色
  14. 用山脊图展示后验分布
  15. Spring AOP 切面记录操作日志
  16. 分享一下最近数学竞赛的获奖经历
  17. 利用DncZeus框架开发UWB室内定位网关
  18. 产品读书《从0到1:开启商业与未来的秘密》
  19. 教你破解隔壁妹子wifi密码,成功率高达90%
  20. 达内不建议我学python-交钱了,学了3天Python编程,我想放弃了......

热门文章

  1. 张量积的基的形象展示
  2. ROF系统的主要性能指标及概念和杂谈(佛系更新)
  3. centos7使用QQ邮箱发送邮件
  4. JAVA 解决 unable to find valid certification path to requested target 证书认证
  5. 今日小程序推荐:功夫拼图-爱TA就给TA拼
  6. Micro Focus :三大方案,助力Biogen收获九大成果
  7. pynlpir更新license Error: unable to fetch newest license解决方案
  8. Android--中国象棋
  9. 系统检测到您的访问行为异常 请正确输入以下验证码,验证通过后,可继续使用经验
  10. day2021-11-26(spring docker数据卷,自定义镜像)