-
Notifications
You must be signed in to change notification settings - Fork 96
/
PointFeature.m
323 lines (278 loc) · 10.5 KB
/
PointFeature.m
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
%PointFeature PointCorner feature object
%
% A superclass for image corner features.
%
% Methods::
% plot Plot feature position
% distance Descriptor distance
% ncc Descriptor similarity
% uv Return feature coordinate
% display Display value
% char Convert value to string
%
% Properties::
% u horizontal coordinate
% v vertical coordinate
% strength feature strength
% descriptor feature descriptor (vector)
%
% Properties of a vector of PointFeature objects are returned as a vector.
% If F is a vector (Nx1) of PointFeature objects then F.u is a 2xN matrix
% with each column the corresponding point coordinate.
%
% See also ScalePointFeature, SurfPointFeature, SiftPointFeature.
% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB. If not, see <http://www.gnu.org/licenses/>.
classdef PointFeature < handle
properties %(GetAccess=protected)%, Hidden=true)
u_ % feature x-coordinates
v_ % feature y-coordinates
strength_
descriptor_
image_id_
end % properties
methods
function f = PointFeature(u, v, strength)
%PointFeature.PointFeature Create a point feature object
%
% F = PointFeature() is a point feature object with null parameters.
%
% F = PointFeature(U, V) is a point feature object with specified
% coordinates.
%
% F = PointFeature(U, V, STRENGTH) as above but with specified strength.
if nargin == 0
return;
end
if nargin >= 2
f.u_ = u;
f.v_ = v;
end
if nargin == 3
f.strength_ = strength;
end
end
function val = uv(features)
val = [[features.u]; [features.v]];
end
function plot(features, varargin)
%PointFeature.plot Plot feature
%
% F.plot() overlay a white square marker at the feature position.
%
% F.plot(LS) as above but the optional line style arguments LS are
% passed to plot.
%
% If F is a vector then each element is plotted.
holdon = ishold;
hold on
if nargin == 1
varargin = {'ws'};
end
for i=1:length(features)
plot(features(i).u_, features(i).v_, varargin{:});
end
if ~holdon
hold off
end
end % plot
function s = distance(f1, f2)
%PointFeature.distance Distance between feature descriptors
%
% D = F.distance(F1) is the distance between feature descriptors, the norm
% of the Euclidean distance.
%
% If F is a vector then D is a vector whose elements are the distance between
% the corresponding element of F and F1.
for i=1:length(f2)
s(i) = norm(f1.descriptor-f2(i).descriptor);
end
end
function s = ncc(f1, f2)
%PointFeature.ncc Feature descriptor similarity
%
% S = F.ncc(F1) is the similarty between feature descriptors which is a
% scalar in the interval -1 to 1, where 1 is perfect match.
%
% If F is a vector then D is a vector whose elements are the distance between
% the corresponding element of F and F1.
for i=1:length(f2)
s(i) = dot(f1.descriptor,f2(i).descriptor);
end
end
function [m,corresp] = match(f1, f2, varargin)
%PointFeature.match Match point features
%
% M = F.match(F2, OPTIONS) is a vector of FeatureMatch objects that
% describe candidate matches between the two vectors of point
% features F and F2.
%
% [M,C] = F.match(F2, OPTIONS) as above but returns a correspodence
% matrix where each row contains the indices of corresponding features
% in F and F2 respectively.
%
% Options::
% 'thresh',T Match threshold (default 0.05)
% 'median' Threshold at the median distance
% 'top',N Take top N features
%
% See also FeatureMatch.
% TODO: should use a kd-tree or FLANN
opt.bilateral = false;
opt = tb_optparse(opt, varargin);
if opt.bilateral
% bilateral matching, best match of f1 in f2 must be best match back in f1
matches = [];
d = distance([f1.descriptor], [f2.descriptor]);
for i=1:numrows(d)
% find smallest element in the row
[best,ii] = min(d(i,:));
[~,jj] = min(d(:,ii));
if jj == i
% we have a match
row = d(i,:);
row(ii) = Inf;
nextbest = min(row);
if nextbest < 0.7*best
matches = [matches [i; ii]];
end
end
end
else
[matches,dist,dist2] = closest([f1.descriptor], [f2.descriptor]);
matches = [1:length(f1); matches];
% delete matches where distance of closest match is greater than
% 0.7 of second closest match
k = dist > 0.7 * dist2;
matches(:,k) = [];
dist(k) = [];
end
% dist is a 1xM matrix of distance between the matched features, low is good.
% matches is a 2xM matrix, one column per match, each column
% is the index of the matching feature in images 1 and 2
% sort into increasing distance
[z,k] = sort(dist, 'ascend');
matches = matches(:,k);
dist = dist(:,k);
m = [];
cor = [];
for i=1:numcols(matches)
k1 = matches(1,i);
k2 = matches(2,i);
mm = FeatureMatch(f1(k1), f2(k2), dist(i));
m = [m mm];
cor(:,i) = [k1 k2]';
end
if nargout > 1
corresp = cor;
end
end
% methods to provide convenient access to properties of object vectors
function val = u(f)
val = [f.u_];
end
function val = v(f)
val = [f.v_];
end
function val = p(f)
val = [[f.u_]; [f.v_]];
end
function val = strength(f)
val = [f.strength_];
end
function val = descriptor(f)
val = [f.descriptor_];
end
function fp = pick(f, uv)
%PointFeature.pick Graphically select a feature
%
% V = F.pick() is the id of the feature closest to the point clicked
% by the user on a plot of the image.
%
if nargin < 2
[u,v] = ginput(1);
uv = f.uv;
end
k = closest([u v]', uv);
fp = f(k);
end
function display(f)
%PointFeature.display Display value
%
% F.display() displays a compact human-readable representation of the feature.
% If F is a vector then the elements are printed one per line.
%
% Notes::
% - This method is invoked implicitly at the command line when the result
% of an expression is a PointFeature object and the command has no trailing
% semicolon.
%
% See also PointFeature.char.
disp(' ');
disp([inputname(1), ' = '])
disp(' ');
if length(f) > 20
fprintf('%d features (listing suppressed)\n Properties:', length(f));
for property=fieldnames(f)'
fprintf(' %s', property{1}(1:end-1));
end
fprintf('\n');
else
disp( char(f) );
end
end % display()
function ss = char(features)
%PointFeature.char Convert to string
%
% S = F.char() is a compact string representation of the point feature.
% If F is a vector then the string has multiple lines, one per element.
ss = [];
for i=1:length(features)
f = features(i);
% display the coordinate
s = sprintf(' (%g,%g)', f.u_, f.v_);
% display the other properties
for property=fieldnames(f)'
prop = property{1}; % convert from cell array
switch prop
case {'u_', 'v_', 'descriptor_'}
continue;
otherwise
val = getfield(f, prop);
if ~isempty(val)
s = strcat(s, [sprintf(', %s=', prop(1:end-1)), num2str(val, ' %g')]);
end
end
end
% do the descriptor last
val = getfield(f, 'descriptor_');
if ~isempty(val)
if length(val) == 1
% only list scalars or shortish vectors
s = strcat(s, [', descrip=', num2str(val, ' %g')]);
elseif length(val) < 4
% only list scalars or shortish vectors
s = strcat(s, [', descrip=(', num2str(val', ' %g'), ')']);
else
s = strcat(s, ', descrip= ..');
end
end
ss = strvcat(ss, s);
end
end
end % methods
end % classdef