OpenCV笔记(6)实现简单的泊松融合

1.泊松融合梳理:

      图像融合是图像处理的一个基本问题,目的是将源图像中一个物体或者一个区域嵌入到目标图像生成一个新的图像。在对图像进行合成的过程中,为了使合成后的图像更自然,合成边界应当保持无缝。但如果源图像和目标图像有着明显不同的纹理特征,则直接合成后的图像会存在明显的边界。

      针对这个问题,有人提出了一种利用构造泊松方程求解像素最优值的方法,在保留了源图像梯度信息的同时,融合源图像与目标图像。该方法根据用户指定的边界条件求解一个泊松方程,实现了梯度域上的连续,从而达到边界处的无缝融合。

      总的来说,将泊松方程引入图像融合后,接下来的操作很容易在梯度域中进行应用,并且可以通过局部的图像编辑得到全局融合的效果。我们都知道,图像梯度的最重要性质是梯度可以用来反映图像中亮度改变最明显的区域,也就是说可以用梯度来捕捉图像上的亮度变化,梯度的方向在图像灰度的最大变化率上,它恰好可以反映出图像边缘的灰度变化。因此,要实现无缝融合,下面两点一定要满足:

      (1)边缘过渡要平滑,就是说梯度要小;

      (2)感兴趣区域内部的自身纹理要最大程度的保留;


      接下来具体分析,以下图为例。

      

      u是源图像被合成的部分,V是u的梯度场,S是合并后的图像,Ω是合并后被覆盖掉的区域,∂Ω是边界,Ω内的像素由f表示,外面的像素由f*表示。

      第一,合并后的图像看上去尽可能的平滑,没有明显的边界,所以Ω内的梯度值要尽可能的小。

      因此,f的值由下式确定:

       

      被积函数为:

      

      代入二维拉格朗日方程:

      

      化简,得:

      

      因此:

      


      第二,需要满足调整以后的图像仍能维持原图像的纹理信息,边界处无明显痕迹。表示为下式:

      

      为了让融合结果中的Ω无限趋近u,这里需要有指引的梯度场V,当融合后的图像内的f与u的梯度信息越相似,就说明原始纹理保持的越好,融合的效果越好。此时的被积函数:

      

      代入拉格朗日方程:

      

      于是得到:

      

      结合散度和拉普拉斯的概念:

      

      又因为:

      

      所以可以化简原式为泊松方程形式:

      


      上面是把泊松方程引入到图像融合中所做的一些公式推导,那么泊松融合的具体流程是什么,我们要总结一下。

      首先计算背景图像和目标图像的梯度场。

      计算完毕后,接下来把目标图像的梯度场覆盖到背景图像的梯度场上,求得融合图像的梯度场。

      接下来求融合图像的散度,已知融合图像的梯度场,求散度只需求导即可。

      最后,进行泊松重建,求解泊松方程组:Ax=b。A是构建的系数矩阵,b是散度值,x是融合图像的像素值,求解得到x之后就能重建融合图像。


2.代码实现:

      opencv把泊松融合集成在了函数seamlessClone里。

void seamlessClone(InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags);

      src:源文件;

      dst:目标文件;

      mask:源文件的mask文件;

      p:src要在dst上摆放的位置;

      blend:输出的融合图像;

      flags:融合的方式,默认为NORMAL_CLONE;

      融合方式共有三个,分别是NORMAL_CLONE,MIXED_CLONE,FEATURE_EXCHANGE。


      测试例:

#include <stdio.h>
#include <time.h>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	clock_t start1, end1;
	clock_t start2, end2;

	Mat src = imread("ROI_img.jpg");
	Mat dst = imread("bg_img.jpg ");

	Mat src_mask = 255 * Mat::ones(src.rows, src.cols, src.depth());
	Point center(dst.cols / 2, dst.rows / 2);

	Mat normal_clone;
	Mat mixed_clone;

	start1 = clock();
	seamlessClone(src, dst, src_mask, center, normal_clone, NORMAL_CLONE);
	end1 = clock();

	start2 = clock();
	seamlessClone(src, dst, src_mask, center, mixed_clone, MIXED_CLONE);
	end2 = clock();

	printf("NORMAL_CLONE use time: %d\n", end1 - start1);
	printf("MIXED_CLONE use time: %d\n", end2 - start2);

	imshow("ROI_img", src);
	imshow("bg_img", dst);
	imshow("normal_clone", normal_clone);
	imshow("mixed_clone", mixed_clone);
	waitKey(0);

	return 1;
}

      源图像src:

      

      目标图像dst:

      

      运行结果:

      

      NORMAL_CLONE,最常用的方法:

      

      MIXED_CLONE:

      

      在这个测试例中,MIXED_CLONE的效果要好于NORMAL_CLONE,MIXED_CLONE运行的时间更短,且NORMAL_CLONE中,飞机周围的云层被改变,融合效果不太好。总的来说,泊松融合后,边界问题可以很好的解决。




参考链接:https://blog.csdn.net/hjimce/article/details/45716603

                 https://blog.csdn.net/ZJU_fish1996/article/details/72760571

                 https://blog.csdn.net/baimafujinji/article/details/6485778

参考书籍:《图像处理中的数学修炼》

  

全部评论

相关推荐

最近和朋友聊天,她说了句让我震惊的话:"我发现我连周末点外卖都开始'最优解'了,一定要赶在高峰期前下单,不然就觉得自己亏了。"这不就是典型的"班味入侵"吗?工作思维已经渗透到生活的方方面面。
小型域名服务器:啊?我一直都这样啊?我还以为是我爱贪小便宜呢?每次去实验室都得接一杯免费的开水回去,出门都得规划一下最短路径,在宿舍就吃南边的食堂,在实验室就吃北边的食堂,快递只有顺路的时候才取。
点赞 评论 收藏
分享
粗心的雪碧不放弃:纯学历问题,我这几个月也是一直优化自己的简历,后来发现优化到我自己都觉得牛逼的时候,发现面试数量也没有提升,真就纯学历问题
点赞 评论 收藏
分享
10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
点赞 2 评论
分享
牛客网
牛客企业服务