|
1 |
/*
|
|
2 |
* Functions to perform affine adaptation of keypoint and to calculate descriptors of elliptic regions
|
|
3 |
*/
|
|
4 |
|
|
5 |
#include "precomp.hpp"
|
|
6 |
|
|
7 |
namespace cv
|
|
8 |
{
|
|
9 |
void calcDerivatives(const Mat& image, Mat & dx2, Mat & dxy, Mat & dy2, float si, float sd);
|
|
10 |
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat& M);
|
|
11 |
bool calcAffineAdaptation(const Mat & image, Elliptic_KeyPoint& keypoint);
|
|
12 |
float selIntegrationScale(const Mat & image, float si, Point c);
|
|
13 |
float selDifferentiationScale(const Mat & image, Mat & Lxm2smooth, Mat & Lxmysmooth, Mat & Lym2smooth, float si, Point c);
|
|
14 |
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat& Mk);
|
|
15 |
float normMaxEval(Mat & U, Mat& uVal, Mat& uVect);
|
|
16 |
|
|
17 |
/*
|
|
18 |
* Calculates derivatives according to integration scale and differentiation scale
|
|
19 |
* si - integration scale
|
|
20 |
* sd - differentiation scale
|
|
21 |
* dx2, dxy and dy2 are per-element derivatives multiplication
|
|
22 |
*/
|
|
23 |
/*void calcDerivatives(const Mat & image, Mat & dx2, Mat & dxy, Mat & dy2, float si, float sd)
|
|
24 |
{
|
|
25 |
int gsize = ceil(sd * 3) * 2 + 1;
|
|
26 |
Size ksize(gsize, gsize);
|
|
27 |
Mat L, Lx, Ly;
|
|
28 |
|
|
29 |
GaussianBlur(image, L, ksize, sd, sd);
|
|
30 |
|
|
31 |
Sobel(L, Lx, L.depth(), 1, 0, 3);//TODO era 3 messo a 1 come in harris laplace?
|
|
32 |
Lx = Lx * sd;
|
|
33 |
|
|
34 |
Sobel(L, Ly, L.depth(), 0, 1, 3);
|
|
35 |
Ly = Ly * sd;
|
|
36 |
|
|
37 |
gsize = ceil(si * 3) * 2 + 1;
|
|
38 |
ksize = Size(gsize, gsize);
|
|
39 |
|
|
40 |
Mat Lxm2 = Lx.mul(Lx);
|
|
41 |
GaussianBlur(Lxm2, dx2, ksize, si, si, BORDER_REPLICATE);
|
|
42 |
|
|
43 |
Mat Lym2 = Ly.mul(Ly);
|
|
44 |
GaussianBlur(Lym2, dy2, ksize, si, si, BORDER_REPLICATE);
|
|
45 |
|
|
46 |
Mat Lxmy = Lx.mul(Ly);
|
|
47 |
GaussianBlur(Lxmy, dxy, ksize, si, si, BORDER_REPLICATE);
|
|
48 |
|
|
49 |
}*/
|
|
50 |
|
|
51 |
/*
|
|
52 |
* Calculates second moments matrix in point p
|
|
53 |
*/
|
|
54 |
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat & M)
|
|
55 |
{
|
|
56 |
int x = p.x;
|
|
57 |
int y = p.y;
|
|
58 |
|
|
59 |
M.create(2, 2, CV_32FC1);
|
|
60 |
M.at<float> (0, 0) = dx2.at<float> (y, x);
|
|
61 |
M.at<float> (0, 1) = M.at<float> (1, 0) = dxy.at<float> (y, x);
|
|
62 |
M.at<float> (1, 1) = dy2.at<float> (y, x);
|
|
63 |
}
|
|
64 |
|
|
65 |
/*
|
|
66 |
* Performs affine adaptation
|
|
67 |
*/
|
|
68 |
bool calcAffineAdaptation(const Mat & fimage, Elliptic_KeyPoint & keypoint)
|
|
69 |
{
|
|
70 |
Mat_<float> transf(2, 3)/*Trasformation matrix*/,
|
|
71 |
size(2, 1)/*Image size after transformation*/, c(2, 1)/*Transformed point*/, p(2, 1) /*Image point*/;
|
|
72 |
Mat U = Mat::eye(2, 2, CV_32F) * 1;
|
|
73 |
|
|
74 |
Mat warpedImg, Mk, Lxm2smooth, Lym2smooth, Lxmysmooth, img_roi;
|
|
75 |
float Qinv = 1, q, si = keypoint.si, sd = 0.75 * si;
|
|
76 |
bool divergence = false, convergence = false;
|
|
77 |
int i = 0;
|
|
78 |
|
|
79 |
//Coordinates in image
|
|
80 |
int py = keypoint.centre.y;
|
|
81 |
int px = keypoint.centre.x;
|
|
82 |
|
|
83 |
//Roi coordinates
|
|
84 |
int roix, roiy;
|
|
85 |
|
|
86 |
//Coordinates in U-trasformation
|
|
87 |
int cx = px;
|
|
88 |
int cy = py;
|
|
89 |
int cxPr = cx;
|
|
90 |
int cyPr = cy;
|
|
91 |
|
|
92 |
float radius = keypoint.size * 1.4;
|
|
93 |
float half_width, half_height;
|
|
94 |
|
|
95 |
Rect roi;
|
|
96 |
|
|
97 |
//Affine adaptation
|
|
98 |
while (i <= 10 && !divergence && !convergence)
|
|
99 |
{
|
|
100 |
//Transformation matrix creation
|
|
101 |
transf.setTo(0);
|
|
102 |
Mat col0 = transf.col(0);
|
|
103 |
U.col(0).copyTo(col0);
|
|
104 |
Mat col1 = transf.col(1);
|
|
105 |
U.col(1).copyTo(col1);
|
|
106 |
keypoint.transf = Mat(transf);
|
|
107 |
|
|
108 |
//Create window around interest point
|
|
109 |
half_width = min((float) min(fimage.cols - px, px), ceil(radius) + 10);
|
|
110 |
half_height = min((float) min(fimage.rows - py, py), ceil(radius) + 10);
|
|
111 |
roix = max(px - (int) half_width, 0);
|
|
112 |
roiy = max(py - (int) half_height, 0);
|
|
113 |
roi = Rect(roix, roiy, px - roix + half_width, py - roiy + half_height);
|
|
114 |
img_roi = fimage(roi);
|
|
115 |
|
|
116 |
//Point within the Roi
|
|
117 |
p(0, 0) = px - roix;
|
|
118 |
p(1, 0) = py - roiy;
|
|
119 |
|
|
120 |
if (half_width <= 0 || half_height <= 0)
|
|
121 |
return divergence;
|
|
122 |
|
|
123 |
//Size of normalized window
|
|
124 |
size(0, 0) = img_roi.cols;
|
|
125 |
size(1, 0) = img_roi.rows;
|
|
126 |
size = U * size;
|
|
127 |
|
|
128 |
//Size of normalized window must be 2*si*3
|
|
129 |
if (ceil(size(0, 0)) >= 2 * radius && ceil(size(1, 0)) >= 2 * radius)
|
|
130 |
{
|
|
131 |
//Transformation
|
|
132 |
Mat warpedImgRoi;
|
|
133 |
warpAffine(img_roi, warpedImgRoi, transf, Size(ceil(size(0, 0)), ceil(size(1, 0))),
|
|
134 |
INTER_AREA, BORDER_DEFAULT);
|
|
135 |
|
|
136 |
//Point in U-Normalized coordinates
|
|
137 |
c = U * p;
|
|
138 |
cx = c(0, 0);
|
|
139 |
cy = c(1, 0);
|
|
140 |
|
|
141 |
//Cut around normalized patch
|
|
142 |
roix = std::max(cx - si * 3 * 1.4, 0.0);
|
|
143 |
roiy = std::max(cy - si * 3 * 1.4, 0.0);
|
|
144 |
roi = Rect(roix, roiy, std::min(cx - roix + si * 3 * 1.4, (double) size(0, 0)),
|
|
145 |
std::min(cy - roiy + si * 3 * 1.4, (double) size(1, 0)));
|
|
146 |
warpedImg = warpedImgRoi(roi);
|
|
147 |
|
|
148 |
//Point's coordinates in cutted window
|
|
149 |
cx = c(0, 0) - roix;
|
|
150 |
cy = c(1, 0) - roiy;
|
|
151 |
|
|
152 |
//Integration Scale selection
|
|
153 |
si = selIntegrationScale(warpedImg, si, Point(cx, cy));
|
|
154 |
|
|
155 |
//Differentation scale selection
|
|
156 |
sd = selDifferentiationScale(warpedImg, Lxm2smooth, Lxmysmooth, Lym2smooth, si, Point(
|
|
157 |
cx, cy));
|
|
158 |
|
|
159 |
//Spatial Localization
|
|
160 |
cxPr = cx;
|
|
161 |
cyPr = cy;
|
|
162 |
|
|
163 |
float cornMax = 0;
|
|
164 |
for (int j = 0; j < 3; j++)
|
|
165 |
{
|
|
166 |
for (int t = 0; t < 3; t++)
|
|
167 |
{
|
|
168 |
float dx2 = Lxm2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
|
|
169 |
float dy2 = Lym2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
|
|
170 |
float dxy = Lxmysmooth.at<float> (cyPr - 1 + j, cxPr - 1 + t);
|
|
171 |
float det = dx2 * dy2 - dxy * dxy;
|
|
172 |
float tr = dx2 + dy2;
|
|
173 |
float cornerness = det - (0.04 * pow(tr, 2));
|
|
174 |
if (cornerness > cornMax)
|
|
175 |
{
|
|
176 |
cornMax = cornerness;
|
|
177 |
cx = cxPr - 1 + t;
|
|
178 |
cy = cyPr - 1 + j;
|
|
179 |
}
|
|
180 |
}
|
|
181 |
}
|
|
182 |
|
|
183 |
//Transform point in image coordinates
|
|
184 |
p(0, 0) = px;
|
|
185 |
p(1, 0) = py;
|
|
186 |
//Displacement vector
|
|
187 |
c(0, 0) = cx - cxPr;
|
|
188 |
c(1, 0) = cy - cyPr;
|
|
189 |
//New interest point location in image
|
|
190 |
p = p + U.inv() * c;
|
|
191 |
px = p(0, 0);
|
|
192 |
py = p(1, 0);
|
|
193 |
|
|
194 |
q = calcSecondMomentSqrt(Lxm2smooth, Lxmysmooth, Lym2smooth, Point(cx, cy), Mk);
|
|
195 |
|
|
196 |
float ratio = 1 - q;
|
|
197 |
|
|
198 |
//if ratio == 1 means q == 0 and one axes equals to 0
|
|
199 |
if (!isnan(ratio) && ratio != 1)
|
|
200 |
{
|
|
201 |
//Update U matrix
|
|
202 |
U = U * Mk;
|
|
203 |
|
|
204 |
Mat uVal, uV;
|
|
205 |
eigen(U, uVal, uV);
|
|
206 |
|
|
207 |
Qinv = normMaxEval(U, uVal, uV);
|
|
208 |
//Keypoint doesn't converge
|
|
209 |
if (Qinv >= 6)
|
|
210 |
divergence = true;
|
|
211 |
//Keypoint converges
|
|
212 |
else if (ratio <= 0.05)
|
|
213 |
{
|
|
214 |
convergence = true;
|
|
215 |
|
|
216 |
//Set transformation matrix
|
|
217 |
transf.setTo(0);
|
|
218 |
Mat col0 = transf.col(0);
|
|
219 |
U.col(0).copyTo(col0);
|
|
220 |
Mat col1 = transf.col(1);
|
|
221 |
U.col(1).copyTo(col1);
|
|
222 |
keypoint.transf = Mat(transf);
|
|
223 |
|
|
224 |
float ax1 = 1. / std::abs(uVal.at<float> (0, 0)) * 3 * si;
|
|
225 |
float ax2 = 1. / std::abs(uVal.at<float> (1, 0)) * 3 * si;
|
|
226 |
double phi = atan(uV.at<float> (1, 0) / uV.at<float> (0, 0)) * (180) / CV_PI;
|
|
227 |
keypoint.axes = Size(ax1, ax2);
|
|
228 |
keypoint.phi = phi;
|
|
229 |
keypoint.centre = Point(px, py);
|
|
230 |
keypoint.si = si;
|
|
231 |
keypoint.size = 3 * si;
|
|
232 |
} else
|
|
233 |
radius = 3 * si * 1.4;
|
|
234 |
|
|
235 |
} else
|
|
236 |
divergence = true;
|
|
237 |
} else
|
|
238 |
divergence = true;
|
|
239 |
++i;
|
|
240 |
}
|
|
241 |
|
|
242 |
return convergence;
|
|
243 |
}
|
|
244 |
|
|
245 |
/*
|
|
246 |
* Selects the integration scale that maximize LoG in point c
|
|
247 |
*/
|
|
248 |
float selIntegrationScale(const Mat & image, float si, Point c)
|
|
249 |
{
|
|
250 |
Mat Lap, L;
|
|
251 |
int cx = c.x;
|
|
252 |
int cy = c.y;
|
|
253 |
float maxLap = 0;
|
|
254 |
float maxsx = si;
|
|
255 |
int gsize;
|
|
256 |
float sigma, sigma_prev = 0;
|
|
257 |
|
|
258 |
image.copyTo(L);
|
|
259 |
/* Search best integration scale between previous and successive layer
|
|
260 |
*/
|
|
261 |
for (float u = 0.7; u <= 1.41; u += 0.1)
|
|
262 |
{
|
|
263 |
float sik = u * si;
|
|
264 |
sigma = sqrt(powf(sik, 2) - powf(sigma_prev, 2));
|
|
265 |
|
|
266 |
gsize = ceil(sigma * 3) * 2 + 1;
|
|
267 |
|
|
268 |
GaussianBlur(L, L, Size(gsize, gsize), sigma);
|
|
269 |
sigma_prev = sik;
|
|
270 |
|
|
271 |
Laplacian(L, Lap, CV_32F, 3);
|
|
272 |
|
|
273 |
float lapVal = sik * sik * std::abs(Lap.at<float> (cy, cx));
|
|
274 |
|
|
275 |
if (u == 0.7)
|
|
276 |
maxLap = lapVal;
|
|
277 |
|
|
278 |
if (lapVal >= maxLap)
|
|
279 |
{
|
|
280 |
maxLap = lapVal;
|
|
281 |
maxsx = sik;
|
|
282 |
|
|
283 |
}
|
|
284 |
|
|
285 |
}
|
|
286 |
return maxsx;
|
|
287 |
}
|
|
288 |
|
|
289 |
/*
|
|
290 |
* Calculates second moments matrix square root
|
|
291 |
*/
|
|
292 |
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Mat & Mk)
|
|
293 |
{
|
|
294 |
Mat M, V, eigVal, Vinv, D;
|
|
295 |
|
|
296 |
calcSecondMomentMatrix(dx2, dxy, dy2, p, M);
|
|
297 |
|
|
298 |
/* *
|
|
299 |
* M = V * D * V.inv()
|
|
300 |
* V has eigenvectors as columns
|
|
301 |
* D is a diagonal Matrix with eigenvalues as elements
|
|
302 |
* V.inv() is the inverse of V
|
|
303 |
* */
|
|
304 |
|
|
305 |
eigen(M, eigVal, V);
|
|
306 |
V = V.t();
|
|
307 |
Vinv = V.inv();
|
|
308 |
|
|
309 |
float eval1 = eigVal.at<float> (0, 0) = sqrt(eigVal.at<float> (0, 0));
|
|
310 |
float eval2 = eigVal.at<float> (1, 0) = sqrt(eigVal.at<float> (1, 0));
|
|
311 |
|
|
312 |
D = Mat::diag(eigVal);
|
|
313 |
|
|
314 |
//square root of M
|
|
315 |
Mk = V * D * Vinv;
|
|
316 |
//return q isotropic measure
|
|
317 |
return min(eval1, eval2) / max(eval1, eval2);
|
|
318 |
}
|
|
319 |
|
|
320 |
float normMaxEval(Mat & U, Mat & uVal, Mat & uVec)
|
|
321 |
{
|
|
322 |
/* *
|
|
323 |
* Decomposition:
|
|
324 |
* U = V * D * V.inv()
|
|
325 |
* V has eigenvectors as columns
|
|
326 |
* D is a diagonal Matrix with eigenvalues as elements
|
|
327 |
* V.inv() is the inverse of V
|
|
328 |
* */
|
|
329 |
uVec = uVec.t();
|
|
330 |
Mat uVinv = uVec.inv();
|
|
331 |
|
|
332 |
//Normalize min eigenvalue to 1 to expand patch in the direction of min eigenvalue of U.inv()
|
|
333 |
double uval1 = uVal.at<float> (0, 0);
|
|
334 |
double uval2 = uVal.at<float> (1, 0);
|
|
335 |
|
|
336 |
if (std::abs(uval1) < std::abs(uval2))
|
|
337 |
{
|
|
338 |
uVal.at<float> (0, 0) = 1;
|
|
339 |
uVal.at<float> (1, 0) = uval2 / uval1;
|
|
340 |
|
|
341 |
} else
|
|
342 |
{
|
|
343 |
uVal.at<float> (1, 0) = 1;
|
|
344 |
uVal.at<float> (0, 0) = uval1 / uval2;
|
|
345 |
|
|
346 |
}
|
|
347 |
|
|
348 |
Mat D = Mat::diag(uVal);
|
|
349 |
//U normalized
|
|
350 |
U = uVec * D * uVinv;
|
|
351 |
|
|
352 |
return max(std::abs(uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))) / min(std::abs(
|
|
353 |
uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))); //define the direction of warping
|
|
354 |
}
|
|
355 |
|
|
356 |
/*
|
|
357 |
* Selects diffrentiation scale
|
|
358 |
*/
|
|
359 |
float selDifferentiationScale(const Mat & img, Mat & Lxm2smooth, Mat & Lxmysmooth,
|
|
360 |
Mat & Lym2smooth, float si, Point c)
|
|
361 |
{
|
|
362 |
float s = 0.5;
|
|
363 |
float sdk = s * si;
|
|
364 |
float sigma_prev = 0, sigma;
|
|
365 |
|
|
366 |
Mat L, dx2, dxy, dy2;
|
|
367 |
|
|
368 |
double qMax = 0;
|
|
369 |
|
|
370 |
//Gaussian kernel size
|
|
371 |
int gsize;
|
|
372 |
Size ksize;
|
|
373 |
|
|
374 |
img.copyTo(L);
|
|
375 |
|
|
376 |
while (s <= 0.751)
|
|
377 |
{
|
|
378 |
Mat M;
|
|
379 |
float sd = s * si;
|
|
380 |
|
|
381 |
//Smooth previous smoothed image L
|
|
382 |
sigma = sqrt(powf(sd, 2) - powf(sigma_prev, 2));
|
|
383 |
|
|
384 |
gsize = ceil(sigma * 3) * 2 + 1;
|
|
385 |
GaussianBlur(L, L, Size(gsize, gsize), sigma);
|
|
386 |
|
|
387 |
sigma_prev = sd;
|
|
388 |
|
|
389 |
//X and Y derivatives
|
|
390 |
Mat Lx, Ly;
|
|
391 |
Sobel(L, Lx, L.depth(), 1, 0, 3);
|
|
392 |
Lx = Lx * sd;
|
|
393 |
Sobel(L, Ly, L.depth(), 0, 1, 3);
|
|
394 |
Ly = Ly * sd;
|
|
395 |
|
|
396 |
//Size of gaussian kernel
|
|
397 |
gsize = ceil(si * 3) * 2 + 1;
|
|
398 |
ksize = Size(gsize, gsize);
|
|
399 |
|
|
400 |
Mat Lxm2 = Lx.mul(Lx);
|
|
401 |
GaussianBlur(Lxm2, dx2, ksize, si, si, BORDER_REPLICATE);
|
|
402 |
|
|
403 |
Mat Lym2 = Ly.mul(Ly);
|
|
404 |
GaussianBlur(Lym2, dy2, ksize, si, si, BORDER_REPLICATE);
|
|
405 |
|
|
406 |
Mat Lxmy = Lx.mul(Ly);
|
|
407 |
GaussianBlur(Lxmy, dxy, ksize, si, si, BORDER_REPLICATE);
|
|
408 |
|
|
409 |
calcSecondMomentMatrix(dx2, dxy, dy2, Point(c.x, c.y), M);
|
|
410 |
|
|
411 |
//calc eigenvalues
|
|
412 |
Mat eval;
|
|
413 |
eigen(M, eval);
|
|
414 |
double eval1 = std::abs(eval.at<float> (0, 0));
|
|
415 |
double eval2 = std::abs(eval.at<float> (1, 0));
|
|
416 |
double q = min(eval1, eval2) / max(eval1, eval2);
|
|
417 |
|
|
418 |
if (q >= qMax)
|
|
419 |
{
|
|
420 |
qMax = q;
|
|
421 |
sdk = sd;
|
|
422 |
dx2.copyTo(Lxm2smooth);
|
|
423 |
dxy.copyTo(Lxmysmooth);
|
|
424 |
dy2.copyTo(Lym2smooth);
|
|
425 |
|
|
426 |
}
|
|
427 |
|
|
428 |
s += 0.05;
|
|
429 |
}
|
|
430 |
|
|
431 |
return sdk;
|
|
432 |
}
|
|
433 |
|
|
434 |
void calcAffineCovariantRegions(const Mat & image, const vector<KeyPoint> & keypoints, vector<
|
|
435 |
Elliptic_KeyPoint> & affRegions, string detector_type)
|
|
436 |
{
|
|
437 |
|
|
438 |
for (size_t i = 0; i < keypoints.size(); ++i)
|
|
439 |
{
|
|
440 |
KeyPoint kp = keypoints[i];
|
|
441 |
Elliptic_KeyPoint ex(kp.pt, 0, Size(kp.size, kp.size), kp.size, kp.size / 3);
|
|
442 |
|
|
443 |
if (calcAffineAdaptation(image, ex))
|
|
444 |
{
|
|
445 |
affRegions.push_back(ex);
|
|
446 |
}
|
|
447 |
}
|
|
448 |
}
|
|
449 |
|
|
450 |
void calcAffineCovariantDescriptors(const Ptr<DescriptorExtractor>& dextractor, const Mat& img,
|
|
451 |
vector<Elliptic_KeyPoint>& affRegions, Mat& descriptors)
|
|
452 |
{
|
|
453 |
|
|
454 |
assert(!affRegions.empty());
|
|
455 |
int size = dextractor->descriptorSize();
|
|
456 |
int type = dextractor->descriptorType();
|
|
457 |
descriptors = Mat(Size(size, affRegions.size()), type);
|
|
458 |
descriptors.setTo(0);
|
|
459 |
|
|
460 |
int i = 0;
|
|
461 |
|
|
462 |
for (vector<Elliptic_KeyPoint>::iterator it = affRegions.begin(); it < affRegions.end(); ++it)
|
|
463 |
{
|
|
464 |
Point p = it->centre;
|
|
465 |
|
|
466 |
Mat_<float> size(2, 1);
|
|
467 |
size(0, 0) = size(1, 0) = it->size;
|
|
468 |
|
|
469 |
//U matrix
|
|
470 |
Mat transf = it->transf;
|
|
471 |
Mat_<float> U(2, 2);
|
|
472 |
U.setTo(0);
|
|
473 |
Mat col0 = U.col(0);
|
|
474 |
transf.col(0).copyTo(col0);
|
|
475 |
Mat col1 = U.col(1);
|
|
476 |
transf.col(1).copyTo(col1);
|
|
477 |
|
|
478 |
float radius = it->size;
|
|
479 |
|
|
480 |
float half_width = min((float) min(img.cols - p.x, p.x), ceil(radius) + 10);
|
|
481 |
float half_height = min((float) min(img.rows - p.y, p.y), ceil(radius) + 10);
|
|
482 |
float roix = max(p.x - (int) half_width, 0);
|
|
483 |
float roiy = max(p.y - (int) half_height, 0);
|
|
484 |
Rect roi(roix, roiy, p.x - roix + half_width, p.y - roiy + half_height);
|
|
485 |
Mat img_roi = img(roi);
|
|
486 |
|
|
487 |
size(0, 0) = img_roi.cols;
|
|
488 |
size(1, 0) = img_roi.rows;
|
|
489 |
|
|
490 |
size = U * size;
|
|
491 |
|
|
492 |
Mat transfImgRoi, transfImg;
|
|
493 |
warpAffine(img_roi, transfImgRoi, transf, Size(ceil(size(0, 0)), ceil(size(1, 0))),
|
|
494 |
INTER_AREA, BORDER_DEFAULT);
|
|
495 |
|
|
496 |
//Trasformazione
|
|
497 |
Mat_<float> c(2, 1); //Transformed point
|
|
498 |
Mat_<float> pt(2, 1); //Image point
|
|
499 |
//Point within the Roi
|
|
500 |
pt(0, 0) = p.x - roix;
|
|
501 |
pt(1, 0) = p.y - roiy;
|
|
502 |
|
|
503 |
//Point in U-Normalized coordinates
|
|
504 |
c = U * pt;
|
|
505 |
float cx = c(0, 0);
|
|
506 |
float cy = c(1, 0);
|
|
507 |
|
|
508 |
//Cut around point to have patch of 2*keypoint->size
|
|
509 |
|
|
510 |
roix = std::max(cx - radius, 0.f);
|
|
511 |
roiy = std::max(cy - radius, 0.f);
|
|
512 |
|
|
513 |
roi = Rect(roix, roiy, std::min(cx - roix + radius, size(0, 0)), std::min(cy - roiy
|
|
514 |
+ radius, size(1, 0)));
|
|
515 |
transfImg = transfImgRoi(roi);
|
|
516 |
|
|
517 |
cx = c(0, 0) - roix;
|
|
518 |
cy = c(1, 0) - roiy;
|
|
519 |
|
|
520 |
Mat tmpDesc;
|
|
521 |
KeyPoint kp(Point(cx, cy), it->size);
|
|
522 |
|
|
523 |
vector<KeyPoint> k(1, kp);
|
|
524 |
|
|
525 |
transfImg.convertTo(transfImg, CV_8U);
|
|
526 |
dextractor->compute(transfImg, k, tmpDesc);
|
|
527 |
|
|
528 |
for (int j = 0; j < tmpDesc.cols; j++)
|
|
529 |
{
|
|
530 |
descriptors.at<float> (i, j) = tmpDesc.at<float> (0, j);
|
|
531 |
}
|
|
532 |
|
|
533 |
i++;
|
|
534 |
|
|
535 |
}
|
|
536 |
|
|
537 |
}
|
|
538 |
}
|