文章目录
- 一、Pyimagesearch的代码汇总
- 二、Github代码汇总
- 1.SSARCandy/panoramas-image-stitching
- 2.TejasBob/Panorama
- 3.TejasNaikk/Image-Alignment-and-Panoramas
- 4.fuenwang/Equirec2Perspec
- 5. avinashk442/Panoramic-Image-Stitching-using-invariant-features(同pyimagesearch中的Image Stitcing with OpenCV and Python)
- 6.samggggflynn/panorama-stitching(同pyimagesearch中的OpenCV panorama stitching)
- 7.FlagArihant2000/CylPanorama
- 8.andrewmagdyanis/PanoramaCreator-image_stitching-
- 9.WillBrennan/ImageStitching
- 10.kushalvyas/Python-Multiple-Image-Stitching
- 11.znliunwpugmail/sift_cv
- 12.creimers/real-time-image-stitching
- 13.sakshikakde
- 14.h-gokul
提示:以下是本篇文章正文内容,下面案例可供参考
一、Pyimagesearch的代码汇总
1.OpenCV panorama stitching,2016年1月11日
使用Python和OpenCV进行图像拼接和全景图构建。给定两张图片,将它们“缝合”在一起形成一个简单的全景图。
介绍了全景图像拼接的4个步骤:
步骤1:从两个输入图像中检测关键点(DoG, Harris等)和提取局部不变描述符(SIFT, SURF等)。
步骤2:匹配两个图像之间的描述符。
步骤3:使用RANSAC算法估计我们匹配的特征向量的单应矩阵。
步骤4:使用从步骤3得到的单应矩阵应用翘曲变换。
代码:在panorama.py中封装上述四个步骤,并且定义了一个用于构造全景图的Stitcher类。在stitch.py中,我们调用panorama.py中的Stitcher类,完成拼接
2.Image Stitcing with OpenCV and Python, 2018年12月17日
网址:https://www.pyimagesearch.com/2018/12/17/image-stitching-with-opencv-and-python/
中文翻译版:https://blog.csdn.net/learning_tortosie/article/details/85083825?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162683446416780255241191%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162683446416780255241191&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-4-85083825.first_rank_v2_pc_rank_v29&utm_term=cv2.createStitcher%28%29+%E5%92%8C+cv2.Stitcher_create%28%29+&spm=1018.2226.3001.4187
内容:
学习如何使用Python、OpenCV和cv2.createStitcher以及 cv2.Stitcher_create来执行图像拼接。使用这个代码,可以将多个图像拼接在一起,创建一个拼接图像的全景。
图像拼接算法步骤图:https://www.pyimagesearch.com/wp-content/uploads/2018/12/image_stitching_opencv_pipeline.png
代码参考论文:Automatic Panorama Image Stitching with Invariant Features,论文地址:http://matthewalunbrown.com/papers/ijcv2007.pdf
在GitHub上实现这篇论文的代码如下:avinashk442/Panoramic-Image-Stitching-using-invariant-features
网址:https://github.com/avinashk442/Panoramic-Image-Stitching-using-invariant-features
论文介绍:
不同于以往的图像拼接算法对输入图像的顺序敏感,Automatic Panorama Image Stitching with Invariant Features方法鲁棒性更强,对以下情况不敏感:
· 图片的顺序
· 方向的图片
· 光照变化
· 噪声图像不是全景图的一部分
代码:
image_stitching_simple.py
# run code
# python image_stitching_simple.py --images images/scottsdale --output output.png
# import the necessary packages
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", type=str, required=True,
help="path to input directory of images to stitch")
ap.add_argument("-o", "--output", type=str, required=True,
help="path to the output image")
args = vars(ap.parse_args())
# grab the paths to the input images and initialize our images list
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(args["images"])))
images = []
# loop over the image paths, load each one, and add them to our
# images to stitch list
for imagePath in imagePaths:
image = cv2.imread(imagePath)
images.append(image)
# initialize OpenCV's image stitcher object and then perform the image
# stitching
print("[INFO] stitching images...")
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
(status, stitched) = stitcher.stitch(images)
# if the status is '0', then OpenCV successfully performed image
# stitching
if status == 0:
# write the output stitched image to disk
cv2.imwrite(args["output"], stitched)
# display the output stitched image to our screen
cv2.imshow("Stitched", stitched)
cv2.waitKey(0)
# otherwise the stitching failed, likely due to not enough keypoints)
# being detected
else:
print("[INFO] image stitching failed ({})".format(status))
image_stitching.py
# run code
# python image_stitching.py --images images/scottsdale --output output.png --crop 1
# import the necessary packages
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", type=str, required=True,
help="path to input directory of images to stitch")
ap.add_argument("-o", "--output", 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())
# grab the paths to the input images and initialize our images list
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(args["images"])))
images = []
# loop over the image paths, load each one, and add them to our
# images to stich list
for imagePath in imagePaths:
image = cv2.imread(imagePath)
images.append(image)
# initialize OpenCV's image sticher object and then perform the image
# stitching
print("[INFO] stitching images...")
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
(status, stitched) = stitcher.stitch(images)
# if the status is '0', then OpenCV successfully performed image
# stitching
if status == 0:
# check to see if we supposed to crop out the largest rectangular
# region from the stitched image
if args["crop"] > 0:
# create a 10 pixel border surrounding the stitched image
print("[INFO] cropping...")
stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,
cv2.BORDER_CONSTANT, (0, 0, 0))
# convert the stitched image to grayscale and threshold it
# such that all pixels greater than zero are set to 255
# (foreground) while all others remain 0 (background)
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
# find all external contours in the threshold image then find
# the *largest* contour which will be the contour/outline of
# the stitched image
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
# allocate memory for the mask which will contain the
# rectangular bounding box of the stitched image region
mask = np.zeros(thresh.shape, dtype="uint8")
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
# create two copies of the mask: one to serve as our actual
# minimum rectangular region and another to serve as a counter
# for how many pixels need to be removed to form the minimum
# rectangular region
minRect = mask.copy()
sub = mask.copy()
# keep looping until there are no non-zero pixels left in the
# subtracted image
while cv2.countNonZero(sub) > 0:
# erode the minimum rectangular mask and then subtract
# the thresholded image from the minimum rectangular mask
# so we can count if there are any non-zero pixels left
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
# find contours in the minimum rectangular mask and then
# extract the bounding box (x, y)-coordinates
cnts = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
(x, y, w, h) = cv2.boundingRect(c)
# use the bounding box coordinates to extract the our final
# stitched image
stitched = stitched[y:y + h, x:x + w]
# write the output stitched image to disk
cv2.imwrite(args["output"], stitched)
# display the output stitched image to our screen
cv2.imshow("Stitched", stitched)
cv2.waitKey(0)
# otherwise the stitching failed, likely due to not enough keypoints)
# being detected
else:
print("[INFO] image stitching failed ({})".format(status))
运行代码:
image_stitching_simple.py:python image_stitching_simple.py --images images/scottsdale –output output.png
image_stitching.py:python image_stitching.py --images images/scottsdale –output output.png –crop 1
3.Real-time panorama and image stitching with OpenCV, 2016年1月25日
网址:https://www.pyimagesearch.com/2016/01/25/real-time-panorama-and-image-stitching-with-opencv/
内容:
参考了Multiple cameras with the Raspberry Pi and OpenCV的代码,网址:https://www.pyimagesearch.com/2016/01/18/multiple-cameras-with-the-raspberry-pi-and-opencv/
使用OpenCV实现实时全景和图像拼接。
使用我们改进的FPS处理速率的Python类来访问我们的内置/USB网络摄像头和/或树莓派摄像头模块。
1、一次访问多个摄像机流。
2、对这些视频流中的帧应用图像拼接和全景构建。
3、在全景图像中执行运动检测。
代码:
代码的结构
|— pyimagesearch
| |---- init.py
| |— basicmotiondetector.py
| |— panorama.py
|— realtime_stitching.py
# panorama images
# import the necessary packages
import numpy as np
import imutils
import cv2
class Stitcher:
def __init__(self):
# determine if we are using OpenCV v3.X and initialize the
# cached homography matrix
self.isv3 = imutils.is_cv3()
self.cachedH = None
def stitch(self, images, ratio=0.75, reprojThresh=4.0):
# unpack the images
(imageB, imageA) = images
# if the cached homography matrix is None, then we need to
# apply keypoint matching to construct it
if self.cachedH is None:
# detect keypoints and extract
(kpsA, featuresA) = self.detectAndDescribe(imageA)
(kpsB, featuresB) = self.detectAndDescribe(imageB)
# match features between the two images
M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)
# if the match is None, then there aren't enough matched
# keypoints to create a panorama
if M is None:
return None
# cache the homography matrix
self.cachedH = M[1]
# apply a perspective transform to stitch the images together
# using the cached homography matrix
result = cv2.warpPerspective(imageA, self.cachedH,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
# return the stitched image
return result
def detectAndDescribe(self, image):
# convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# check to see if we are using OpenCV 3.X
if self.isv3:
# detect and extract features from the image
descriptor = cv2.xfeatures2d.SIFT_create()
(kps, features) = descriptor.detectAndCompute(image, None)
# otherwise, we are using OpenCV 2.4.X
else:
# detect keypoints in the image
detector = cv2.FeatureDetector_create("SIFT")
kps = detector.detect(gray)
# extract features from the image
extractor = cv2.DescriptorExtractor_create("SIFT")
(kps, features) = extractor.compute(gray, kps)
# convert the keypoints from KeyPoint objects to NumPy
# arrays
kps = np.float32([kp.pt for kp in kps])
# return a tuple of keypoints and features
return (kps, features)
def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB,
ratio, reprojThresh):
# compute the raw matches and initialize the list of actual
# matches
matcher = cv2.DescriptorMatcher_create("BruteForce")
rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
matches = []
# loop over the raw matches
for m in rawMatches:
# ensure the distance is within a certain ratio of each
# other (i.e. Lowe's ratio test)
if len(m) == 2 and m[0].distance < m[1].distance * ratio:
matches.append((m[0].trainIdx, m[0].queryIdx))
# computing a homography requires at least 4 matches
if len(matches) > 4:
# construct the two sets of points
ptsA = np.float32([kpsA[i] for (_, i) in matches])
ptsB = np.float32([kpsB[i] for (i, _) in matches])
# compute the homography between the two sets of points
(H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC,
reprojThresh)
# return the matches along with the homograpy matrix
# and status of each matched point
return (matches, H, status)
# otherwise, no homograpy could be computed
return None
def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):
# initialize the output visualization image
(hA, wA) = imageA.shape[:2]
(hB, wB) = imageB.shape[:2]
vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
vis[0:hA, 0:wA] = imageA
vis[0:hB, wA:] = imageB
# loop over the matches
for ((trainIdx, queryIdx), s) in zip(matches, status):
# only process the match if the keypoint was successfully
# matched
if s == 1:
# draw the match
ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
cv2.line(vis, ptA, ptB, (0, 255, 0), 1)
# return the visualization
return vis
realtime_stitching.py
# realtime_stitching.py
# import the necessary packages
from __future__ import print_function
from basicmotiondetector import BasicMotionDetector
from panorama import Stitcher
from imutils.video import VideoStream
import numpy as np
import datetime
import imutils
import time
import cv2
# initialize the video streams and allow them to warmup
print("[INFO] starting cameras...")
# leftStream是一个USB摄像头,rightStream是一个树莓派摄像头
leftStream = VideoStream(src=0).start()
rightStream = VideoStream(usePiCamera=True).start()
# # 使用两个USB摄像头时,初始化如下
# leftStream = VideoStream(src=0).start()
# rightStream = VideoStream(src=1).start()
time.sleep(2.0)
# initialize the image stitcher, motion detector, and total
# number of frames read
stitcher = Stitcher()
motion = BasicMotionDetector(minArea=500)
total = 0
# loop over frames from the video streams
while True:
# grab the frames from their respective video streams
left = leftStream.read()
right = rightStream.read()
# resize the frames
left = imutils.resize(left, width=400)
right = imutils.resize(right, width=400)
# stitch the frames together to form the panorama
# IMPORTANT: you might have to change this line of code
# depending on how your cameras are oriented; frames
# should be supplied in left-to-right order
result = stitcher.stitch([left, right])
# no homograpy could be computed
if result is None:
print("[INFO] homography could not be computed")
break
# convert the panorama to grayscale, blur it slightly, update
# the motion detector
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
locs = motion.update(gray)
# only process the panorama for motion if a nice average has
# been built up
if total > 32 and len(locs) > 0:
# initialize the minimum and maximum (x, y)-coordinates,
# respectively
(minX, minY) = (np.inf, np.inf)
(maxX, maxY) = (-np.inf, -np.inf)
# loop over the locations of motion and accumulate the
# minimum and maximum locations of the bounding boxes
for l in locs:
(x, y, w, h) = cv2.boundingRect(l)
(minX, maxX) = (min(minX, x), max(maxX, x + w))
(minY, maxY) = (min(minY, y), max(maxY, y + h))
# draw the bounding box
cv2.rectangle(result, (minX, minY), (maxX, maxY),
(0, 0, 255), 3)
# increment the total number of frames read and draw the
# timestamp on the image
total += 1
timestamp = datetime.datetime.now()
ts = timestamp.strftime("%A %d %B %Y %I:%M:%S%p")
cv2.putText(result, ts, (10, result.shape[0] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)
# show the output images
cv2.imshow("Result", result)
cv2.imshow("Left Frame", left)
cv2.imshow("Right Frame", right)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# do a bit of cleanup
print("[INFO] cleaning up...")
cv2.destroyAllWindows()
leftStream.stop()
rightStream.stop()
basicmotiondetector.py
# import the necessary packages
import imutils
import cv2
class BasicMotionDetector:
def __init__(self, accumWeight=0.5, deltaThresh=5, minArea=5000):
# determine the OpenCV version, followed by storing the
# the frame accumulation weight, the fixed threshold for
# the delta image, and finally the minimum area required
# for "motion" to be reported
self.isv2 = imutils.is_cv2()
self.accumWeight = accumWeight
self.deltaThresh = deltaThresh
self.minArea = minArea
# initialize the average image for motion detection
self.avg = None
def update(self, image):
# initialize the list of locations containing motion
locs = []
# if the average image is None, initialize it
if self.avg is None:
self.avg = image.astype("float")
return locs
# otherwise, accumulate the weighted average between
# the current frame and the previous frames, then compute
# the pixel-wise differences between the current frame
# and running average
cv2.accumulateWeighted(image, self.avg, self.accumWeight)
frameDelta = cv2.absdiff(image, cv2.convertScaleAbs(self.avg))
# threshold the delta image and apply a series of dilations
# to help fill in holes
thresh = cv2.threshold(frameDelta, self.deltaThresh, 255,
cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
# find contours in the thresholded image, taking care to
# use the appropriate version of OpenCV
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# loop over the contours
for c in cnts:
# only add the contour to the locations list if it
# exceeds the minimum area
if cv2.contourArea(c) > self.minArea:
locs.append(c)
# return the set of locations
return locs
运行代码:
python realtime_stitching.py
注意:OpenCV版本之间的区别
cv2.createStitcher() —— OpenCV 3.X
cv2.Stitcher_create() —— OpenCV 4.X
对于cv2.createStitcher([, try_use_gpu])函数,它仅仅只有一个参数 try_use_gpu,一般情况下默认设置为False。
对于cv2.Stitcher_create([,model]) 函数,需要参数 mode,返回一个 Stitcher 类。
二、Github代码汇总
1.SSARCandy/panoramas-image-stitching
代码链接
功能:拼接一个文件夹中的所有图片,形成一个全景图。难点在于focal_length的确定,会导致拼接的效果不好。
运行代码:python main.py 输入图像文件夹
2.TejasBob/Panorama
代码链接
功能:从视频中截取视频帧,然后自动的完成拼接全景图。
运行代码:python test.py --choice <1-5>
代码参考文献:
1、Image Alignment and Stitching: A Tutorial
2、Automatic Panoramic Image Stitching using Invariant Features 论文
3.TejasNaikk/Image-Alignment-and-Panoramas
代码链接
功能:使用拉普拉斯混合将不同的透视图像拼接成一个平滑的全景图。用单形变换和仿射变换分别创建透视和圆柱翘曲。然后对图像的SIFT特征描述符进行匹配和混合,形成单一的全景视图。
相同代码:SwethasriKavuri/Image-Stitching-Panorama,代码链接地址
运行代码:直接运行
4.fuenwang/Equirec2Perspec
功能:Equirec2Perspec是一个python工具,可以将等角全景分割成普通透视视图。输入是一个360°的全景图,输出是一个透视图。
运行代码:直接运行文件即可
5. avinashk442/Panoramic-Image-Stitching-using-invariant-features(同pyimagesearch中的Image Stitcing with OpenCV and Python)
代码链接
功能:实现了全景图像拼接使用不变特征从零开始。实现了David Lowe的论文“使用不变特征的自动全景图像拼接”。论文地址:论文链接地址
运行代码:将需要拼接的图像放在代码所在的当前文件夹中,然后运行stitch.py即可。
6.samggggflynn/panorama-stitching(同pyimagesearch中的OpenCV panorama stitching)
代码链接
功能:使用Python和OpenCV进行图像拼接和全景图构建。给定两张图片,将它们“缝合”在一起形成一个简单的全景图。
运行代码:python stitch.py --first images/bryce_left_01.png --second images/bryce_right_01.png
7.FlagArihant2000/CylPanorama
代码链接
功能:可以实现拼接、透视、视频帧拼接等,输出全景图。
运行代码:直接运行。
8.andrewmagdyanis/PanoramaCreator-image_stitching-
代码链接
功能:使用openCV库上实现的图像拼接技术来制作全景图像。它从不同的角度为相同的东西拍摄许多图像,然后将它们拼接并裁剪所有UN填充的像素。
运行代码:直接运行。
9.WillBrennan/ImageStitching
代码链接
功能:该算法运行一个视频文件,或一组图像,并将它们拼接在一起,形成一个单一的图像。它可以用于扫描大文件,从单一照片的分辨率可能不够。目前这还没有考虑到图像模糊,评估进入帧的质量是否比前一帧好,或者镜头失真。
运行代码:python stitching.py --display --save
参考论文:Automatic Panoramic Image Stitching using Invariant Features,论文链接
10.kushalvyas/Python-Multiple-Image-Stitching
功能:使用多个图像创建全景图。
说明文档:链接地址
运行代码:python pano.py <txtlists/filename_.txt>
参考论文:Automatic Panoramic Image Stitching using Invariant Features,论文链接
11.znliunwpugmail/sift_cv
代码链接
功能:使用python实现了SIFT算法。
代码运行:直接运行
参考:
https://blog.csdn.net/qq_46111316/article/details/120558049
https://blog.csdn.net/qq_46111316/article/details/120538650
12.creimers/real-time-image-stitching
link
使用 Python 和 OpenCV 对 2 张以上图像进行实时图像拼接
13.sakshikakde
link
第一部分探讨了在一组两个图像之间找到单应矩阵的传统方法。
第二部分描述了一种有监督和无监督的深度学习方法的实现,用于估计合成生成的数据之间的单应性。
14.h-gokul
link
使用 Homography 进行全景图像拼接。
第一阶段:使用传统方法;第二阶段:有监督和无监督的深度学习方法。