Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/python/asift.py
16337 views
1
#!/usr/bin/env python
2
3
'''
4
Affine invariant feature-based image matching sample.
5
6
This sample is similar to find_obj.py, but uses the affine transformation
7
space sampling technique, called ASIFT [1]. While the original implementation
8
is based on SIFT, you can try to use SURF or ORB detectors instead. Homography RANSAC
9
is used to reject outliers. Threading is used for faster affine sampling.
10
11
[1] http://www.ipol.im/pub/algo/my_affine_sift/
12
13
USAGE
14
asift.py [--feature=<sift|surf|orb|brisk>[-flann]] [ <image1> <image2> ]
15
16
--feature - Feature to use. Can be sift, surf, orb or brisk. Append '-flann'
17
to feature name to use Flann-based matcher instead bruteforce.
18
19
Press left mouse button on a feature point to see its matching point.
20
'''
21
22
# Python 2/3 compatibility
23
from __future__ import print_function
24
25
import numpy as np
26
import cv2 as cv
27
28
# built-in modules
29
import itertools as it
30
from multiprocessing.pool import ThreadPool
31
32
# local modules
33
from common import Timer
34
from find_obj import init_feature, filter_matches, explore_match
35
36
37
def affine_skew(tilt, phi, img, mask=None):
38
'''
39
affine_skew(tilt, phi, img, mask=None) -> skew_img, skew_mask, Ai
40
41
Ai - is an affine transform matrix from skew_img to img
42
'''
43
h, w = img.shape[:2]
44
if mask is None:
45
mask = np.zeros((h, w), np.uint8)
46
mask[:] = 255
47
A = np.float32([[1, 0, 0], [0, 1, 0]])
48
if phi != 0.0:
49
phi = np.deg2rad(phi)
50
s, c = np.sin(phi), np.cos(phi)
51
A = np.float32([[c,-s], [ s, c]])
52
corners = [[0, 0], [w, 0], [w, h], [0, h]]
53
tcorners = np.int32( np.dot(corners, A.T) )
54
x, y, w, h = cv.boundingRect(tcorners.reshape(1,-1,2))
55
A = np.hstack([A, [[-x], [-y]]])
56
img = cv.warpAffine(img, A, (w, h), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_REPLICATE)
57
if tilt != 1.0:
58
s = 0.8*np.sqrt(tilt*tilt-1)
59
img = cv.GaussianBlur(img, (0, 0), sigmaX=s, sigmaY=0.01)
60
img = cv.resize(img, (0, 0), fx=1.0/tilt, fy=1.0, interpolation=cv.INTER_NEAREST)
61
A[0] /= tilt
62
if phi != 0.0 or tilt != 1.0:
63
h, w = img.shape[:2]
64
mask = cv.warpAffine(mask, A, (w, h), flags=cv.INTER_NEAREST)
65
Ai = cv.invertAffineTransform(A)
66
return img, mask, Ai
67
68
69
def affine_detect(detector, img, mask=None, pool=None):
70
'''
71
affine_detect(detector, img, mask=None, pool=None) -> keypoints, descrs
72
73
Apply a set of affine transformations to the image, detect keypoints and
74
reproject them into initial image coordinates.
75
See http://www.ipol.im/pub/algo/my_affine_sift/ for the details.
76
77
ThreadPool object may be passed to speedup the computation.
78
'''
79
params = [(1.0, 0.0)]
80
for t in 2**(0.5*np.arange(1,6)):
81
for phi in np.arange(0, 180, 72.0 / t):
82
params.append((t, phi))
83
84
def f(p):
85
t, phi = p
86
timg, tmask, Ai = affine_skew(t, phi, img)
87
keypoints, descrs = detector.detectAndCompute(timg, tmask)
88
for kp in keypoints:
89
x, y = kp.pt
90
kp.pt = tuple( np.dot(Ai, (x, y, 1)) )
91
if descrs is None:
92
descrs = []
93
return keypoints, descrs
94
95
keypoints, descrs = [], []
96
if pool is None:
97
ires = it.imap(f, params)
98
else:
99
ires = pool.imap(f, params)
100
101
for i, (k, d) in enumerate(ires):
102
print('affine sampling: %d / %d\r' % (i+1, len(params)), end='')
103
keypoints.extend(k)
104
descrs.extend(d)
105
106
print()
107
return keypoints, np.array(descrs)
108
109
if __name__ == '__main__':
110
print(__doc__)
111
112
import sys, getopt
113
opts, args = getopt.getopt(sys.argv[1:], '', ['feature='])
114
opts = dict(opts)
115
feature_name = opts.get('--feature', 'brisk-flann')
116
try:
117
fn1, fn2 = args
118
except:
119
fn1 = '../data/aero1.jpg'
120
fn2 = '../data/aero3.jpg'
121
122
img1 = cv.imread(fn1, 0)
123
img2 = cv.imread(fn2, 0)
124
detector, matcher = init_feature(feature_name)
125
126
if img1 is None:
127
print('Failed to load fn1:', fn1)
128
sys.exit(1)
129
130
if img2 is None:
131
print('Failed to load fn2:', fn2)
132
sys.exit(1)
133
134
if detector is None:
135
print('unknown feature:', feature_name)
136
sys.exit(1)
137
138
print('using', feature_name)
139
140
pool=ThreadPool(processes = cv.getNumberOfCPUs())
141
kp1, desc1 = affine_detect(detector, img1, pool=pool)
142
kp2, desc2 = affine_detect(detector, img2, pool=pool)
143
print('img1 - %d features, img2 - %d features' % (len(kp1), len(kp2)))
144
145
def match_and_draw(win):
146
with Timer('matching'):
147
raw_matches = matcher.knnMatch(desc1, trainDescriptors = desc2, k = 2) #2
148
p1, p2, kp_pairs = filter_matches(kp1, kp2, raw_matches)
149
if len(p1) >= 4:
150
H, status = cv.findHomography(p1, p2, cv.RANSAC, 5.0)
151
print('%d / %d inliers/matched' % (np.sum(status), len(status)))
152
# do not draw outliers (there will be a lot of them)
153
kp_pairs = [kpp for kpp, flag in zip(kp_pairs, status) if flag]
154
else:
155
H, status = None, None
156
print('%d matches found, not enough for homography estimation' % len(p1))
157
158
explore_match(win, img1, img2, kp_pairs, None, H)
159
160
161
match_and_draw('affine find_obj')
162
cv.waitKey()
163
cv.destroyAllWindows()
164
165