-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdemo.py
executable file
·139 lines (113 loc) · 6.52 KB
/
demo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Demo to show MultiHarrisZernike feature detector on the Skerki dataset
@author: vik748
"""
import sys, os
import cv2
import time
from matplotlib import pyplot as plt
import numpy as np
from zernike_py.MultiHarrisZernike import MultiHarrisZernike
def knn_match_and_lowe_ratio_filter(matcher, des1, des2,threshold=0.9, dist_mask_12=None, draw_plot_dist=False):
# First match 2 against 1
if dist_mask_12 is None:
dist_mask_21 = None
else:
dist_mask_21 = dist_mask_12.T
matches_knn = matcher.knnMatch(des2,des1, k=2, mask = dist_mask_21 )
all_ds = [m[0].distance for m in matches_knn if len(m) >0]
#print("Len of knn matches", len(matches_knn))
matches = []
# Run lowes filter and filter with difference higher than threshold this might
# still leave multiple matches into 1 (train descriptors)
# Create mask of size des1 x des2 for permissible matches
mask = np.zeros((des1.shape[0],des2.shape[0]),dtype='uint8')
for match in matches_knn:
if len(match)==1 or (len(match)>1 and match[0].distance < threshold*match[1].distance):
# if match[0].distance < 75:
matches.append(match[0])
mask[match[0].trainIdx,match[0].queryIdx] = 1
#matches = [m for m in matches if m.distance<5 ]
if draw_plot_dist:
fig, axes = plt.subplots(1, 1, num=3)
filt_ds = [m.distance for m in matches]
axes.plot(sorted(all_ds),'.',label = 'All Matches')
axes.plot(sorted(filt_ds),'.',label = 'Filtered Matches')
axes.set_xlabel('Number')
axes.set_ylabel('Distance')
axes.legend()
plt.pause(.1)
# run matches again using mask but from 1 to 2 which should remove duplicates
# This is basically same as running cross match after lowe ratio test
matches_cross = matcher.match(des1,des2,mask=mask)
#print("Len of cross matches", len(matches_cross))
return matches_cross
def draw_arrows(vis_orig, points1, points2, color = (0, 255, 0), thick = 2, tip_length = 0.25):
if len(vis_orig.shape) == 2: vis = cv2.cvtColor(vis_orig,cv2.COLOR_GRAY2RGB)
else: vis = vis_orig
for p1,p2 in zip(points1,points2):
cv2.arrowedLine(vis, (int(p1[0]),int(p1[1])), (int(p2[0]),int(p2[1])),
color=color, thickness=thick, tipLength = tip_length)
return vis
def draw_feature_tracks(img_left,kp1,img_right,kp2, matches, mask, display_invalid=False, color=(0, 255, 0), thick = 2):
'''
This function extracts takes a 2 images, set of keypoints and a mask of valid
(mask as a ndarray) keypoints and plots the valid ones in green and invalid in red.
The mask should be the same length as matches
'''
bool_mask = mask.astype(bool)
valid_right_matches = np.array([kp2[mat.trainIdx].pt for is_match, mat in zip(bool_mask, matches) if is_match])
valid_left_matches = np.array([kp1[mat.queryIdx].pt for is_match, mat in zip(bool_mask, matches) if is_match])
#img_right_out = draw_points(img_right, valid_right_matches)
img_right_out = draw_arrows(img_right, valid_left_matches, valid_right_matches, thick = thick)
img_left_out = draw_arrows(img_left, valid_right_matches, valid_left_matches, thick = thick)
return img_left_out, img_right_out
img0_name = os.path.join('test_data', 'skerki_test_image_0.tif')
img1_name = os.path.join('test_data', 'skerki_test_image_1.tif')
gr0 = cv2.imread(img0_name, cv2.IMREAD_GRAYSCALE)
gr1 = cv2.imread(img1_name, cv2.IMREAD_GRAYSCALE)
zernike_obj = MultiHarrisZernike(Nfeats= 600, seci = 5, secj = 4, levels = 6, ratio = 0.75,
sigi = 2.75, sigd = 1.0, nmax = 8, like_matlab=False, lmax_nd = 3, harris_threshold = None)
zernike_obj.plot_zernike(zernike_obj.ZstrucZ)
kp0, des0 = zernike_obj.detectAndCompute(gr0, mask=None, timing=True)
kp1, des1 = zernike_obj.detectAndCompute(gr1, mask=None, timing=True)
matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=False)
matches_01 = knn_match_and_lowe_ratio_filter(matcher, des0, des1, threshold=0.9)
kp0_match_01_pts = np.array([kp0[mat.queryIdx].pt for mat in matches_01])
kp1_match_01_pts = np.array([kp1[mat.trainIdx].pt for mat in matches_01])
if [int(x) for x in cv2.__version__.split(".")] >= [3,4,0]:
E_12, mask_e_12 = cv2.findFundamentalMat(kp0_match_01_pts, kp1_match_01_pts,
method=cv2.FM_RANSAC, # RAnsac
ransacReprojThreshold=1.0, # Inlier threshold in pixel since we don't use nomalized coordinates
confidence=0.9999)
else:
E_12, mask_e_12 = cv2.findFundamentalMat(kp0_match_01_pts, kp1_match_01_pts,
method=cv2.FM_RANSAC, # Ransac
param1=1.0, # Inlier threshold in pixel since we don't use nomalized coordinates
param2=0.9999)
kp0_match_inliers = [kp0[mat.queryIdx] for mat, msk in zip(matches_01, mask_e_12) if msk]
kp1_match_inliers = [kp1[mat.trainIdx] for mat, msk in zip(matches_01, mask_e_12) if msk]
gr0_inliers = cv2.drawKeypoints(gr0, kp0_match_inliers, gr0,color=[255,255,0],
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
gr1_inliers = cv2.drawKeypoints(gr1, kp1_match_inliers, gr0,color=[255,255,0],
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
matches_img_left, matches_img_right = draw_feature_tracks(gr0_inliers, kp0, gr1_inliers, kp1, matches_01,
mask_e_12, display_invalid=True, color=(0, 255, 0),
thick = 2)
fig2, fig2_axes = plt.subplots(1,2)
fig2.suptitle('Zernike Feature Matching: {:d} matches'.format(np.sum(mask_e_12)))
[ax.axis("off") for ax in fig2_axes]
fig2_axes[0].imshow(matches_img_left)
fig2_axes[1].imshow(matches_img_right)
fig2.subplots_adjust(left=0.0, bottom=0.0, right=1.0, top=.9, wspace=0.1, hspace=0.0)
kp0, des0, kp_eig_vals, Ft = zernike_obj.detectAndCompute(gr0, computeEigVals=True, mask=None, timing=False)
fig3, fig3_axes = plt.subplots(1,1)
fig3.suptitle('Harris Eigen Values')
fig3_axes.plot(kp_eig_vals[:,0],kp_eig_vals[:,1], '+')
data_lims = np.mean(kp_eig_vals,axis=0) + 2 * np.std(kp_eig_vals,axis=0)
fig3_axes.set_xlim([0,data_lims[0]])
fig3_axes.set_ylim([0,data_lims[1]])
fig3_axes.set_xlabel(r'$\lambda_1$'); fig3_axes.set_ylabel(r'$\lambda_2$')
plt.draw(); plt.show(block=True);