Find homography for stitching - computer-vision

I’m working on the following task:
I have 6 fisheye cameras and would like to produce a 360 degree stitched image.
After carrying out the calibration procedure with findChessboardCorners, calibrateCamera, I obtained the intrinsic and extrinsic matrix.
Starting from the 6 images with fish-eye effect, through the fisheye.initUndistortRectifyMap function, I obtained the 6 planar images.
The two planar images from above are reported below.
Now I should do the stitching to get a 360 degree image.
I tried to do this using the cv2.createStitcher function, but this doesn’t always work, also I would like to have access to the homography matrix to determine the static matrices of the system.
So I tried to calculate the homography matrix, identifying through the SIFT algorithm, the common keypoints between two images and keeping the keypoints that best match.
I then stitched the two images using the warpPerspective function.
I believe that the procedure is correct up to the calculation of the keypoints, but I do not understand why the final result is not good.
In fact, in an attempt to stitch the second image is completely deformed / changed in perspective with a loss of right image.
Here there is the code:
import cv2
import numpy as np
def cvshow(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.destroyAllWindows()
def sift_kp(image):
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
sift = cv2.xfeatures2d.SIFT_create()
sift = cv2.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(image, None)
kp_image = cv2.drawKeypoints(gray_image, kp, None)
return kp_image, kp, des
def get_good_match(des1, des2):
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2) # des1 is the template image, des2 is the matching image
matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
good = []
for m, n in matches:
if m.distance < 0.55 * n.distance:
good.append(m)
return good
def drawMatches(imageA, imageB, kpsA, kpsB, matches, status):
# Initialize the visualization picture, connect the A and B pictures left and right together
(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
# Joint traversal, draw matching pairs
for ((trainIdx, queryIdx), s) in zip(matches, status):
# When the point pair is matched successfully, draw it on the visualization
if s == 1:
# Draw matching pairs
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 visualization results
return vis
# Panorama stitching
def siftimg_rightlignment(img_right, img_left):
_, kp1, des1 = sift_kp(img_right)
_, kp2, des2 = sift_kp(img_left)
goodMatch = get_good_match(des1, des2)
# When the matching pairs of the filter items are greater than 4 pairs: calculate the perspective transformation matrix
if len(goodMatch) > 4:
# Get the point coordinates of the matching pair
ptsA = np.float32([kp1[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ptsB = np.float32([kp2[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ransacReprojThreshold = 4
H, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, ransacReprojThreshold)
print(H)
#H = np.array([[-3.95002617e-01,-7.49813070e-02, 4.43642683e+02], [-4.06655962e-01,5.27365057e-01, 1.20636875e+02],[-1.60149798e-03, -3.69708507e-05, 1.00000000e+00]])
# The function of this function is to first use RANSAC to select the best four sets of pairing points, and then calculate the H matrix. H is a 3*3 matrix
# Change the angle of view to the right of the picture, result is the transformed picture
result = cv2.warpPerspective(img_right, H, (img_right.shape[1] + img_left.shape[1], img_right.shape[0]))
cvshow('result_medium', result)
# Pass the picture left to the left end of the result picture
result[0:img_left.shape[0], 0:img_left.shape[1]] = img_left
return result
# Feature matching + panoramic stitching
import numpy as np
import cv2
# Read the stitched pictures (note the placement of the left and right pictures)
# Is to transform the graphics on the right
img_left = cv2.imread(r'\planar\0.png')
img_right = cv2.imread(r'\planar\5.png')
img_right = cv2.resize(img_right, None, fx=0.5, fy=0.3)
# Ensure that the two images are the same size
img_left = cv2.resize(img_left, (img_right.shape[1], img_right.shape[0]))
kpimg_right, kp1, des1 = sift_kp(img_right)
kpimg_left, kp2, des2 = sift_kp(img_left)
# Display the original image and the image after key point detection at the same time
cvshow('img_left', np.hstack((img_left, kpimg_left)))
cvshow('img_right', np.hstack((img_right, kpimg_right)))
goodMatch = get_good_match(des1, des2)
all_goodmatch_img = cv2.drawMatches(img_right, kp1, img_left, kp2, goodMatch, None, flags=2)
# goodmatch_img Set the first goodMatch[:10]
goodmatch_img = cv2.drawMatches(img_right, kp1, img_left, kp2, goodMatch[:10], None, flags=2)
cvshow('Keypoint Matches1', all_goodmatch_img)
cvshow('Keypoint Matches2', goodmatch_img)
# Stitch the picture into a panorama
result = siftimg_rightlignment(img_right, img_left)
cvshow('result', result)```

Related

Reduce dimensionality with PCA after ORB

i try to reduce dimensionality of feature that have been extracted by using ORB with PCA then draw the keypoints that have been processed by PCA
plt.rcParams['figure.figsize'] = [14.0, 7.0]
e1 = cv2.getTickCount()
#read image and convert to RGB
image_normal = cv2.imread(image)
image_query = cv2.cvtColor(image_normal, cv2.COLOR_BGR2RGB)
image_gray = cv2.cvtColor(image_query, cv2.COLOR_RGB2GRAY)
#ORB function
orb = cv2.ORB_create()
keypoints, descriptor = orb.detectAndCompute(image_gray, None)
# Draw the keypoints
image = cv2.drawKeypoints(image_query, keypoints,0,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
mean, eigenvectors = cv2.PCACompute(image, np.mean(image, axis=0).reshape(1,-1))
e2 = cv2.getTickCount()
t = (e2 - e1) / cv2.getTickFrequency()
#Show Image
plt.imshow(image)
plt.title('ORB Keypoints')
plt.show()
# Print the number of keypoints detected and time
print("\nNumber of keypoints Detected: ", len(keypoints))
print('Time Cost for ORB: ', (t))
as i try i got an error that says
error: OpenCV(3.4.2) C:\projects\opencv-
python\opencv\modules\core\src\pca.cpp:72: error: (-215:Assertion failed)
data.channels() == 1 in function 'cv::PCA::operator ()'

Splitting dataset

I am new to opencv and python.
I am trying to create sudoku solver in opencv and want to use this image as my dataset for recognizing the digits in sudoku.
I want the entire image to be used as dataset.
sudoku digits dataset
Dimensions: 468x108
This image has 39 numbers in a row and 9 such rows [ 1 .. 9 ]
image = cv2.imread( 'images/digits_sudoku4.png')
image = cv2.resize( image, None, fx=2, fy=2,)
gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY)
cells = [np.hsplit(row, 39) for row in np.vsplit(gray, 12)]
# Convert the List data type to Numpy Array
x = np.array(cells)
print ("The shape of our cells array: " + str(x.shape))
train = x.astype(np.float32) # Size = (3500,400)
# Create labels for train and test data
k = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
train_labels = np.repeat( k, 468)[:, np.newaxis]
# Initiate kNN, train the data, then test it with test data for k=3
knn = cv2.KNearest()
knn.train(train, train_labels)
#ret, result, neighbors, distance = knn.find_nearest(test, k=3)
# Now we check the accuracy of classification
# For that, compare the result with test_labels and check which are wrong
'''
matches = result == test_labels
correct = np.count_nonzero(matches)
accuracy = correct * (100.0 / result.size)
print("Accuracy is = %.2f" % accuracy + "%")
'''
cv2.imshow( 'Sudoku', gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
I am facing this error on line knn.train(train, train_labels)...
cv2.error: /build/opencv-SviWsf/opencv-2.4.9.1+dfsg/modules/ml/src/inner_functions.cpp:857: error: (-5) train data must be floating-point matrix in function cvCheckTrainData
Please help me out.
Thankyou.

Python // How to get a rectangle around the target object using the features extracted by SIFT in OpenCV

Here is my code:
import numpy as np
import cv2
from matplotlib import pyplot as plt
from scipy import misc
import matplotlib.pyplot as plt
MIN_MATCH_COUNT = 10
img1 = cv2.imread('Screenshot_2.png',0)
img2 = cv2.imread('Screenshot_12.png',0)
# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1,des2,k=2)
good = []
for m,n in matches:
if m.distance < 0.7*n.distance:
good.append(m)
print good
if len(good)>MIN_MATCH_COUNT:
src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
matchesMask = mask.ravel().tolist()
h,w = img1.shape
pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
dst = cv2.perspectiveTransform(pts,M)
img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)
else:
print "Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT)
matchesMask = None
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
singlePointColor = None,
matchesMask = matchesMask, # draw only inliers
flags = 2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3, 'gray'),plt.show()
I would like to trace with OpenCV a rectangle of my detected objects with this method, but I do not know how start for get what I want.
I found nowhere to solve my question with Python
Did you have any advice to give me to carry out my project?:(
Just get src_pts where mask==1 and find min_X, min_Y, max_X, max_Y for rectangle onto Source Image.
Below is the code I have tried..
pts = src_pts[mask==1]
min_x, min_y = np.int32(pts.min(axis=0))
max_x, max_y = np.int32(pts.max(axis=0))
Here you got up-left point as (min_x, min_y) and bottom_right point as (max_x, max_y). Below code is for diplaying bounding box on originalImage.
cv2.rectangle(originalImage,(min_x, min_y), (max_x,max_y), 255,2)
plt.imshow(originalImage, cmap='gray')

How to save images to a server folder via sockets using python and opencv?

I would like to know how to save images captured by Opencv, in a directory created by code that should stay on the server ...**
import cv2, sys, numpy, os
haar_file = 'haarcascade_frontalface_default.xml'
datasets = 'datasets' #All the faces data will be present this folder
sub_data = raw_input ('digite o seu nome') #These are sub data sets of folder, for my faces I've used my name
path = os.path.join(datasets, sub_data)
if not os.path.isdir(path):
os.mkdir(path)
(width, height) = (130, 100) # defining the size of images
face_cascade = cv2.CascadeClassifier(haar_file)
webcam = cv2.VideoCapture(0) #'0' is use for my webcam, if you've any other camera attached use '1' like this
# The program loops until it has 100 images of the face.
count = 1
while count < 101:
(_, im) = webcam.read()
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 4)
for (x,y,w,h) in faces:
cv2.rectangle(im,(x,y),(x+w,y+h),(255,0,0),2)
face = gray[y:y + h, x:x + w]
face_resize = cv2.resize(face, (width, height))
cv2.imwrite('%s/%s.png' % (path,count), face_resize)
count += 1
cv2.imshow('OpenCV', im)
key = cv2.waitKey(10)
if key == 27:
break

How to blend multiple images in OpenCV?

I have group of images and associated weights with it. I want to blend them together. I know there is a blend command in OpenCV to blend two images. But how do I blend multiple images together?
The blending can be done using the below code(This is in Java using OpenCV):
//Create a black-colored image
Mat mergedImage = new Mat(inputImageSize, inputImageType, new Scalar(0));
//Add each image from a vector<Mat> inputImages with weight 1.0/n where n is number of images to merge
for (Mat mat : inputImages) {
Core.addWeighted(mergedImage, 1, mat, 1.0/n, 0, mergedImage);
}
Edit:- The above code suffers from rounding error. If inputImageType is an integer type, division by 1/n will cause this issue. Thus, above code should be used only for floating matrices.
What about simple matrix operations, like the following?
blendedImage = weight_1 * image_1 + weight_2 * image_2 + ... + weight_n * image_n
Here is Python code to blend multiple images in a list. I used the basic formulation from Dennis' answer.
First, let's get three images.
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
dim = (425, 425)
apple = mpimg.imread('apple.jpg')
apple = cv2.resize(apple, dim)
banana = mpimg.imread('banana.jpg')
banana = cv2.resize(banana, dim)
orange = mpimg.imread('orange.jpg')
orange = cv2.resize(orange, dim)
_ = plt.imshow(apple)
_ = plt.show()
_ = plt.imshow(banana)
_ = plt.show()
_ = plt.imshow(orange)
_ = plt.show()
Here are the images:
Now let's blend them together equally. Since there are three images, the fraction of each image's contribution to the final output is 0.333.
def blend(list_images): # Blend images equally.
equal_fraction = 1.0 / (len(list_images))
output = np.zeros_like(list_images[0])
for img in list_images:
output = output + img * equal_fraction
output = output.astype(np.uint8)
return output
list_images = [apple, banana, orange]
output = blend(list_images)
_ = plt.imshow(output)
And here is the result: