2 Copyright 2005, 2006 Computer Vision Lab,
3 Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland.
6 This file is part of BazAR.
8 BazAR is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
13 BazAR is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along with
18 BazAR; if not, write to the Free Software Foundation, Inc., 51 Franklin
19 Street, Fifth Floor, Boston, MA 02110-1301, USA
23 * Vincent Lepetit <vincent.lepetit@epfl.ch>
39 #include "../../artvertiser/FProfiler/FProfiler.h"
41 const unsigned int yape_bin_size
= 1000;
42 const int yape_tmp_points_array_size
= 10000;
44 bool operator <(const keypoint
&p1
, const keypoint
&p2
)
46 return p1
.score
> p2
.score
;
49 yape::yape(int _width
, int _height
)
56 minimal_neighbor_number
= 4;
59 set_bins_number(4, 4);
61 disactivate_subpixel();
63 set_minimal_neighbor_number(3);
70 if (Dirs
) delete Dirs
;
71 if (Dirs_nb
) delete[] Dirs_nb
;
72 if (scores
) cvReleaseImage(&scores
);
73 if (filtered_image
) cvReleaseImage(&filtered_image
);
74 if (raw_detect_thread_data
.size()>0)
77 for ( int i
=0; i
<raw_detect_thread_data
.size(); i
++ )
79 delete raw_detect_thread_data
[i
];
81 raw_detect_thread_data
.clear();
82 delete shared_barrier
;
86 int yape::static_detect(IplImage
* image
, keypoint
* points
, int max_point_number
, int _radius
, int _tau
)
88 yape
* pe
= new yape(image
->width
, image
->height
);
90 pe
->set_radius(_radius
);
92 int point_number
= pe
->detect(image
, points
, max_point_number
);
99 void yape::set_radius(int _radius
)
104 void yape::set_tau(int _tau
)
109 void yape::init_for_monoscale(void)
111 scores
= cvCreateImage(cvSize(width
, height
), IPL_DEPTH_16S
, 1);
112 filtered_image
= cvCreateImage(cvSize(width
, height
), IPL_DEPTH_8U
, 1);
114 Dirs
= new dir_table
;
115 memset(Dirs
,0,sizeof(dir_table
));
116 Dirs_nb
= new int[yape_max_radius
];
117 memset(Dirs_nb
,0,sizeof(int)*yape_max_radius
);
118 for(int R
= 1; R
< yape_max_radius
; R
++)
119 precompute_directions(filtered_image
, Dirs
->t
[R
], &(Dirs_nb
[R
]), R
);
122 void yape::reserve_tmp_arrays(void)
125 for(int i
= 0; i
< bin_nb_u
; i
++)
126 for(int j
= 0; j
< bin_nb_v
; j
++)
129 bins
[i
][j
].reserve(yape_bin_size
);
134 tmp_points
.reserve(yape_tmp_points_array_size
);
138 void yape::precompute_directions(IplImage
* image
, short * _Dirs
, int * _Dirs_nb
, int R
)
140 int widthStep
= image
->widthStep
;
146 for(y
= 0; y
< x
; y
++, i
++)
148 x
= int(sqrt(double(R
* R
- y
* y
)) + 0.5);
149 _Dirs
[i
] = short(x
+ widthStep
* y
);
151 for(x
-- ; x
< y
&& x
>= 0; x
--, i
++)
153 y
= int(sqrt(double(R
* R
- x
* x
)) + 0.5);
154 _Dirs
[i
] = short(x
+ widthStep
* y
);
156 for( ; -x
< y
; x
--, i
++)
158 y
= int(sqrt(double(R
* R
- x
* x
)) + 0.5);
159 _Dirs
[i
] = short(x
+ widthStep
* y
);
161 for(y
-- ; y
>= 0; y
--, i
++)
163 x
= int(-sqrt(double(R
* R
- y
* y
)) - 0.5);
164 _Dirs
[i
] = short(x
+ widthStep
* y
);
166 for(; y
> x
; y
--, i
++)
168 x
= int(-sqrt(double(R
* R
- y
* y
)) - 0.5);
169 _Dirs
[i
] = short(x
+ widthStep
* y
);
171 for(x
++ ; x
<= 0; x
++, i
++)
173 y
= int(-sqrt(double(R
* R
- x
* x
)) - 0.5);
174 _Dirs
[i
] = short(x
+ widthStep
* y
);
176 for( ; x
< -y
; x
++, i
++)
178 y
= int(-sqrt(double(R
* R
- x
* x
)) - 0.5);
179 _Dirs
[i
] = short(x
+ widthStep
* y
);
181 for(y
++ ; y
< 0; y
++, i
++)
183 x
= int(sqrt(double(R
* R
- y
* y
)) + 0.5);
184 _Dirs
[i
] = short(x
+ widthStep
* y
);
189 _Dirs
[i
+ 1] = _Dirs
[1];
192 void yape::save_image_of_detected_points(char * name
, IplImage
* image
, keypoint
* points
, int points_nb
)
194 IplImage
* color_image
= mcvGrayToColor(image
);
196 for(int i
= 0; i
< points_nb
; i
++) {
197 int s
= (int)points
[i
].scale
;
198 float x
= PyrImage::convCoordf(points
[i
].u
, s
, 0);
199 float y
= PyrImage::convCoordf(points
[i
].v
, s
, 0);
200 float l
= PyrImage::convCoordf(32.0f
, s
, 0);
202 mcvCircle(color_image
, int(x
), int(y
), (int)l
, mcvRainbowColor(s
% 7));
205 mcvSaveImage(name
, color_image
);
208 bool yape::double_check(IplImage
* image
, int x
, int y
, short * dirs
, unsigned char dirs_nb
)
210 unsigned char * I
= (unsigned char *)(image
->imageData
+ y
* image
->widthStep
);
215 for(A
= dirs_nb
/ 2 - 2; A
<= dirs_nb
/ 2 + 2; A
++)
216 for(int i
= 0; i
< dirs_nb
- A
; i
++)
218 if (I
[x
+dirs
[i
]] > Im
&& I
[x
+dirs
[i
]] < Ip
&& I
[x
+dirs
[i
+A
]] > Im
&& I
[x
+dirs
[i
+A
]] < Ip
)
225 #define A_INF (A < Im)
226 #define A_SUP (A > Ip)
227 #define A_NOT_INF (A >= Im)
228 #define A_NOT_SUP (A <= Ip)
230 #define B0_INF (B0 < Im)
231 #define B0_SUP (B0 > Ip)
232 #define B0_NOT_INF (B0 >= Im)
233 #define B0_NOT_SUP (B0 <= Ip)
235 #define B1_INF (B1 < Im)
236 #define B1_SUP (B1 > Ip)
237 #define B1_NOT_INF (B1 >= Im)
238 #define B1_NOT_SUP (B1 <= Ip)
240 #define B2_INF (B2 < Im)
241 #define B2_SUP (B2 > Ip)
242 #define B2_NOT_INF (B2 >= Im)
243 #define B2_NOT_SUP (B2 <= Ip)
245 #define GET_A_old() A = I[x+dirs[a]]
246 #define GET_B0_old() B0 = I[x+dirs[b]]
247 #define GET_B1_old() b++; B1 = I[x+dirs[b]]
248 #define GET_B2_old() b++; B2 = I[x+dirs[b]]
249 #define GET_A_paranoid() temp = cache[a]; GET_A_old(); printf("GET_A: %i %i %i\n", temp, a, A ); assert(temp==A)
250 #define GET_B0_paranoid() temp = cache[b]; GET_B0_old(); printf("GET_B0: %i %i %i\n", temp, b, B0 ); assert(temp==B0)
251 #define GET_B1_paranoid() temp = cache[++b]; --b; GET_B1_old(); printf("GET_B1: %i %i %i\n", temp, b, B1 ); assert(temp==B1)
252 #define GET_B2_paranoid() temp = cache[++b]; --b; GET_B2_old(); printf("GET_B2: %i %i %i\n", temp, b, B2 ); assert(temp==B2)
253 #define GET_A_new() A = cache[a];
254 #define GET_B0_new() B0 = cache[b];
255 #define GET_B1_new() B1 = cache[++b];
256 #define GET_B2_new() B2 = cache[++b];
258 #define GET_A() GET_A_new()
259 #define GET_B0() GET_B0_new()
260 #define GET_B1() GET_B1_new()
261 #define GET_B2() GET_B2_new()
263 #define GOTO_STATE(s) { score -= A + B1; state = (s); break; }
264 #define GOTO_END_NOT_AN_INTEREST_POINT { /*stats_iter[a]++;*/ Scores[x] = 0; return; }
265 #define PUT_B2_IN_B1_AND_GET_B2() B1 = B2; GET_B2()
267 #define B1_NOT_INF_B2_NOT_INF 0
268 #define B1_NOT_SUP_B2_NOT_SUP 1
269 #define B1_INF_B2_INF 2
270 #define B1_SUP_B2_SUP 3
271 #define B1_INF_B2_NOT_SUP 4
272 #define B1_SUP_B2_NOT_INF 5
273 #define B1_SUP_B2_INF 6
274 #define B1_INF_B2_SUP 7
275 #define B1_EQUAL_B2_NOT_SUP 8
276 #define B1_EQUAL_B2_NOT_INF 9
278 void yape::perform_one_point(const unsigned char * I
, const int x
, short * Scores
,
279 const int Im
, const int Ip
,
280 const short * dirs
, const unsigned char opposite
, const unsigned char dirs_nb
)
284 unsigned char a
= 0, b
= opposite
- 1;
285 unsigned char A
, B0
, B1
, B2
;
289 unsigned char cache
[dirs_nb
];
290 for ( int i
=0; i
<dirs_nb
; i
++ )
292 cache
[i
] = I
[x
+dirs
[i
]];
295 /*printf("dirs: opp %hi, ", (short)opposite );
296 for ( int i=0; i<dirs_nb; i++ )
298 printf("%hi ", dirs[i] );
310 // WE KNOW THAT NOT(A ~ I0 & B1 ~ I0):
313 if (A_NOT_INF
) { // A ~ I0
316 if (B0_NOT_INF
) GOTO_END_NOT_AN_INTEREST_POINT
321 if (B2_SUP
) state
= B1_SUP_B2_SUP
;
322 else if (B2_INF
) state
= B1_SUP_B2_INF
;
323 else GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
325 else/* if (B1_INF)*/ {
327 if (B2_SUP
) state
= B1_INF_B2_SUP
;
328 else if (B2_INF
) state
= B1_INF_B2_INF
;
329 else GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
331 //else GOTO_END_NOT_AN_INTEREST_POINT // A ~ I0, B1 ~ I0
338 if (B2_SUP
) state
= B1_SUP_B2_SUP
;
339 else if (B2_INF
) state
= B1_SUP_B2_INF
;
340 else GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
344 if (B2_SUP
) state
= B1_INF_B2_SUP
;
345 else if (B2_INF
) state
= B1_INF_B2_INF
;
346 else GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
348 else GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B1 ~ I0
353 if (B0_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
355 if (B1_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
357 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
358 state
= B1_NOT_SUP_B2_NOT_SUP
;
364 if (B0_INF
) GOTO_END_NOT_AN_INTEREST_POINT
366 if (B1_INF
) GOTO_END_NOT_AN_INTEREST_POINT
368 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
369 state
= B1_NOT_INF_B2_NOT_INF
;
372 for(a
= 1; a
<= opposite
; a
++)
378 case B1_NOT_INF_B2_NOT_INF
:
380 PUT_B2_IN_B1_AND_GET_B2();
381 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
382 GOTO_STATE(B1_NOT_INF_B2_NOT_INF
);
385 if (B1_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
386 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
387 PUT_B2_IN_B1_AND_GET_B2();
388 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
389 GOTO_STATE(B1_EQUAL_B2_NOT_SUP
);
392 if (B1_NOT_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
393 if (B2_NOT_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
394 PUT_B2_IN_B1_AND_GET_B2();
395 if (B2_SUP
) GOTO_STATE(B1_SUP_B2_SUP
);
396 if (B2_INF
) GOTO_STATE(B1_SUP_B2_INF
);
397 GOTO_END_NOT_AN_INTEREST_POINT
399 case B1_NOT_SUP_B2_NOT_SUP
:
401 PUT_B2_IN_B1_AND_GET_B2();
402 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
403 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP
);
406 if (B1_INF
) GOTO_END_NOT_AN_INTEREST_POINT
407 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
408 PUT_B2_IN_B1_AND_GET_B2();
409 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
410 GOTO_STATE(B1_EQUAL_B2_NOT_INF
);
413 if (B1_NOT_INF
) GOTO_END_NOT_AN_INTEREST_POINT
414 if (B2_NOT_INF
) GOTO_END_NOT_AN_INTEREST_POINT
415 PUT_B2_IN_B1_AND_GET_B2();
416 if (B2_INF
) GOTO_STATE(B1_INF_B2_INF
);
417 if (B2_SUP
) GOTO_STATE(B1_INF_B2_SUP
);
418 GOTO_END_NOT_AN_INTEREST_POINT
421 if (A_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
422 PUT_B2_IN_B1_AND_GET_B2();
425 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
426 GOTO_STATE(B1_INF_B2_NOT_SUP
);
429 if (B2_SUP
) GOTO_STATE(B1_INF_B2_SUP
);
430 if (B2_INF
) GOTO_STATE(B1_INF_B2_INF
);
431 GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
434 if (A_INF
) GOTO_END_NOT_AN_INTEREST_POINT
435 PUT_B2_IN_B1_AND_GET_B2();
437 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
438 GOTO_STATE(B1_SUP_B2_NOT_INF
);
441 if (B2_SUP
) GOTO_STATE(B1_SUP_B2_SUP
);
442 if (B2_INF
) GOTO_STATE(B1_SUP_B2_INF
);
443 GOTO_END_NOT_AN_INTEREST_POINT
445 case B1_INF_B2_NOT_SUP
:
446 if (A_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
448 PUT_B2_IN_B1_AND_GET_B2();
449 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
450 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP
);
452 if (B2_NOT_INF
) GOTO_END_NOT_AN_INTEREST_POINT
453 PUT_B2_IN_B1_AND_GET_B2();
454 if (B2_INF
) GOTO_STATE(B1_INF_B2_INF
);
455 if (B2_SUP
) GOTO_STATE(B1_INF_B2_SUP
);
456 GOTO_END_NOT_AN_INTEREST_POINT
458 case B1_SUP_B2_NOT_INF
:
459 if (A_INF
) GOTO_END_NOT_AN_INTEREST_POINT
461 PUT_B2_IN_B1_AND_GET_B2();
462 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
463 GOTO_STATE(B1_NOT_INF_B2_NOT_INF
);
466 if (B2_NOT_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
467 PUT_B2_IN_B1_AND_GET_B2();
468 if (B2_SUP
) GOTO_STATE(B1_SUP_B2_SUP
);
469 if (B2_INF
) GOTO_STATE(B1_SUP_B2_INF
);
470 GOTO_END_NOT_AN_INTEREST_POINT
473 if (A_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
474 if (A_INF
) GOTO_END_NOT_AN_INTEREST_POINT
475 PUT_B2_IN_B1_AND_GET_B2();
477 if (B2_SUP
) GOTO_STATE(B1_SUP_B2_SUP
);
478 if (B2_INF
) GOTO_STATE(B1_SUP_B2_INF
);
479 GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
482 if (A_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
483 if (A_INF
) GOTO_END_NOT_AN_INTEREST_POINT
484 PUT_B2_IN_B1_AND_GET_B2();
486 if (B2_INF
) GOTO_STATE(B1_INF_B2_INF
);
487 if (B2_SUP
) GOTO_STATE(B1_INF_B2_SUP
);
488 GOTO_END_NOT_AN_INTEREST_POINT
// A ~ I0, B2 ~ I0
490 case B1_EQUAL_B2_NOT_SUP
:
492 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
493 PUT_B2_IN_B1_AND_GET_B2();
494 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
495 GOTO_STATE(B1_EQUAL_B2_NOT_INF
);
498 PUT_B2_IN_B1_AND_GET_B2();
499 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
500 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP
);
502 GOTO_END_NOT_AN_INTEREST_POINT
504 case B1_EQUAL_B2_NOT_INF
:
506 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
507 PUT_B2_IN_B1_AND_GET_B2();
508 if (B2_SUP
) GOTO_END_NOT_AN_INTEREST_POINT
509 GOTO_STATE(B1_EQUAL_B2_NOT_SUP
);
512 PUT_B2_IN_B1_AND_GET_B2();
513 if (B2_INF
) GOTO_END_NOT_AN_INTEREST_POINT
514 GOTO_STATE(B1_NOT_INF_B2_NOT_INF
);
516 GOTO_END_NOT_AN_INTEREST_POINT
519 cout
<< "PB default" << endl
;
523 Scores
[x
] = short(score
+ dirs_nb
* I
[x
]);
526 int yape::detect(IplImage
* image
, keypoint
* points
, int max_point_number
, IplImage
* _filtered_image
)
528 IplImage
* used_filtered_image
;
530 if (_filtered_image
== 0)
532 int gaussian_filter_size
= 3;
534 if (radius
>= 5) gaussian_filter_size
= 5;
535 if (radius
>= 7) gaussian_filter_size
= 7;
536 cvSmooth(image
, filtered_image
, CV_GAUSSIAN
, gaussian_filter_size
, gaussian_filter_size
);
538 used_filtered_image
= filtered_image
;
541 used_filtered_image
= _filtered_image
;
543 reserve_tmp_arrays();
545 raw_detect_mt(used_filtered_image
);
547 get_local_maxima(image
, radius
, 0);
549 int points_nb
= pick_best_points(points
, max_point_number
);
552 for(int i
= 0; i
< points_nb
; i
++)
553 subpix_refine(used_filtered_image
, points
+ i
);
558 static unsigned mymin(unsigned a
, unsigned b
)
563 /*! This method sorts tmp_points and select the max_point_number best points,
564 * as long as the score is high enough.
566 int yape::pick_best_points(keypoint
* points
, unsigned int max_point_number
)
571 for(int i
= 0; i
< bin_nb_u
; i
++)
573 for(int j
= 0; j
< bin_nb_v
; j
++)
575 if (bins
[i
][j
].size() > 0){
576 sort(bins
[i
][j
].begin(), bins
[i
][j
].end());
577 N
+= bins
[i
][j
].size();
582 N
= max_point_number
;
583 unsigned int N_per_bin
= N
/ (bin_nb_u
* bin_nb_v
);
585 for(int i
= 0; i
< bin_nb_u
; i
++)
587 for(int j
= 0; j
< bin_nb_v
; j
++)
589 for(unsigned int k
= 0; k
< mymin(N_per_bin
, bins
[i
][j
].size()); k
++, points_nb
++)
590 points
[points_nb
] = bins
[i
][j
][k
];
597 if (tmp_points
.size() > 0)
599 sort(tmp_points
.begin(), tmp_points
.end());
601 int score_threshold
= 0;
603 int tot_pts
= tmp_points
.size()<max_point_number
? tmp_points
.size() : max_point_number
;
607 points_nb
<tot_pts
&& tmp_points
[points_nb
].score
>score_threshold
;
609 points
[points_nb
] = tmp_points
[points_nb
];
618 static inline int computeLResponse(const uchar
* ptr
, const short* cdata
, int csize
)
620 int i
, csize2
= csize
/2, sum
= -ptr
[0]*csize
;
621 for( i
= 0; i
< csize2
; i
++ )
624 sum
+= ptr
[ofs
] + ptr
[-ofs
];
629 static inline void perform_one_point_2( const unsigned char* img
, int x
, short* scores
, const int tau
,
630 const short* dirs
, const unsigned char opposite
, const unsigned char dirs_nb
)
634 void yape::perform_one_point(const unsigned char * I, const int x, short * Scores,
635 const int Im, const int Ip,
636 const short * dirs, const unsigned char opposite, const unsigned char dirs_nb)
640 unsigned char a = 0, b = opposite - 1;
641 unsigned char A, B0, B1, B2;
645 unsigned char cache[dirs_nb];
646 for ( int i=0; i<dirs_nb; i++ )
648 cache[i] = I[x+dirs[i]];
653 for( k
= 0; k
< dirs_nb
; k
++ )
655 if( abs(val0
- img
[dirs
[k
]]) < tau
&&
656 (abs(val0
- img
[dirs
[k
+ opposite
]]) < tau
||
657 abs(val0
- img
[dirs
[k
+ opposite
- 1]]) < tau
||
658 abs(val0
- img
[dirs
[k
+ opposite
+ 1]]) < tau
||
659 abs(val0
- img
[dirs
[k
+ opposite
- 2]]) < tau
||
660 abs(val0
- img
[dirs
[k
+ opposite
+ 2]]) < tau
) )
670 scores
[x
] = (short)computeLResponse(img
, dirs
, dirs_nb
);
674 yape::RawDetectThreadData::RawDetectThreadData()
676 run_semaphore
= new FSemaphore( 0 );
679 yape::RawDetectThreadData::~RawDetectThreadData()
683 run_semaphore
->Signal();
685 pthread_join( thread
, &ret
);
686 delete run_semaphore
;
689 void* yape::raw_detect_thread_func( void* _data
)
691 RawDetectThreadData
* data
= (RawDetectThreadData
*)_data
;
695 // continue/stop mechanism
696 data
->run_semaphore
->Wait();
697 if ( data
->should_stop
)
700 unsigned int R
= data
->y
->radius
;
701 short * dirs
= data
->y
->Dirs
->t
[R
];
702 unsigned char dirs_nb
= (unsigned char)(data
->y
->Dirs_nb
[R
]);
703 unsigned char opposite
= dirs_nb
/ 2;
705 CvRect roi
= cvGetImageROI(data
->im
);
707 if (roi
.x
< int(R
+1)) roi
.x
= R
+1;
708 if (roi
.y
< int(R
+1)) roi
.y
= R
+1;
709 if ((roi
.x
+ roi
.width
) > int(data
->im
->width
-R
-2)) roi
.width
= data
->im
->width
- R
- roi
.x
- 2;
710 if ((roi
.y
+ roi
.height
) > int(data
->im
->height
-R
-2)) roi
.height
= data
->im
->height
- R
- roi
.y
- 2;
712 unsigned int xend
= roi
.x
+ roi
.width
;
713 unsigned int yend
= data
->y_start
+ data
->y_count
;
714 int tau
= data
->y
->tau
;
716 for(unsigned int y
= data
->y_start
; y
< yend
; y
++)
718 unsigned char* I
= (unsigned char*)(data
->im
->imageData
+ y
*data
->im
->widthStep
);
719 short * Scores
= (short*)(data
->y
->scores
->imageData
+ y
*data
->y
->scores
->widthStep
);
720 for(unsigned int x
= roi
.x
; x
< xend
; x
++)
722 unsigned char* img
= I
+x
;
726 if (Im
<img
[R
] && img
[R
]<Ip
&& Im
<img
[-R
] && img
[-R
]<Ip
)
730 //perform_one_point(I, x, Scores, Im, Ip, dirs, opposite, dirs_nb);
731 //int old_score = Scores[x];
732 perform_one_point_2( img
, x
, Scores
, tau
, dirs
, opposite
, dirs_nb
);
733 //int new_score = Scores[x];
734 //printf("%3i %3i: %i %i\n", x, y, old_score, new_score );
740 data
->barrier
->Wait();
747 void yape::raw_detect_mt(IplImage
* im
)
749 PROFILE_THIS_FUNCTION();
750 int thread_count
= 8;
751 if ( raw_detect_thread_data
.size() != thread_count
)
753 assert( raw_detect_thread_data
.size() == 0 );
755 // make shared barrier
756 shared_barrier
= new FBarrier( thread_count
+1 );
758 // make threads joinable
759 pthread_attr_t thread_attr
;
760 pthread_attr_init(&thread_attr
);
761 pthread_attr_setdetachstate(&thread_attr
, PTHREAD_CREATE_JOINABLE
);
762 printf("creating %i raw_detect threads\n", thread_count
);
763 for ( int i
=0; i
<thread_count
; i
++ )
766 RawDetectThreadData
* thread_data
= new RawDetectThreadData
;
767 thread_data
->run_semaphore
= new FSemaphore(0);
768 thread_data
->y
= this;
769 thread_data
->barrier
= shared_barrier
;
770 thread_data
->should_stop
= false;
772 pthread_create( &thread_data
->thread
, &thread_attr
, raw_detect_thread_func
, (void*)thread_data
);
774 raw_detect_thread_data
.push_back( thread_data
);
776 pthread_attr_destroy(&thread_attr
);
781 unsigned int R
= radius
;
782 CvRect roi
= cvGetImageROI(im
);
783 // get y for divisions
784 if (roi
.y
< int(R
+1)) roi
.y
= R
+1;
785 if ((roi
.y
+ roi
.height
) > int(im
->height
-R
-2)) roi
.height
= im
->height
- R
- roi
.y
- 2;
787 // distribute y over threads
789 int y_remaining_count
= roi
.height
;
790 int y_count
= y_remaining_count
/ raw_detect_thread_data
.size();
791 assert( y_remaining_count
>= raw_detect_thread_data
.size() && "too many threads / not enough roi.y height" );
793 for ( int i
=0; i
<raw_detect_thread_data
.size(); i
++ )
796 RawDetectThreadData
* thread_data
= raw_detect_thread_data
[i
];
797 thread_data
->im
= im
;
798 thread_data
->y_start
= curr_y
;
799 // distribute y ranges to trheads, ensuring last thread gets remainder
800 if ( i
== raw_detect_thread_data
.size()-1 )
801 thread_data
->y_count
= y_remaining_count
;
803 thread_data
->y_count
= y_count
;
805 y_remaining_count
-= y_count
;
808 thread_data
->run_semaphore
->Signal();
811 // wait for all threads to complete
812 shared_barrier
->Wait();
816 /*! Detect interest points, without filtering and without selecting best ones.
817 * Just find them and add them to tmp_points. tmp_points is not cleared in this
820 void yape::raw_detect(IplImage
*im
) {
821 unsigned int R
= radius
;
822 short * dirs
= Dirs
->t
[R
];
823 unsigned char dirs_nb
= (unsigned char)(Dirs_nb
[R
]);
824 unsigned char opposite
= dirs_nb
/ 2;
826 CvRect roi
= cvGetImageROI(im
);
828 if (roi
.x
< int(R
+1)) roi
.x
= R
+1;
829 if (roi
.y
< int(R
+1)) roi
.y
= R
+1;
830 if ((roi
.x
+ roi
.width
) > int(im
->width
-R
-2)) roi
.width
= im
->width
- R
- roi
.x
- 2;
831 if ((roi
.y
+ roi
.height
) > int(im
->height
-R
-2)) roi
.height
= im
->height
- R
- roi
.y
- 2;
833 unsigned int xend
= roi
.x
+ roi
.width
;
834 unsigned int yend
= roi
.y
+ roi
.height
;
836 PROFILE_SECTION_PUSH("performing points");
838 for(unsigned int y
= roi
.y
; y
< yend
; y
++)
840 unsigned char* I
= (unsigned char*)(im
->imageData
+ y
*im
->widthStep
);
841 short * Scores
= (short*)(scores
->imageData
+ y
*scores
->widthStep
);
842 for(unsigned int x
= roi
.x
; x
< xend
; x
++)
844 unsigned char* img
= I
+x
;
848 if (Im
<img
[R
] && img
[R
]<Ip
&& Im
<img
[-R
] && img
[-R
]<Ip
)
852 perform_one_point(I
, x
, Scores
, Im
, Ip
, dirs
, opposite
, dirs_nb
);
853 //int old_score = Scores[x];
854 //perform_one_point_2( img, x, Scores, tau, dirs, opposite, dirs_nb );
855 //int new_score = Scores[x];
856 //printf("%3i %3i: %i %i\n", x, y, old_score, new_score );
860 PROFILE_SECTION_POP();
864 for( y = radius; y < layerSize.height - radius; y++ )
866 const uchar* img = pyrLayer.ptr<uchar>(y) + radius;
867 short* scores = scoreLayer.ptr<short>(y);
868 uchar* mask = maskLayer.ptr<uchar>(y);
870 for( x = 0; x < radius; x++ )
872 scores[x] = scores[layerSize.width - 1 - x] = 0;
873 mask[x] = mask[layerSize.width - 1 - x] = 0;
876 for( x = radius; x < layerSize.width - radius; x++, img++ )
879 if( (std::abs(val0 - img[radius]) < tau && std::abs(val0 - img[-radius]) < tau) ||
880 (std::abs(val0 - img[vradius]) < tau && std::abs(val0 - img[-vradius]) < tau))
887 for( k = 0; k < csize; k++ )
889 if( std::abs(val0 - img[cdata[k]]) < tau &&
890 (std::abs(val0 - img[cdata[k + csize2]]) < tau ||
891 std::abs(val0 - img[cdata[k + csize2 - 1]]) < tau ||
892 std::abs(val0 - img[cdata[k + csize2 + 1]]) < tau ||
893 std::abs(val0 - img[cdata[k + csize2 - 2]]) < tau ||
894 std::abs(val0 - img[cdata[k + csize2 + 2]]) < tau ) )
905 scores[x] = (short)computeLResponse(img, cdata, csize);
920 #define MINIMAL_SCORE (0 / radius)
922 inline bool yape::third_check(const short * Sb
, const int next_line
)
929 if (Sb
[S
+E
] != 0) n
++;
930 if (Sb
[S
+W
] != 0) n
++;
932 if (Sb
[N
+E
] != 0) n
++;
933 if (Sb
[N
+W
] != 0) n
++;
935 return n
>= minimal_neighbor_number
;
938 // Test if a pixel is a local maxima in a given neighborhood.
939 static inline bool is_local_maxima(const short *p
, int neighborhood
, const IplImage
*scores
)
941 #ifdef CONSIDER_ABS_VALUE_ONLY
942 unsigned v
= abs(p
[0]);
943 if (v
< 5) return false;
945 int step
= scores
->widthStep
/ 2;
947 p
-= step
*neighborhood
;
948 for (int y
= -neighborhood
; y
<=neighborhood
; ++y
) {
949 for (int x
= -neighborhood
; x
<=neighborhood
; ++x
) {
959 int step
= scores
->widthStep
/ 2;
962 p
-= step
*neighborhood
;
963 for (int y
= -neighborhood
; y
<=neighborhood
; ++y
) {
964 for (int x
= -neighborhood
; x
<=neighborhood
; ++x
) {
971 p
-= step
*neighborhood
;
972 for (int y
= -neighborhood
; y
<=neighborhood
; ++y
) {
973 for (int x
= -neighborhood
; x
<=neighborhood
; ++x
) {
986 /*! Find local maximas in score image and append them to tmp_points.
987 * \return the number of local maxima found.
989 int yape::get_local_maxima(IplImage
* image
, int R
, float scale
/*, keypoint * points, int max_number_of_points*/)
993 const int next_line
= scores
->widthStep
/ sizeof(short);
994 int h
= scores
->height
;
995 int w
= scores
->width
;
997 CvRect roi
= cvGetImageROI(image
);
999 if (roi
.x
< int(R
+1)) roi
.x
= R
+1;
1000 if (roi
.y
< int(R
+1)) roi
.y
= R
+1;
1001 if ((roi
.x
+ roi
.width
) > int(scores
->width
-R
-2)) roi
.width
= scores
->width
- R
- roi
.x
- 2;
1002 if ((roi
.y
+ roi
.height
) > int(scores
->height
-R
-2)) roi
.height
= scores
->height
- R
- roi
.y
- 2;
1004 unsigned int xend
= roi
.x
+ roi
.width
;
1005 unsigned int yend
= roi
.y
+ roi
.height
;
1007 for(unsigned int y
= roi
.y
; y
< yend
; y
++)
1009 short * Scores
= (short *)(scores
->imageData
+ y
* scores
->widthStep
);
1011 for(unsigned int x
= roi
.x
; x
< xend
; x
++)
1013 short * Sb
= Scores
+ x
;
1015 // skip 0 score pixels
1017 ++x
; // if this pixel is 0, the next one will not be good enough. Skip it.
1020 if (third_check(Sb
, next_line
) && is_local_maxima(Sb
, R
, scores
))
1026 p
.score
= float(abs(Sb
[0]));
1030 int bin_u_index
= (bin_nb_u
* x
) / w
;
1031 int bin_v_index
= (bin_nb_v
* y
) / h
;
1033 if (bin_u_index
>= bin_nb_u
)
1034 bin_u_index
= bin_nb_u
- 1;
1035 if (bin_v_index
>= bin_nb_v
)
1036 bin_v_index
= bin_nb_v
- 1;
1038 if (bins
[bin_u_index
][bin_v_index
].size() < yape_bin_size
)
1039 bins
[bin_u_index
][bin_v_index
].push_back(p
);
1042 tmp_points
.push_back(p
);
1053 /////////////////////////////////////////////////////////////////
1054 // Sub-pixel / sub-scale accuracy.
1055 /////////////////////////////////////////////////////////////////
1057 static float fit_quadratic_2x2(float x
[2], float L
[3][3])
1062 b
[0] = -(L
[1][2] - L
[1][0]) / 2.0f
;
1063 b
[1] = -(L
[2][1] - L
[0][1]) / 2.0f
;
1065 H
[0][0] = L
[1][0] - 2.0f
* L
[1][1] + L
[1][2];
1066 H
[1][1] = L
[0][1] - 2.0f
* L
[1][1] + L
[2][1];
1067 H
[0][1] = H
[1][0] = (L
[0][0] - L
[0][2] - L
[2][0] + L
[2][2]) / 4.0f
;
1069 float t4
= 1/(H
[0][0]*H
[1][1]-H
[0][1]*H
[1][0]);
1070 x
[0] = H
[1][1]*t4
*b
[0]-H
[0][1]*t4
*b
[1];
1071 x
[1] = -H
[1][0]*t4
*b
[0]+H
[0][0]*t4
*b
[1];
1073 return 0.5f
* (b
[0] * x
[0] + b
[1] * x
[1]);
1076 void yape::subpix_refine(IplImage
*im
, keypoint
*p
)
1080 int px
= (int) p
->u
;
1081 int py
= (int) p
->v
;
1082 int dirs_nb
= Dirs_nb
[radius
];
1083 short * dirs
= Dirs
->t
[radius
];
1085 if ((px
<= radius
) || (px
>= (scores
->width
-radius
)) || (py
<= radius
) || (py
>= (scores
->height
-radius
)))
1088 unsigned char * I
= (unsigned char *) (im
->imageData
+ py
*im
->widthStep
) + px
;
1089 short * s
= (short *) (scores
->imageData
+ py
*scores
->widthStep
) + px
;
1090 int line
= scores
->widthStep
/sizeof(short);
1092 for (int y
=0; y
<3; ++y
) {
1093 int offset
= (y
-1)*line
- 1;
1094 for (int x
=0; x
<3; ++x
) {
1095 if (s
[ offset
+ x
]==0) {
1096 // Compute Laplacian
1098 for (int d
=0; d
<dirs_nb
; ++d
)
1099 score
+= I
[offset
+ x
+ dirs
[d
]];
1100 L
[y
][x
] = -float(score
- dirs_nb
*(int)I
[offset
+ x
]);
1102 L
[y
][x
] = (float)s
[ offset
+ x
];
1108 p
->score
+= fit_quadratic_2x2(delta
, L
);
1110 if ((delta
[0] >= -1) && (delta
[0] <= 1))
1114 if ((delta
[1] >= -1) && (delta
[1] <= 1))
1120 //////////////////////////////////////////////////////////////////////
1121 // PyrYape implementation
1122 //////////////////////////////////////////////////////////////////////
1124 /*! \param w width passed to Yape constructor
1125 \param h height passed to Yape constructor
1126 \param nbLev pyramid depth
1128 pyr_yape::pyr_yape(int w
, int h
, int nbLev
)
1132 pscores
= new PyrImage(scores
, nbLev
);
1134 pDirs_nb
[0] = Dirs_nb
;
1137 PyrImage
pim(cvCreateImage(cvSize(w
, h
), IPL_DEPTH_8U
, 1),nbLev
);
1139 for (int i
=1; i
<nbLev
; i
++) {
1140 pDirs
[i
] = new dir_table
;
1141 pDirs_nb
[i
] = new int[yape_max_radius
];
1142 for(int R
= 1; R
< yape_max_radius
; R
++)
1143 precompute_directions(pim
[i
], pDirs
[i
]->t
[R
], &(pDirs_nb
[i
][R
]), R
);
1147 pyr_yape::~pyr_yape()
1149 if (internal_pim
) delete internal_pim
;
1151 for (int i
=0; i
<pscores
->nbLev
; i
++) {
1153 delete[] pDirs_nb
[i
];
1162 void pyr_yape::select_level(int l
)
1164 scores
= pscores
->images
[l
];
1166 Dirs_nb
= pDirs_nb
[l
];
1169 /*! Detect features on the pyramid, filling the scale field of keypoints with
1170 * the pyramid level. \return the detected keypoint number.
1172 int pyr_yape::detect(PyrImage
*image
, keypoint
*points
, int max_point_number
)
1174 reserve_tmp_arrays();
1176 PROFILE_SECTION_PUSH("detect + maxima" );
1177 for (int i
=image
->nbLev
-1; i
>=0; --i
)
1180 raw_detect_mt(image
->images
[i
]);
1181 get_local_maxima(image
->images
[i
], radius
, float(i
));
1183 PROFILE_SECTION_POP();
1185 PROFILE_SECTION_PUSH("pick best, refine");
1186 int n
= pick_best_points(points
, max_point_number
);
1187 for (int i
= 0; i
< n
; i
++) {
1188 int l
=(int)points
[i
].scale
;
1190 subpix_refine(image
->images
[l
], points
+ i
);
1192 PROFILE_SECTION_POP();
1198 * This method does the following:
1199 * 1) Apply a Gaussian blur filter on the provided image, putting the result in
1200 * the pyramid lowest level.
1201 * 2) Build the pyramid
1202 * 3) call detect() on it.
1204 * If no pyramid is given by the caller, a temporary pyramid image is created
1205 * and recycled for future calls.
1207 * \param im the input image. Must be 1 channel (gray levels).
1208 * \param points an array to store keypoints.
1209 * \param max_point_number the size of this array.
1210 * \param caller_pim the pyramid to work on, or 0 for an internal pyramid.
1212 int pyr_yape::pyramidBlurDetect(IplImage
*im
, keypoint
*points
, int max_point_number
, PyrImage
*caller_pim
)
1214 PROFILE_THIS_FUNCTION();
1215 assert(im
->nChannels
== 1);
1219 if (caller_pim
== 0)
1221 PROFILE_THIS_BLOCK("create pim");
1222 if (internal_pim
&& ((internal_pim
->images
[0]->width
!= im
->width
)
1223 || (internal_pim
->images
[0]->height
!= im
->height
)))
1225 delete internal_pim
;
1229 if (internal_pim
== 0)
1230 internal_pim
= new PyrImage(cvCreateImage(cvGetSize(im
), IPL_DEPTH_8U
, 1), pscores
->nbLev
);
1237 assert (im
->width
== caller_pim
->images
[0]->width
);
1240 int gaussian_filter_size
= 3;
1241 if (radius
>= 5) gaussian_filter_size
= 5;
1242 if (radius
>= 7) gaussian_filter_size
= 7;
1244 PROFILE_SECTION_PUSH("gaussian");
1245 cvSmooth(im
, pim
->images
[0], CV_GAUSSIAN
, gaussian_filter_size
, gaussian_filter_size
);
1246 PROFILE_SECTION_POP();
1248 PROFILE_SECTION_PUSH("build");
1250 PROFILE_SECTION_POP();
1252 PROFILE_SECTION_PUSH("detect");
1253 int res
= detect(pim
, points
, max_point_number
);
1254 PROFILE_SECTION_POP();
1258 void pyr_yape::save_image_of_detected_points(char * name
, IplImage
* image
, keypoint
* points
, int points_nb
)
1260 IplImage
* point_image
= mcvGrayToColor(image
);
1261 for(int i
= 0; i
< points_nb
; i
++)
1262 mcvCircle(point_image
,
1263 (int)PyrImage::convCoordf(points
[i
].u
, (int)points
[i
].scale
, 0),
1264 (int)PyrImage::convCoordf(points
[i
].v
, (int)points
[i
].scale
, 0),
1265 PyrImage::convCoord(2 * radius
, (int)points
[i
].scale
, 0), mcvRainbowColor((int)points
[i
].scale
), 1);
1266 mcvSaveImage(name
, point_image
);
1267 cvReleaseImage(&point_image
);
1270 void pyr_yape::stat_points(keypoint
*points
, int nb_pts
)
1272 int *histogram
= new int[pscores
->nbLev
];
1274 for (int l
=0; l
< pscores
->nbLev
; ++l
) histogram
[l
]=0;
1276 for (int i
=0; i
<nb_pts
; ++i
)
1277 histogram
[(int)(points
[i
].scale
)]++;
1279 for (int l
=0; l
< pscores
->nbLev
; ++l
)
1280 cout
<< "Level " << l
<< ": " << histogram
[l
] << " keypoints ("
1281 << 100.0f
* (float)histogram
[l
]/(float)nb_pts
<< "%)\n";