-
函数介绍
-
图像拼接算法实现
-
图像拼接算法改进
Image Stitching with OpenCV and Python - PyImageSearchwww.pyimagesearch.com
本文参考上面这个链接,实现多张图像的拼接,构建一张全景图。
根据多个图像创建全景图的步骤为:
-
检测两张图像的关键点特征(DoG、Harris等)
-
计算不变特征描述符(SIFT、SURF或ORB等)
-
根据关键点特征和描述符,对两张图像进行匹配,得到若干匹配点对,并移除错误匹配;
-
使用Ransac算法和匹配的特征来估计单应矩阵(homography matrix);
-
通过单应矩阵来对图像进行仿射变换;
-
两图像拼接,重叠部分融合;
-
裁剪以获得美观的最终图像。
原理比较复杂,本文先不讲解,OpenCV中已经实现了全景图拼接的算法,它们是
cv2.createStitcher
(OpenCV 3.x) 和
cv2.Stitcher_create
(OpenCV 4) 。
该算法对以下条件具有较好的鲁棒性:
一、函数介绍
OpenCV 3.x 的 cv2.createStitcher 函数原型为:
createStitcher(...)
createStitcher([, try_use_gpu]) -> retval
这个函数有一个参数
try_use_gpu
,它可以用来提升图像拼接整个过程的速度。
OpenCV 4 的 cv2.Stitcher_create 函数原型为:
Stitcher_create(...)
Stitcher_create([, mode]) -> retval
. @brief Creates a Stitcher configured in one of the stitching
. modes.
. @param mode Scenario for stitcher operation. This is usually
. determined by source of images to stitch and their transformation.
. Default parameters will be chosen for operation in given scenario.
. @return Stitcher class instance.
要执行实际的图像拼接,我们需要调用
.stitch
方法:
OpenCV 3.x:
stitch(...) method of cv2.Stitcher instance
stitch(images[, pano]) -> retval, pano
OpenCV 4.x:
stitch(...) method of cv2.Stitcher instance
stitch(images, masks[, pano]) -> retval, pano
. @brief These functions try to stitch the given images.
. @param images Input images.
. @param masks Masks for each input image specifying where to
. look for keypoints (optional).
. @param pano Final pano.
. @return Status code.
该方法接收一个图像列表,然后尝试将它们拼接成全景图像,并进行返回。
变量
status=0
表示图像拼接是否成功。
二、图像拼接算法实现
先把三张图片读取出来存放到列表里:
img_dir = 'pictures/stitching'
names = os.listdir(img_dir)
images = []
for name in names:
img_path = os.path.join(img_dir, name)
image = cv2.imread(img_path)
images.append(image)
图片顺序没有影响,我试了一下,不同的图片顺序,输出全景图都相同。
然后构造图像拼接对象
stitcher
, 要注意的是,OpenCV 3 和 4 的构造器是不同的。
import imutils
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
再把图像列表传入
.stitch
函数,该函数会返回状态和拼接好的全景图(如果没有错误):
status, stitched = stitcher.stitch(images)
完整代码如下:
import os
import cv2
import imutils
img_dir = 'pictures/stitching'
names = os.listdir(img_dir)
images = []
for name in names:
img_path = os.path.join(img_dir, name)
image = cv2.imread(img_path)
images.append(image)
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
status, stitched = stitcher.stitch(images)
if status==0:
cv2.imwrite('pictures/stitch.jpg', stitched)
OpenCV真的很强大,这短短几行,就实现了拼接全景图。
全景图如下:
images.append(image)
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
status, stitched = stitcher.stitch(images)
在全景图四周各添加10像素宽的黑色边框,以确保能够找到全景图的完整轮廓:
stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,
cv2.BORDER_CONSTANT, (0, 0, 0))
再将全景图转换为灰度图,并将不为0的像素全置为255,作为前景,其他像素灰度值为0,作为背景。
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
注:和轮廓相关的详细讲解可以查看 这篇文章。
cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(cnts, key=cv2.contourArea) # 获取最大轮廓
mask = np.zeros(thresh.shape, dtype="uint8")
x, y, w, h = cv2.boundingRect(cnt)
# 绘制最大外接矩形框(内部填充)
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
这个白色矩形框是整个全景图可以容纳下的最小矩形区域。
接下来就是最难,也是最巧妙的部分了,先创建mask的两个副本:
-
minRect
,这个mask的白色区域会慢慢缩小,直到它刚好可以完全放入全景图内部。
-
sub
,这个mask用于确定
minRect
是否需要继续减小,以得到满足要求的矩形区域。
minRect = mask.copy()
sub = mask.copy()
# 开始while循环,直到sub中不再有前景像素
while cv2.countNonZero(sub) > 0:
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
不断地对
minRect
进行腐蚀操作,然后用
minRect
减去之前得到的阈值图像,得到
sub
,
再判断
sub
中是否存在非零像素,如果不存在,则此时的
minRect
就是我们最终想要的全景图内部最大矩形区域。
sub
和
minRect
在while循环中的变化情况如下动图所示:
因为OpenCV中灰度图像素值范围0-255,如果两个数相减得到负数的话,会直接将其置为0;如果两个数相加,结果超过了255的话,则直接置为255。
比如下面这个图,左图中白色矩形可以完全包含在全景图中,但不是全景图的最大内接矩形,用它减去右边的阈值图,
因为黑色像素减白色像素,会得到黑色像素,所以其结果图为全黑的图。
所以上面那个while循环最终得到的
minRect
就是减去阈值图得到全黑图的面积最大的矩形区域。
好了,我们已经得到全景图的内置最大矩形框了,接下来就是找到这个矩形框的轮廓,并获取其坐标:
cnts, hierarchy = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(cnts, key=cv2.contourArea)
# 计算最大轮廓的边界框
(x, y, w, h) = cv2.boundingRect(cnt)
# 使用边界框坐标提取最终的全景图
stitched = stitched[y:y + h, x:x + w]
得到最终结果图如下:
images.append(image)
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
status, stitched = stitcher.stitch(images)
# 四周填充黑色像素,再得到阈值图
stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10, cv2.BORDER_CONSTANT, (0, 0, 0))
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(cnts, key=cv2.contourArea)
mask = np.zeros(thresh.shape, dtype="uint8")
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
minRect = mask.copy()
sub = mask.copy()
# 开始while循环,直到sub中不再有前景像素
while cv2.countNonZero(sub) > 0:
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
cnts, hierarchy = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(cnts, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(cnt)
# 使用边界框坐标提取最终的全景图
stitched = stitched[y:y + h, x:x + w]
cv2.imwrite('final.jpg', stitched)
如果觉得有用,就点个赞吧(ง •̀_•́)ง。
目录:函数介绍图像拼接算法实现图像拼接算法改进Image Stitching with OpenCV and Python - PyImageSearchwww.pyimagesearch.com本文参考上面这个链接,实现多张图像的拼接,构建一张全景图。根据多个图像创建全景图的步骤为:检测两张图像的关键点特征(DoG、Harris等)计算不变特征描述符(SIFT、SURF或ORB等)根据关键点特...
opencv
_python Stitcher
拼接
图像
实例(SIFT/SURF检测特征点,BF/FLANN匹配特征点)
SIFI/SURF检测特征点,BF/FLANN匹配特征点,stitch缝接图片,并进行视角变换。
先创建一个Stitcher类:
import numpy as np
import cv2
class Stitcher:
#
拼接
函数
def stitch(se...
图像拼接
技术就是将数张有重叠部分的
图像
(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的
全景图
或高分辨率
图像
的技术。
下面用
opencv
实现一下多张
图像
进行
拼接
如下图所示,三张不同角度的
图像
最终
拼接
成一张全视角的
图像
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
先直接上代码,文末会有具体分析,代码也有相应注释。
本文是以三张图片横向排列
拼接
为例 ,其他的也是类似
IplImage*paletteImageRam1,paletteImageRam2,paletteImageRam3; //此处是定义了三个图片,实际使用时应当载入自己的三幅图片
//将三个图片
拼接
在一起 double width,height;...
分别将两张图片对应的关键点求出,并将每个关键点对应的特征向量描述出来。
对两幅
图像
的关键点进行特征匹配(这里使用BF-knn方法进行匹配)
利用RANSAC方法对匹配好的关键点进行筛选,计算出单应性矩阵H
对配对的结果可视化。
利用H将
图像
A进行投影变换,将变换后的
图像
A的大小设定为A,B
拼接
好以后
图像
的大小
将
图像
B
拼接
在
图像
A空缺的地方,完成
拼接
。
求关键点和特征向量
def detectAndDescribe(s
OpenCV
常用
图像拼接
方法将分为四个部分与大家共享,这里是第四种方法,至此四种常用方法介绍完毕。
OpenCV
的常用
图像拼接
方法(四):基于
OpenCV
Stitcher类的
图像拼接
,
OpenCV
版本为4.4.0。特点和适用范围:
图像
需有足够重合相同特征区域。优点:适应部分倾斜/尺度变换和畸变情形,
拼接
效果好,使用简单,可以一次
拼接
多张图片。缺点:需要有足够的相同特征区域进行匹配,速度较慢(和
图像
大小有关,可以使用GPU加速)。
如下是待
拼接
的两张图片:
#include "
opencv
2/imgcodecs.hpp"
#include "
opencv
2/highgui.hpp"
#include "
opencv
2/stitching.hpp"
#include
图像拼接
(Image Stitching)是一种利用实景
图像
组成全景空间的技术,它将多幅
图像拼接
成一幅大尺度
图像
或360度
全景图
,接可以看做是场景重建的一种特殊情况,其中
图像
仅通过平面单应性进行关联。
图像拼接
在运动检测和跟踪,增强现实,分辨率增强,视频压缩和
图像
稳定等机器视觉领域有很大的应用。
图像拼接
的输出是
两个
输入
图像
的并集。通常用到四个步骤:
特征提取(Feature Extraction):检测输入
图像
中的特征点。
图像
配准(Image Registration):建立了
图像
之间的几何对应关系
#include <
opencv
2/core/core.hpp>
#include <
opencv
2/highgui/highgui.hpp>
#include "img
proc
/img
proc
.hpp"
#include <
opencv
2/features2d/features2d.hpp>
#incl...
参考大神的帖子:
使用
OpenCV
3进行SURF特征提取和暴力匹配代码详解:https://blog.csdn.net/zilanpotou182/article/details/68061929
OpenCV
探索之路(二十四)
图像拼接
与
图像
融合技术:http://www.cnblogs.com/skyfsm/p/7411961.html
最终完整代码如下:
#include <i...
Images stitching 是
opencv
3.4.0中的模块之一,使用此模块可以实现对
图像
的
拼接
。在此之前需要编译
opencv
3.4.0+contrib。具体编译方法可以点此链接。也可以直接下载我编译好的
opencv
340+contrib的文件直接配置,配置方法与
opencv
一样。
具体内容可以参考sitiching的官方帮助文档。
Image Stitching 模块下共包...
OpenCV
3中提供了一个用于
图像拼接
的模块——Stitcher,可以将连续拍摄的
图像
序列,
拼接
成一幅全景画面。如下所示是56幅连续拍摄的
图像
:0.png1.png2.png3.png4.png处理代码如下:#include < stdio.h >
#include <
opencv
2\
opencv
.hpp >
#include <
opencv
2\stitc...