Python, How to stitch images which overlapping areas?
up vote
0
down vote
favorite
I'm trying to stitch together images which have overlapping areas.
The images are sorted, each image has overlapping area with the previous image. For example:
https://imgur.com/a/t9zzeHD
I've tried the code at https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/, which I slightly changed and used tilted images but the end result (https://imgur.com/a/B2d2VBL) is not as expected.
Does the issue arise from 5th image which has a black right side? Not sure on why the black was added and how to avoid it.
Anybody knows how I can fix the code to not distort the images as I add more and more images? Better code examples for me to use are welcomed.
~~~~~~~~ EDIT ~~~~~~~
As pointed by Dan in the comments I'm using the wrong tool (warpPerspective) for the job. What I'm really looking for is a way to get find the matching key points in both images, translate it to the correct Y in each image so I could cut the images and then stitch them accordingly.
So the question now might be a bit simple on how to get matching key points and translate it to Y coordinates.
PLEASE IGNORE THE CODE AS IT IS ONLY AN EXAMPLE FOR WHERE I STARTED AND IT IS ONLY MISLEADING AT THIS POINT.
The code example bellow, takes an input of a path to directory which contains the images ["0.png", "1.png", "2.png", "3.png"]
from PIL import Image
import numpy as np
import imutils
import cv2
# from panorama import Stitcher
import argparse
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, images, ratio=0.75, reprojThresh=4.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
result = cv2.warpPerspective(imageA, H,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
# 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
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
if __name__ == '__main__':
images_folder = sys.argv[1]
images = ["0.png", "1.png", "2.png", "3.png"]
imageA = cv2.imread(images_folder+images[0])
imageB = cv2.imread(images_folder+images[1])
# stitch the images together to create a panorama
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
count = 0
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
img.save(current_stiched_image)
for image in images[2:]:
count+=1
print("image: {}".format(image))
print("count: {}".format(count))
print("current_stiched_image: {}".format(current_stiched_image))
imageA1 = cv2.imread(current_stiched_image)
imageB1 = cv2.imread(images_folder + image)
(result, vis) = stitcher.stitch([imageA1, imageB1], showMatches=True)
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
print("new current_stiched_image: {}".format(current_stiched_image))
img.save(current_stiched_image)
python opencv
add a comment |
up vote
0
down vote
favorite
I'm trying to stitch together images which have overlapping areas.
The images are sorted, each image has overlapping area with the previous image. For example:
https://imgur.com/a/t9zzeHD
I've tried the code at https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/, which I slightly changed and used tilted images but the end result (https://imgur.com/a/B2d2VBL) is not as expected.
Does the issue arise from 5th image which has a black right side? Not sure on why the black was added and how to avoid it.
Anybody knows how I can fix the code to not distort the images as I add more and more images? Better code examples for me to use are welcomed.
~~~~~~~~ EDIT ~~~~~~~
As pointed by Dan in the comments I'm using the wrong tool (warpPerspective) for the job. What I'm really looking for is a way to get find the matching key points in both images, translate it to the correct Y in each image so I could cut the images and then stitch them accordingly.
So the question now might be a bit simple on how to get matching key points and translate it to Y coordinates.
PLEASE IGNORE THE CODE AS IT IS ONLY AN EXAMPLE FOR WHERE I STARTED AND IT IS ONLY MISLEADING AT THIS POINT.
The code example bellow, takes an input of a path to directory which contains the images ["0.png", "1.png", "2.png", "3.png"]
from PIL import Image
import numpy as np
import imutils
import cv2
# from panorama import Stitcher
import argparse
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, images, ratio=0.75, reprojThresh=4.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
result = cv2.warpPerspective(imageA, H,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
# 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
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
if __name__ == '__main__':
images_folder = sys.argv[1]
images = ["0.png", "1.png", "2.png", "3.png"]
imageA = cv2.imread(images_folder+images[0])
imageB = cv2.imread(images_folder+images[1])
# stitch the images together to create a panorama
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
count = 0
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
img.save(current_stiched_image)
for image in images[2:]:
count+=1
print("image: {}".format(image))
print("count: {}".format(count))
print("current_stiched_image: {}".format(current_stiched_image))
imageA1 = cv2.imread(current_stiched_image)
imageB1 = cv2.imread(images_folder + image)
(result, vis) = stitcher.stitch([imageA1, imageB1], showMatches=True)
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
print("new current_stiched_image: {}".format(current_stiched_image))
img.save(current_stiched_image)
python opencv
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,warpPerspective
seems a bit counterproductive.
– Dan Mašek
Nov 9 at 12:30
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm trying to stitch together images which have overlapping areas.
The images are sorted, each image has overlapping area with the previous image. For example:
https://imgur.com/a/t9zzeHD
I've tried the code at https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/, which I slightly changed and used tilted images but the end result (https://imgur.com/a/B2d2VBL) is not as expected.
Does the issue arise from 5th image which has a black right side? Not sure on why the black was added and how to avoid it.
Anybody knows how I can fix the code to not distort the images as I add more and more images? Better code examples for me to use are welcomed.
~~~~~~~~ EDIT ~~~~~~~
As pointed by Dan in the comments I'm using the wrong tool (warpPerspective) for the job. What I'm really looking for is a way to get find the matching key points in both images, translate it to the correct Y in each image so I could cut the images and then stitch them accordingly.
So the question now might be a bit simple on how to get matching key points and translate it to Y coordinates.
PLEASE IGNORE THE CODE AS IT IS ONLY AN EXAMPLE FOR WHERE I STARTED AND IT IS ONLY MISLEADING AT THIS POINT.
The code example bellow, takes an input of a path to directory which contains the images ["0.png", "1.png", "2.png", "3.png"]
from PIL import Image
import numpy as np
import imutils
import cv2
# from panorama import Stitcher
import argparse
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, images, ratio=0.75, reprojThresh=4.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
result = cv2.warpPerspective(imageA, H,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
# 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
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
if __name__ == '__main__':
images_folder = sys.argv[1]
images = ["0.png", "1.png", "2.png", "3.png"]
imageA = cv2.imread(images_folder+images[0])
imageB = cv2.imread(images_folder+images[1])
# stitch the images together to create a panorama
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
count = 0
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
img.save(current_stiched_image)
for image in images[2:]:
count+=1
print("image: {}".format(image))
print("count: {}".format(count))
print("current_stiched_image: {}".format(current_stiched_image))
imageA1 = cv2.imread(current_stiched_image)
imageB1 = cv2.imread(images_folder + image)
(result, vis) = stitcher.stitch([imageA1, imageB1], showMatches=True)
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
print("new current_stiched_image: {}".format(current_stiched_image))
img.save(current_stiched_image)
python opencv
I'm trying to stitch together images which have overlapping areas.
The images are sorted, each image has overlapping area with the previous image. For example:
https://imgur.com/a/t9zzeHD
I've tried the code at https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/, which I slightly changed and used tilted images but the end result (https://imgur.com/a/B2d2VBL) is not as expected.
Does the issue arise from 5th image which has a black right side? Not sure on why the black was added and how to avoid it.
Anybody knows how I can fix the code to not distort the images as I add more and more images? Better code examples for me to use are welcomed.
~~~~~~~~ EDIT ~~~~~~~
As pointed by Dan in the comments I'm using the wrong tool (warpPerspective) for the job. What I'm really looking for is a way to get find the matching key points in both images, translate it to the correct Y in each image so I could cut the images and then stitch them accordingly.
So the question now might be a bit simple on how to get matching key points and translate it to Y coordinates.
PLEASE IGNORE THE CODE AS IT IS ONLY AN EXAMPLE FOR WHERE I STARTED AND IT IS ONLY MISLEADING AT THIS POINT.
The code example bellow, takes an input of a path to directory which contains the images ["0.png", "1.png", "2.png", "3.png"]
from PIL import Image
import numpy as np
import imutils
import cv2
# from panorama import Stitcher
import argparse
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, images, ratio=0.75, reprojThresh=4.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
result = cv2.warpPerspective(imageA, H,
(imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
# 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
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
if __name__ == '__main__':
images_folder = sys.argv[1]
images = ["0.png", "1.png", "2.png", "3.png"]
imageA = cv2.imread(images_folder+images[0])
imageB = cv2.imread(images_folder+images[1])
# stitch the images together to create a panorama
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
count = 0
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
img.save(current_stiched_image)
for image in images[2:]:
count+=1
print("image: {}".format(image))
print("count: {}".format(count))
print("current_stiched_image: {}".format(current_stiched_image))
imageA1 = cv2.imread(current_stiched_image)
imageB1 = cv2.imread(images_folder + image)
(result, vis) = stitcher.stitch([imageA1, imageB1], showMatches=True)
imgRGB=cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
img = Image.fromarray(imgRGB)
current_stiched_image = images_folder + "lol10{}.png".format(count)
print("new current_stiched_image: {}".format(current_stiched_image))
img.save(current_stiched_image)
python opencv
python opencv
edited Nov 10 at 7:59
asked Nov 9 at 4:22
Captain_Meow_Meow
64531128
64531128
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,warpPerspective
seems a bit counterproductive.
– Dan Mašek
Nov 9 at 12:30
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55
add a comment |
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,warpPerspective
seems a bit counterproductive.
– Dan Mašek
Nov 9 at 12:30
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,
warpPerspective
seems a bit counterproductive.– Dan Mašek
Nov 9 at 12:30
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,
warpPerspective
seems a bit counterproductive.– Dan Mašek
Nov 9 at 12:30
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
The problem of the black strip is that you put 2 overlapping images inside an image of the size of both of them... the black strip is the width of the overlapping area. To remove it you can always calculate the width needed. For example, you can find where the top and bottom right points will be mapped to, using the formula given in the documentation. Something like this:
def determineMaXSize(self, w, h ,M):
x0 = (M[0,0]*(w-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,2]) # for top right point
x1 = (M[0,0]*(w-1) + M[0,1]*(h-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,1]*(h-1) + M[2,2])# for bottom right point
print ("x0",x0)
print("x1",x1)
return int(min(x0, x1))
And then:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
maxWidth = self.determineMaXSize(imageA.shape[1], imageA.shape[0] ,H)
result = result[:, 0:maxWidth]
I take the min width between the 2 point to remove all the black part from the right, even if the image is distorted. (it will cut a little of the image in this case)
Your second problem is that somehow the match between the two images of the guy's chest are not so good to do the matching and they end a little bit moved, and then ends on having quite some distortion. You should try to obtain images with more overlapping or try using other matching methods or other parameters for the SIFT feature detection. Maybe try looking to a method which only estimates translations based on features/points.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
The problem of the black strip is that you put 2 overlapping images inside an image of the size of both of them... the black strip is the width of the overlapping area. To remove it you can always calculate the width needed. For example, you can find where the top and bottom right points will be mapped to, using the formula given in the documentation. Something like this:
def determineMaXSize(self, w, h ,M):
x0 = (M[0,0]*(w-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,2]) # for top right point
x1 = (M[0,0]*(w-1) + M[0,1]*(h-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,1]*(h-1) + M[2,2])# for bottom right point
print ("x0",x0)
print("x1",x1)
return int(min(x0, x1))
And then:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
maxWidth = self.determineMaXSize(imageA.shape[1], imageA.shape[0] ,H)
result = result[:, 0:maxWidth]
I take the min width between the 2 point to remove all the black part from the right, even if the image is distorted. (it will cut a little of the image in this case)
Your second problem is that somehow the match between the two images of the guy's chest are not so good to do the matching and they end a little bit moved, and then ends on having quite some distortion. You should try to obtain images with more overlapping or try using other matching methods or other parameters for the SIFT feature detection. Maybe try looking to a method which only estimates translations based on features/points.
add a comment |
up vote
0
down vote
The problem of the black strip is that you put 2 overlapping images inside an image of the size of both of them... the black strip is the width of the overlapping area. To remove it you can always calculate the width needed. For example, you can find where the top and bottom right points will be mapped to, using the formula given in the documentation. Something like this:
def determineMaXSize(self, w, h ,M):
x0 = (M[0,0]*(w-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,2]) # for top right point
x1 = (M[0,0]*(w-1) + M[0,1]*(h-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,1]*(h-1) + M[2,2])# for bottom right point
print ("x0",x0)
print("x1",x1)
return int(min(x0, x1))
And then:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
maxWidth = self.determineMaXSize(imageA.shape[1], imageA.shape[0] ,H)
result = result[:, 0:maxWidth]
I take the min width between the 2 point to remove all the black part from the right, even if the image is distorted. (it will cut a little of the image in this case)
Your second problem is that somehow the match between the two images of the guy's chest are not so good to do the matching and they end a little bit moved, and then ends on having quite some distortion. You should try to obtain images with more overlapping or try using other matching methods or other parameters for the SIFT feature detection. Maybe try looking to a method which only estimates translations based on features/points.
add a comment |
up vote
0
down vote
up vote
0
down vote
The problem of the black strip is that you put 2 overlapping images inside an image of the size of both of them... the black strip is the width of the overlapping area. To remove it you can always calculate the width needed. For example, you can find where the top and bottom right points will be mapped to, using the formula given in the documentation. Something like this:
def determineMaXSize(self, w, h ,M):
x0 = (M[0,0]*(w-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,2]) # for top right point
x1 = (M[0,0]*(w-1) + M[0,1]*(h-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,1]*(h-1) + M[2,2])# for bottom right point
print ("x0",x0)
print("x1",x1)
return int(min(x0, x1))
And then:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
maxWidth = self.determineMaXSize(imageA.shape[1], imageA.shape[0] ,H)
result = result[:, 0:maxWidth]
I take the min width between the 2 point to remove all the black part from the right, even if the image is distorted. (it will cut a little of the image in this case)
Your second problem is that somehow the match between the two images of the guy's chest are not so good to do the matching and they end a little bit moved, and then ends on having quite some distortion. You should try to obtain images with more overlapping or try using other matching methods or other parameters for the SIFT feature detection. Maybe try looking to a method which only estimates translations based on features/points.
The problem of the black strip is that you put 2 overlapping images inside an image of the size of both of them... the black strip is the width of the overlapping area. To remove it you can always calculate the width needed. For example, you can find where the top and bottom right points will be mapped to, using the formula given in the documentation. Something like this:
def determineMaXSize(self, w, h ,M):
x0 = (M[0,0]*(w-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,2]) # for top right point
x1 = (M[0,0]*(w-1) + M[0,1]*(h-1) + M[0,2]) / (M[2,0]*(w-1) + M[2,1]*(h-1) + M[2,2])# for bottom right point
print ("x0",x0)
print("x1",x1)
return int(min(x0, x1))
And then:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
maxWidth = self.determineMaXSize(imageA.shape[1], imageA.shape[0] ,H)
result = result[:, 0:maxWidth]
I take the min width between the 2 point to remove all the black part from the right, even if the image is distorted. (it will cut a little of the image in this case)
Your second problem is that somehow the match between the two images of the guy's chest are not so good to do the matching and they end a little bit moved, and then ends on having quite some distortion. You should try to obtain images with more overlapping or try using other matching methods or other parameters for the SIFT feature detection. Maybe try looking to a method which only estimates translations based on features/points.
answered Nov 9 at 13:04
api55
6,41732443
6,41732443
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53219838%2fpython-how-to-stitch-images-which-overlapping-areas%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
The question title seems a bit odd too -- isn't the overlap a prerequisite for the stitching to work? | With an input like this,
warpPerspective
seems a bit counterproductive.– Dan Mašek
Nov 9 at 12:30
@DanMašek yes I agree, as I'm unfamiliar with working with cv2 I used an exmaple I found, after digging more into it today I did find that using warpPerspective is deferentially not the right approach as It's more relevant to stitching images in cases such as panorama and such. I guess what I really need is just finding the area with the maximum matching points and apply a cut & stitch. But as I'm new I'm not sure on how to find the best matching key points, and how to translate that output into a Y coordinates (where to cut).
– Captain_Meow_Meow
Nov 10 at 7:55