OpenCV图像拼接改进算法之完美拼接
点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
前言概述
之前写了两篇文章分别是图像单应性矩阵变换与图像拼接,图像拼接中使用单应性矩阵实现图像特征对齐,从而为图像拼接特别是无缝拼接打下基础,看一下上一篇我的图像拼接效果如下:
经过分析发现:效果不好的原因是像素叠加的时候没有考虑左右两侧图像的位置信息,直接通过手动指定了融合区域跟阈值,而不是根据图像实际位置由图像生成mask层,根据mask层动态生成融合图像重叠区域的阈值,如此可以解决融合不够自然或者看上去拼接效果不好。最终改进之后的两张图像拼接效果如下:
是不是一个完美的无缝图像拼接我说了不算,大家说了算,欢迎留言反馈!
改进思路
想要完美的实现无缝拼接,有两个关键技术点:
特征提取与对齐阶段要取得配准对其好的单应性矩阵H,要用好的特征提取,千万别ORB。
拼接阶段融合,要有好的图像融合算法支持,别提金字塔融合,速度太感人了,所以最好一层搞定,间隔权重采样是个好方法。
之前的实现中图像对齐跟配准做的不错,就是最后的拼接效果不好,所以要改进图像融合,实现无缝融合。这里我观察了右侧图像透视变换的结果,发现一般都是一个不规则的图像,以我老家房屋的图像为例:对齐+透视变换之后如下:
生成的mask图像如下:
如果想要完美的融合,就不能随便制定区域融合,而是根据右侧透视变换之后的图像,来生成每一行有多少列是跟左侧图像重叠的,然后自动计算重叠区域大小,计算间隔值,完成最终mask权重图像生成,如下图:
代码实现与步骤
我是一个比较懒的人,代码已经有注释了,这里我就不过多解释,只简单说一下代码执行流程。
首先是图像特征提取与求单应性矩阵,这步可以省略了。代码可以参考上一篇文章即可。
使用单应性矩阵求得右侧变换之后的图像跟mask
根据mask得权重mask层
最后跟之前的一致,直接融合即可。
特征提取部分代码,参考之前文章,不写废话。融合部分,修改后的代码如下:
1// 获取全景图大小
2int h = max(left.rows, right.rows);
3int w = left.cols + right.cols;
4Mat panorama_01 = Mat::zeros(Size(w, h), CV_8UC3);
5Rect roi;
6roi.x = 0;
7roi.y = 0;
8roi.width = left.cols;
9roi.height = left.rows;
10
11// 获取左侧与右侧对齐图像
12left.copyTo(panorama_01(roi));
13Mat panorama_02;
14warpPerspective(right, panorama_02, H, Size(w, h));
15imwrite("D:/panorama_02.png", panorama_02);
16
17// 计算融合重叠区域mask
18Mat mask = Mat::zeros(Size(w, h), CV_8UC1);
19generate_mask(panorama_02, mask);
20
21// 创建遮罩层并根据mask完成权重初始化
22Mat mask1 = Mat::ones(Size(w, h), CV_32FC1);
23Mat mask2 = Mat::ones(Size(w, h), CV_32FC1);
24
25// left mask
26linspace(mask1, 1, 0, left.cols, mask);
27
28// right mask
29linspace(mask2, 0, 1, left.cols, mask);
30
31// 左侧融合
32Mat m1;
33vector<Mat> mv;
34mv.push_back(mask1);
35mv.push_back(mask1);
36mv.push_back(mask1);
37merge(mv, m1);
38panorama_01.convertTo(panorama_01, CV_32F);
39multiply(panorama_01, m1, panorama_01);
40
41// 右侧融合
42mv.clear();
43mv.push_back(mask2);
44mv.push_back(mask2);
45mv.push_back(mask2);
46Mat m2;
47merge(mv, m2);
48panorama_02.convertTo(panorama_02, CV_32F);
49multiply(panorama_02, m2, panorama_02);
50
51// 合并全景图
52Mat panorama;
53add(panorama_01, panorama_02, panorama);
54panorama.convertTo(panorama, CV_8U);
55imwrite("D:/panorama.png", panorama);
测试了一张图像,特征点匹配效果如下:
拼接融合之后图像:
说明是真的没问题了!(边上还有点黑的,可以直接裁了,比较懒了!)
好消息!
小白学视觉知识星球
开始面向外开放啦👇👇👇
下载1:OpenCV-Contrib扩展模块中文版教程 在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。 下载2:Python视觉实战项目52讲 在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。 下载3:OpenCV实战项目20讲 在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。 交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~