Обнаружение ключевых точек и сшивание изображений
] 2
Таким образом, как показано на рисунке ниже, у меня есть ключевые точки, обнаруженные на изображении, но выходное изображение после перспективы обтекания игнорирует первое изображение на левой стороне, не могу понять, почему!
import numpy as np
import imutils
import cv2
class Stitcher:
def __init__(self):
# determine if we are using OpenCV v3.X
self.isv3 = imutils.is_cv3()
def stitch(self, imageA,imageB, ratio=0.75, reprojThresh=10.0,
showMatches=False):
# unpack the images, then detect keypoints and extract
# local invariant descriptors from them
#(imageB, imageA) = images
(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
# otherwise, apply a perspective warp to stitch the images
# together
(matches, H, status) = M
#print(M)
#print(matches)
#print(H)
#print(status)
#cv2.imwrite('intermediate.jpg',matches)
result = cv2.warpPerspective(imageA, H,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
#cv2.imshow('intermediate',result)
# check to see if the keypoint matches should be visualized
if showMatches:
vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches,
status)
# return a tuple of the stitched image and the
# visualization
return (result, vis)
# 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
#SIFT Algorithm
descriptor = cv2.xfeatures2d.SIFT_create()
#SURF Algorithm
#descriptor = cv2.xfeatures2d.SURF_create()# 400 is hesian threshold, optimum values should be around 300-500
#upright SURF: faster and can be used for panorama stiching i.e our case.
#descriptor.upright = True
print(descriptor.descriptorSize())
(kps, features) = descriptor.detectAndCompute(image, None)
print(len(kps),features.shape)
# 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
#print("features",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))
print(len(matches))
# 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
Выше приведен код, используемый для обнаружения и сшивания ключевых точек,
Еще один вопрос, может ли кто-нибудь помочь мне с вертикальным сшиванием изображений, кроме поворота изображений и выполнения горизонтального сшивания.
Большое спасибо!
Я изменил свой код и использовал функцию @Alexander padtransf.warpPerspectivePadded, чтобы выполнять обтекание и смешивание! Можете ли вы помочь мне получить равномерное освещение для выходного изображения?
1 ответ
У меня была эта проблема сама. Если я не ошибаюсь, вы используете этот блог в качестве ссылки.
Проблема заключается в warpPerspective
в отношении линии:
result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0])) result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
Этот метод является всенаправленным. Под этим я подразумеваю, что вы просто накладываете imageA поверх imageB, заменяя значения пикселей на основе ширины и высоты, представленных .shape[0]
а также .shape[1]
, Я решил это в C++, и поэтому у меня нет кода для отображения на Python, но он может дать вам представление о том, что должно быть сделано.
- Получите четыре угла каждого из изображений, которые вы используете.
- Получите минимальные и максимальные углы для каждого изображения, найденного в шаге 1.
- Создайте коврик "HTR", который будет использоваться для отображения изображения один, чтобы привести в соответствие с уже деформированным изображением два HTR.at(0,2) представляет местоположение в матрице 3x3 матов. Numpy, вероятно, то, что вам нужно использовать здесь.
Mat Htr = Mat::eye(3,3,CV_64F); if (min_x < 0){ max_x = image2.size().width - min_x; Htr.at<double>(0,2)= -min_x; } if (min_y < 0){ max_y = image2.size().height - min_y; Htr.at<double>(1,2)= -min_y; }
- Выполните перспективное преобразование по четырем углам каждого изображения, чтобы увидеть, где они окажутся в пространстве.
perspectiveTransform(vector<Point2f> fourPointImage1, vector<Point2f> image1dst, Htr*homography); perspectiveTransform(vector<Point2f> fourPointImage2, vector<Point2f> image2dst, Htr);
- Получите минимальное и максимальное значения из
image1dst
четыре угла иiamge2dst
четыре угла. - Получите минимум и максимум
image1dst
а такжеiamge2dst
и использовать для создания новогоblank image
правильного размера, чтобы держать окончательно сшитые изображения. - Повторите шаг 3 на этот раз, чтобы определить
translation
необходимо отрегулировать четыре угла каждого изображения, чтобы убедиться, что они перемещаются в виртуальное пространствоblank image
- Наконец добавьте фактические изображения со всеми омографиями, которые вы нашли / сделали.
warpPerspective(image1, blankImage, (translation*homography),result.size(), INTER_LINEAR,BORDER_CONSTANT,(0)); warpPerspective(image2, image2Updated, translation, result.size(), INTER_LINEAR, BORDER_CONSTANT, (0));
Конечная цель и результат - определить, куда будут деформироваться изображения, чтобы вы могли создать пустое изображение, в котором будут храниться все сшитые изображения, чтобы ничего не обрезалось. Только после того, как вы выполнили всю предварительную обработку, вы фактически соединили изображения вместе. Я надеюсь, что это помогает, и если у вас есть вопросы, просто кричите.