当前位置:   article > 正文

Opencv 实战五 图像拼接_cv2拼接图片

cv2拼接图片

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

  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))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
#执行
python main.py --images images/ --output output.png --crop 1
  • 1
  • 2

结果如下所示
在这里插入图片描述
有一说一opencv真的牛掰

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/81286?site
推荐阅读
相关标签
  

闽ICP备14008679号