Opencv 实战五 图像拼接

图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。图像拼接原理主要涉及以下几个关键步骤:

  1. 特征提取:在拼接图像之前,首先需要在每张图像中提取一些特征点,这些特征点在图像中有明显的可识别的独特性,例如角点、边缘等。OpenCV 提供了一些特征提取算法,如 SIFT (Scale-Invariant Feature Transform)、SURF (Speeded-Up Robust Features) 和 ORB (Oriented FAST and Rotated BRIEF) 等。
  2. 特征匹配:一旦从图像中提取了特征点,接下来的步骤是将两张图像之间的对应特征点进行匹配。这可以通过一些匹配算法,如最近邻算法 (Nearest Neighbor) 或 k-最近邻算法 (k-Nearest Neighbors) 来实现。
  3. 计算图像变换:特征匹配后,可以通过计算图像间的变换矩阵,例如仿射变换或透视变换,将两张图像对齐。这个变换矩阵描述了如何将一个图像上的点映射到另一个图像上的对应点。
  4. 图像拼接:一旦得到了图像间的变换矩阵,就可以将两张图像拼接成一张更大的图像。在拼接时,可以通过一些图像融合算法,如线性融合或像素融合,来平滑处理图像之间的过渡区域,使拼接结果看起来更自然。
    下面用opencv实现一下多张图像进行拼接如下图所示,三张不同角度的图像最终拼接成一张全视角的图像
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
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真的牛掰

  • 11
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论
OpenCV是一种开源计算机视觉库,可用于处理和分析图像,包括多图片拼接。多图片拼接是将多幅图片按照一定的规则和算法进行连接,形成一幅更大尺寸或更全面的图像。 在使用OpenCV进行多图片拼接时,首先需要将待拼接图片加载到内存或者直接从摄像头获取图片。然后,根据需求选择适当的拼接算法,常见的拼接算法有简单的拼接、特征点匹配、全景拼接等。 在进行拼接之前,需要对图片进行一些预处理,例如调整图片的尺寸、均衡化图像的直方图、去噪等。这些预处理操作有助于提高拼接的效果和质量。 拼接过程中,关键的一步是特征点匹配。特征点是图像中具有辨识度和重复性的显著性点,通过对图像中的特征点进行匹配,可以确定图片之间的对应关系,从而进行拼接OpenCV提供了一些特征点检测和匹配的算法,例如SIFT、SURF、ORB等。 在特征点匹配之后,需要进行图像的几何变换以及重叠区域的融合。常见的图像变换方法有仿射变换、透视变换等,这些变换可以根据特征点的位置和匹配关系将图片进行对齐和变换。融合过程中,可以使用像素级别的混合、渐变融合等技术,将不同图片的重叠区域进行平滑地过渡。 最后,通过OpenCV提供的图像保存函数,将拼接好的图像保存到文件或者显示在屏幕上。 总结来说,使用OpenCV进行多图片拼接需要加载图片、进行预处理、特征点匹配、几何变换、重叠区域融合等步骤。通过合理选择算法和参数,可以得到较好的拼接效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VisionX Lab

你的鼓励将是我更新的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值