赞
踩
图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。图像拼接原理主要涉及以下几个关键步骤:
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images",default='images', type=str, required=True,
help="path to input directory of images to stitch")
ap.add_argument("-o", "--output", default='output.png',type=str, required=True,
help="path to the output image")
ap.add_argument("-c", "--crop", type=int, default=0,
help="whether to crop out largest rectangular region")
args = vars(ap.parse_args()) # vars函数是实现返回对象object的属性和属性值的字典对象
print(args) # {'images': 'images/scottsdale', 'output': 'output.png', 'crop': 1}
# 匹配输入图像的路径并初始化我们的图像列表
# rectangular_region = 2
print("[INFO] loading images...")
# 获取到每张待拼接图像并排序,如['第一张图片路径', 第二张图片路径',第三张图片路径']
imagePaths = sorted(list(paths.list_images(args["images"])))
# print(imagePaths)
# imagePaths = ['IMG_1786-2.jpg',
# 'IMG_1787-2.jpg',
# 'IMG_1788-2.jpg']
images = []
# 遍历图像路径,加载每个路径,然后将它们添加到我们的路径中图像到stich列表
for imagePath in imagePaths:
image = cv2.imread(imagePath)
images.append(image)
# 初始化OpenCV的图像sticher对象,然后执行图像拼接
print("[INFO] stitching images...")
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
(status, stitched) = stitcher.stitch(images)
# print(status, stitched)
# 如果状态为“0”,则OpenCV成功执行图像拼接
if status == 0:
# 检查我们是否应该从拼接图像中裁剪出最大的矩形区域
if args["crop"] > 0:
# 在拼接图像周围创建一个10像素的黑色边框
print("[INFO] cropping...")
stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,
cv2.BORDER_CONSTANT, (0, 0, 0))
# cv2.imshow('123',stitched)
# 将拼接图像转换为灰度
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
# cv2.imshow('456', gray)
# 对灰度图像进行阈值二值化,
# 这样所有大于零的像素都设置为255(前景),而其他所有像素都保持为0(背景)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
# cv2.imshow('789', thresh)
# 在阈值图像中找到所有外部轮廓,然后找到 “最大 ”轮廓,它将是拼接图像的轮廓
# cv2.RETR_EXTERNAL:只找外轮廓。cv2.CHAIN_APPROX_SIMPLE:输出少量轮廓点
# 输出参数1:图像
# 输出参数2:轮廓列表
# 输出参数3:层级
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# print(cnts) #cnts包括三个数组:
# print(len(cnts))
cnts = imutils.grab_contours(cnts)
################################
# imutils.grab_contours 的源码 :
# # if the length the contours tuple returned by cv2.findContours
# # is '2' then we are using either OpenCV v2.4, v4-beta, or
# # v4-official
# if len(cnts) == 2:
# cnts = cnts[0]
# # if the length of the contours tuple is '3' then we are using
# # either OpenCV v3, v4-pre, or v4-alpha
# elif len(cnts) == 3:
# cnts = cnts[1]
# # otherwise OpenCV has changed their cv2.findContours return
# # signature yet again and I have no idea WTH is going on
# else:
# raise Exception(("Contours tuple must have length 2 or 3, "
# "otherwise OpenCV changed their cv2.findContours return "
# "signature yet again. Refer to OpenCV's documentation "
# "in that case"))
# # return the actual contours array
# return cnts
##################################
# 抓取具有最大区域的轮廓(即拼接图像本身的轮廓),cv2.contourArea是求轮廓面积
c = max(cnts, key=cv2.contourArea)
# print(c)
# print(c.shape)
# 为掩码分配内存,该掩码将包含拼接图像区域的矩形边界框
mask = np.zeros(thresh.shape, dtype="uint8")
# 计算出最大轮廓的边界框,使用边界矩形信息.使用 cv2.boundingRect(img) 函数,用一个最小的矩形,
# 把找到的形状包起来,img是一个二值图,也就是它的参数;返回四个值,分别是 x,y,w,h;
# 其中 x,y 是矩阵左上点的坐标,w,h 是矩阵的宽和高
(x, y, w, h) = cv2.boundingRect(c)
# 使用cv2.rectangle给图像加框,我们在mask上绘制一个纯白色矩形。
# 参数1:图像
# 参数2:左上角坐标
# 参数3:右下角坐标
# 参数4:框的颜色
# 参数5:框的粗细
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
# 创建掩码的两个副本
# 第一个mask,将逐渐缩小,直到它可以放入全景内部。
minRect = mask.copy()
# 第二个mask,将用于确定是否需要继续减小minRect的大小。
sub = mask.copy()
cv2.imshow('111',sub)
# 保持循环,直到sub中没有更多的前景像素
# 对二值化图像执行countNonZero。可得到非零像素点数(即外边框的像素点)
print(cv2.countNonZero(sub))
while cv2.countNonZero(sub) > 0:
# 执行侵蚀形态学操作以减小minRect的大小。
minRect = cv2.erode(minRect, None)
cv2.imshow('333',minRect)
# 从minRect中减去thresh ,一旦minRect中没有更多的前景像素,我们就可以从循环中断开
sub = cv2.subtract(minRect, thresh)
# 在最小矩形掩码中找到轮廓,然后提取边界框(x,y) - 坐标
cnts = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('444',cnts[0])
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
(x, y, w, h) = cv2.boundingRect(c)
# 使用边界框坐标来提取我们的最终拼接图像
stitched = stitched[y:y + h, x:x + w]
# 将输出拼接图像写入磁盘
cv2.imwrite("result.jpg", stitched)
# 将输出拼接图像显示到我们的屏幕
cv2.imshow("Stitched", stitched)
cv2.waitKey(0)
# 否则,拼接失败,可能是由于检测不到足够的关键点
else:
print("[INFO] image stitching failed ({})".format(status))
#执行
python main.py --images images/ --output output.png --crop 1
结果如下所示
有一说一opencv真的牛掰
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。