Skip to content

Commit 4329de7

Browse files
committed
Added HW3.zip and README.md Edited
Signed-off-by: Vaishnav Murali <vaishnavmurali@gmail.com>
1 parent db0bfec commit 4329de7

File tree

7 files changed

+74
-18
lines changed

7 files changed

+74
-18
lines changed

Assignment-3/HW3.zip

7.45 MB
Binary file not shown.

Assignment-3/Q1/Q1.py

Whitespace-only changes.

Assignment-3/Q3/Homography.jpg

230 KB
Loading

Assignment-3/Q3/Matches.jpg

643 KB
Loading

Assignment-3/Q3/Q3.py

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import cv2
22
import numpy as np
3+
import numpy
34
import matplotlib.pyplot as plt
45
import sys
56
import random
6-
from scipy.sparse.linalg import svds
7-
from sklearn import linear_model
7+
NN_THRESHOLD = 0.7
8+
PIXEL_ERROR_THRESHOLD = 3
89
Detector = cv2.xfeatures2d.SIFT_create()
910
def SIFT(image):
1011
return Detector.detectAndCompute(image,None)
@@ -16,7 +17,7 @@ def matches(feature1,feature2,kp1,kp2):
1617
features2 = []
1718
for k,i in enumerate(feature2):
1819
ind = np.argsort(np.linalg.norm(np.subtract(feature1,i),axis=1))[:2]
19-
if np.linalg.norm(i-feature1[ind[0]])< 0.7 * np.linalg.norm(i-feature1[ind[1]]): #ratio : 0.7-0.8
20+
if np.linalg.norm(i-feature1[ind[0]])< NN_THRESHOLD * np.linalg.norm(i-feature1[ind[1]]): #ratio : 0.7-0.8
2021
kps2.append(kp2[k])
2122
features2.append(i)
2223
kps1.append(kp1[ind[0]])
@@ -41,6 +42,7 @@ def merge_images():
4142
ptA = (int(kps1[i].pt[0]), int(kps1[i].pt[1]))
4243
ptB = (int(kps2[i].pt[0]) + wA, int(kps2[i].pt[1]))
4344
cv2.line(vis, ptA, ptB, (random.randint(0,255), random.randint(0,255), random.randint(0,255)), 1)
45+
plt.imsave("Matches.jpg",vis)
4446
plt.title("Matches")
4547
plt.imshow(vis)
4648
kps1 = np.array(kps1)
@@ -56,30 +58,56 @@ def merge_images():
5658
best_count = -1
5759
for i in range(len(kps1)):
5860
ind = np.array(random.sample(list(range(len(kps1))),4))
59-
x_p = np.array([[v.pt[0],v.pt[1]] for v in kps1[ind]])
60-
x = np.array([[v.pt[0],v.pt[1]] for v in kps2[ind]])
61+
x_p = np.array([[v.pt[0],v.pt[1],1] for v in kps1[ind]])
62+
x = np.array([[v.pt[0],v.pt[1],1] for v in kps2[ind]])
6163
A = np.array([])
62-
for j in range(4):
63-
A = np.vstack([A,
64-
[[-x[j,0],-x[j,1],-1,0,0,0,x[j,0]*x_p[j,0],x[j,1]*x_p[j,0],x_p[j,0]],
65-
[0,0,0,-x[j,0],-x[j,1],-1,x[j,0]*x_p[j,1],x[j,1]*x_p[j,1],x_p[j,1]]]]
66-
) if A.size else np.array([[-x[j,0],-x[j,1],-1,0,0,0,x[j,0]*x_p[j,0],x[j,1]*x_p[j,0],x_p[j,0]],[0,0,0,-x[j,0],-x[j,1],-1,x[j,0]*x_p[j,1],x[j,1]*x_p[j,1],x_p[j,1]]])
67-
u,s,vh = np.linalg.svd(A)
68-
xtemp = np.hstack([x_p,np.ones((x.shape[0],1))])
69-
xori = np.hstack([x,np.ones((x_p.shape[0],1))])
70-
L = vh[-1,:]
71-
h = L.reshape((3,3))
64+
fp = x
65+
tp = x_p
66+
m = numpy.mean(fp[:2], axis=1)
67+
maxstd = numpy.max(numpy.std(fp[:2], axis=1)) + 1e-9
68+
C1 = numpy.diag([1/maxstd, 1/maxstd, 1])
69+
C1[0, 2] = -m[0] / maxstd
70+
C1[1, 2] = -m[1] / maxstd
71+
fp = numpy.dot(C1, fp.T)
72+
73+
# -to
74+
m = numpy.mean(tp[:2], axis=1)
75+
maxstd = numpy.max(numpy.std(tp[:2], axis=1)) + 1e-9
76+
C2 = numpy.diag([1/maxstd, 1/maxstd, 1])
77+
C2[0, 2] = -m[0] / maxstd
78+
C2[1, 2] = -m[1] / maxstd
79+
tp = numpy.dot(C2, tp.T)
80+
81+
correspondences_count = fp.shape[1]
82+
A = numpy.zeros((2 * correspondences_count, 9))
83+
for i in range(correspondences_count):
84+
A[2 * i ] = [-fp[0][i], -fp[1][i], -1, 0, 0, 0,
85+
tp[0][i] * fp[0][i], tp[0][i] * fp[1][i], tp[0][i]]
86+
A[2 * i + 1] = [0, 0, 0, -fp[0][i], -fp[1][i], -1,
87+
tp[1][i] * fp[0][i], tp[1][i] * fp[1][i], tp[1][i]]
88+
89+
U, S, V = numpy.linalg.svd(A)
90+
H = V[8].reshape((3, 3))
91+
92+
H = numpy.dot(numpy.linalg.inv(C2), numpy.dot(H, C1))
93+
h = H/H[2,2]
7294
homo_x = np.matmul(h,kp2_coordinates.T)
73-
k = np.linalg.norm(kp1_coordinates-homo_x.T,axis=1)<3
95+
k = np.linalg.norm(kp1_coordinates-homo_x.T,axis=1)<PIXEL_ERROR_THRESHOLD
7496
if best_count<np.count_nonzero(k):
7597
best_count = np.count_nonzero(k)
7698
best_h = h
77-
# print(best_count)
99+
# return H / H[2, 2]
100+
101+
102+
103+
print(best_count)
78104
result = cv2.warpPerspective(img2,best_h,
79105
(img1.shape[1] + img2.shape[1], img1.shape[0]))
106+
plt.imsave("Homography.jpg",result)
80107
result[0:img1.shape[0],0:img2.shape[1]] = img1
108+
plt.imsave("Result.jpg",result)
81109

82-
H,mask = cv2.findHomography(kp2_coordinates, kp1_coordinates, cv2.RANSAC,5.0)
110+
H,mask = cv2.findHomography(kp2_coordinates, kp1_coordinates, cv2.RANSAC,PIXEL_ERROR_THRESHOLD)
83111
result1 = cv2.warpPerspective(img2,H,
84112
(img1.shape[1] + img2.shape[1], img1.shape[0]))
85113
result1[0:img1.shape[0],0:img2.shape[1]] = img1

Assignment-3/Q3/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,29 @@
11
# Q3: Image Stitching
2+
#### Usage:
3+
```bash
4+
$ python Q3.py
5+
```
6+
### Note:
7+
- The program assumes `uttower_right.jpg` and `uttower_left.jpg` are in the same folder.
8+
- It has Thresholds hardcoded in it. Please change according to your needs for any modification.
9+
- As the program uses SIFT descriptor, the original cv2 won't have this (SIFT is proprietary). To run the code, uninstall cv2 using
10+
```
11+
pip uninstall opencv-python
12+
```
13+
and install `opencv-python-contrib` by running
14+
```
15+
pip install opencv-python-contrib
16+
```
17+
18+
### Report
19+
First the SIFT descriptor matches are found based on the Nearest Neighbour with a threshold distance as mentioned in [David Lowe's Paper](https://people.eecs.berkeley.edu/~malik/cs294/lowe-ijcv04.pdf)
20+
![Matches](Matches.jpg)
21+
22+
The Homography Matrix is selected using RANSAC and DLT, which selects the matrix which projects the maximum number of matches within a threhold.
23+
This generates a warped image in the final image plane using the found Homography.
24+
![Warped Perspective](Homography.jpg)
25+
26+
The Left image is overwritten in the warped image (no blending used)
27+
![Result](Result.jpg)
28+
29+
As RANSAC is used, this might not generate same images every time, But will have decent merged images.

Assignment-3/Q3/Result.jpg

337 KB
Loading

0 commit comments

Comments
 (0)