summaryrefslogtreecommitdiffstats
path: root/SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c
diff options
context:
space:
mode:
Diffstat (limited to 'SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c')
-rw-r--r--SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c524
1 files changed, 524 insertions, 0 deletions
diff --git a/SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c b/SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c
new file mode 100644
index 0000000..63f4830
--- /dev/null
+++ b/SD-VBS/benchmarks/sift/src/matlab/siftdescriptor.c
@@ -0,0 +1,524 @@
1/* file: siftdescriptor
2** author: Andrea Vedaldi
3** description: Compute SIFT descriptors
4**/
5
6/* AUTORIGHTS
7Copyright (c) 2006 The Regents of the University of California.
8All Rights Reserved.
9
10Created by Andrea Vedaldi
11UCLA Vision Lab - Department of Computer Science
12
13Permission to use, copy, modify, and distribute this software and its
14documentation for educational, research and non-profit purposes,
15without fee, and without a written agreement is hereby granted,
16provided that the above copyright notice, this paragraph and the
17following three paragraphs appear in all copies.
18
19This software program and documentation are copyrighted by The Regents
20of the University of California. The software program and
21documentation are supplied "as is", without any accompanying services
22from The Regents. The Regents does not warrant that the operation of
23the program will be uninterrupted or error-free. The end-user
24understands that the program was developed for research purposes and
25is advised not to rely exclusively on the program for any reason.
26
27This software embodies a method for which the following patent has
28been issued: "Method and apparatus for identifying scale invariant
29features in an image and use of same for locating an object in an
30image," David G. Lowe, US Patent 6,711,293 (March 23,
312004). Provisional application filed March 8, 1999. Asignee: The
32University of British Columbia.
33
34IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
35FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
36INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
37ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN
38ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF
39CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
40LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
42BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE
43MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44*/
45
46/*
47 REMARKS. The use of strcasecmp makes the function POSIX but not ANSI
48 compliant. When compling with Altivec, GCC Altivec extensions are
49 supported.
50*/
51
52#define LOWE_COMPATIBLE
53
54#include"mexutils.c"
55#include<stdlib.h>
56#include<math.h>
57
58#ifdef WINDOWS
59#include<string.h>
60#ifndef __cplusplus
61#define sqrtf(x) ((float)sqrt((double)(x)))
62#define powf(x,y) ((float)pow((double)(x),(double)(y)))
63#define fabsf(x) ((float)fabs((double)(x)))
64#define sinf(x) ((float)sin((double)(x)))
65#define cosf(x) ((float)cos((double)(x)))
66#define expf(x) ((float)exp((double)(x)))
67#define atan2f(x,y) ((float)atan2((double)(x),(double)(y)))
68#endif
69#else
70#include<strings.h>
71#endif
72
73/* Altivec and Accelerate support.
74 * Very crude at this time.
75 */
76#if defined( MACOSX ) && defined( __ALTIVEC__ )
77#include<Accelerate/Accelerate.h>
78typedef union
79{
80 float x[4] ;
81 vFloat vec ;
82} float4 ;
83#endif
84
85#define greater(a,b) a > b
86#define min(a,b) (((a)<(b))?(a):(b))
87#define max(a,b) (((a)>(b))?(a):(b))
88
89
90enum {SCALESPACE, NOSCALESPACE} ;
91
92enum {PROP_MAGNIF=0,
93 PROP_NBP,
94 PROP_NBO,
95 PROP_UNKNOWN} ;
96
97char const * properties [4] =
98 { "Magnif",
99 "NumSpatialBins",
100 "NumOrientBins",
101 0L
102 } ;
103
104/** Fast fmodf for 2*PI
105 **/
106/*inline*/
107float fast_mod(float th)
108{
109 while(th < 0) th += 2*M_PI ;
110 while(th > 2*M_PI) th -= 2*M_PI ;
111 return th ;
112}
113
114/** Fast floor. Equivalent to (int) floor(x)
115 **/
116/*inline*/
117int fast_floor(float x)
118{
119 return (int)( x - ((x>=0)?0:1) ) ;
120}
121
122/** Normalizes in norm L_2 a descriptor.
123 **/
124void
125normalize_histogram(float* L_begin, float* L_end)
126{
127 float* L_iter ;
128 float norm=0.0 ;
129
130 for(L_iter = L_begin; L_iter != L_end ; ++L_iter)
131 norm += (*L_iter) * (*L_iter) ;
132
133 norm = sqrtf(norm) ;
134 /* mexPrintf("%f\n",norm) ;*/
135
136 for(L_iter = L_begin; L_iter != L_end ; ++L_iter)
137 *L_iter /= norm ;
138}
139
140/** @brief MATLAB Driver.
141 **/
142void
143mexFunction(int nout, mxArray *out[],
144 int nin, const mxArray *in[])
145{
146 int M,N,S=0,smin=0,K,num_levels=0 ;
147 const int* dimensions ;
148 const double* P_pt ;
149 const double* G_pt ;
150 float* descr_pt ;
151 float* buffer_pt ;
152 float sigma0 ;
153 float magnif = 3.0f ; /* Spatial bin extension factor. */
154 int NBP = 4 ; /* Number of bins for one spatial direction (even). */
155 int NBO = 8 ; /* Number of bins for the ortientation. */
156 int mode = NOSCALESPACE ;
157 int buffer_size=0;
158
159 enum {IN_G=0,IN_P,IN_SIGMA0,IN_S,IN_SMIN} ;
160 enum {OUT_L=0} ;
161
162 /* ------------------------------------------------------------------
163 ** Check the arguments
164 ** --------------------------------------------------------------- */
165
166 if (nin < 3) {
167 mexErrMsgTxt("At least three arguments are required") ;
168 } else if (nout > 1) {
169 mexErrMsgTxt("Too many output arguments.");
170 }
171
172 if( !uIsRealScalar(in[IN_SIGMA0]) ) {
173 mexErrMsgTxt("SIGMA0 should be a real scalar") ;
174 }
175
176 if(!mxIsDouble(in[IN_G]) ||
177 mxGetNumberOfDimensions(in[IN_G]) > 3) {
178 mexErrMsgTxt("G should be a real matrix or 3-D array") ;
179 }
180
181 sigma0 = (float) *mxGetPr(in[IN_SIGMA0]) ;
182
183 dimensions = mxGetDimensions(in[IN_G]) ;
184 M = dimensions[0] ;
185 N = dimensions[1] ;
186 G_pt = mxGetPr(in[IN_G]) ;
187
188 P_pt = mxGetPr(in[IN_P]) ;
189 K = mxGetN(in[IN_P]) ;
190
191 if( !uIsRealMatrix(in[IN_P],-1,-1)) {
192 mexErrMsgTxt("P should be a real matrix") ;
193 }
194
195 if ( mxGetM(in[IN_P]) == 4) {
196 /* Standard (scale space) mode */
197 mode = SCALESPACE ;
198 num_levels = dimensions[2] ;
199
200 if(nin < 5) {
201 mexErrMsgTxt("Five arguments are required in standard mode") ;
202 }
203
204 if( !uIsRealScalar(in[IN_S]) ) {
205 mexErrMsgTxt("S should be a real scalar") ;
206 }
207
208 if( !uIsRealScalar(in[IN_SMIN]) ) {
209 mexErrMsgTxt("SMIN should be a real scalar") ;
210 }
211
212 if( !uIsRealMatrix(in[IN_P],4,-1)) {
213 mexErrMsgTxt("When the e mode P should be a 4xK matrix.") ;
214 }
215
216 S = (int)(*mxGetPr(in[IN_S])) ;
217 smin = (int)(*mxGetPr(in[IN_SMIN])) ;
218
219 } else if ( mxGetM(in[IN_P]) == 3 ) {
220 mode = NOSCALESPACE ;
221 num_levels = 1 ;
222 S = 1 ;
223 smin = 0 ;
224 } else {
225 mexErrMsgTxt("P should be either a 3xK or a 4xK matrix.") ;
226 }
227
228 /* Parse the property-value pairs */
229 {
230 char str [80] ;
231 int arg = (mode == SCALESPACE) ? IN_SMIN + 1 : IN_SIGMA0 + 1 ;
232
233 while(arg < nin) {
234 int k ;
235
236 if( !uIsString(in[arg],-1) ) {
237 mexErrMsgTxt("The first argument in a property-value pair"
238 " should be a string") ;
239 }
240 mxGetString(in[arg], str, 80) ;
241
242#ifdef WINDOWS
243 for(k = 0 ; properties[k] && strcmpi(str, properties[k]) ; ++k) ;
244#else
245 for(k = 0 ; properties[k] && strcasecmp(str, properties[k]) ; ++k) ;
246#endif
247
248 switch (k) {
249 case PROP_NBP:
250 if( !uIsRealScalar(in[arg+1]) ) {
251 mexErrMsgTxt("'NumSpatialBins' should be real scalar") ;
252 }
253 NBP = (int) *mxGetPr(in[arg+1]) ;
254 if( NBP <= 0 || (NBP & 0x1) ) {
255 mexErrMsgTxt("'NumSpatialBins' must be positive and even") ;
256 }
257 break ;
258
259 case PROP_NBO:
260 if( !uIsRealScalar(in[arg+1]) ) {
261 mexErrMsgTxt("'NumOrientBins' should be a real scalar") ;
262 }
263 NBO = (int) *mxGetPr(in[arg+1]) ;
264 if( NBO <= 0 ) {
265 mexErrMsgTxt("'NumOrientlBins' must be positive") ;
266 }
267 break ;
268
269 case PROP_MAGNIF:
270 if( !uIsRealScalar(in[arg+1]) ) {
271 mexErrMsgTxt("'Magnif' should be a real scalar") ;
272 }
273 magnif = (float) *mxGetPr(in[arg+1]) ;
274 if( magnif <= 0 ) {
275 mexErrMsgTxt("'Magnif' must be positive") ;
276 }
277 break ;
278
279 case PROP_UNKNOWN:
280 mexErrMsgTxt("Property unknown.") ;
281 break ;
282 }
283 arg += 2 ;
284 }
285 }
286
287 /* -----------------------------------------------------------------
288 * Pre-compute gradient and angles
289 * -------------------------------------------------------------- */
290 /* Alloc two buffers and make sure their size is multiple of 128 for
291 * better alignment (used also by the Altivec code below.)
292 */
293 buffer_size = (M*N*num_levels + 0x7f) & (~ 0x7f) ;
294 buffer_pt = (float*) mxMalloc( sizeof(float) * 2 * buffer_size ) ;
295 descr_pt = (float*) mxCalloc( NBP*NBP*NBO*K, sizeof(float) ) ;
296
297 {
298 /* Offsets to move in the scale space. */
299 const int yo = 1 ;
300 const int xo = M ;
301 const int so = M*N ;
302 int x,y,s ;
303
304#define at(x,y) (*(pt + (x)*xo + (y)*yo))
305
306 /* Compute the gradient */
307 for(s = 0 ; s < num_levels ; ++s) {
308 const double* pt = G_pt + s*so ;
309 for(x = 1 ; x < N-1 ; ++x) {
310 for(y = 1 ; y < M-1 ; ++y) {
311 float Dx = 0.5 * ( at(x+1,y) - at(x-1,y) ) ;
312 float Dy = 0.5 * ( at(x,y+1) - at(x,y-1) ) ;
313 buffer_pt[(x*xo+y*yo+s*so) + 0 ] = Dx ;
314 buffer_pt[(x*xo+y*yo+s*so) + buffer_size] = Dy ;
315 }
316 }
317 }
318
319 /* Compute angles and modules */
320 {
321 float* pt = buffer_pt ;
322 int j = 0 ;
323 while (j < N*M*num_levels) {
324
325#if defined( MACOSX ) && defined( __ALTIVEC__ )
326 if( ((unsigned int)pt & 0x7) == 0 && j+3 < N*M*num_levels ) {
327 /* If aligned to 128 bit and there are at least 4 pixels left */
328 float4 a, b, c, d ;
329 a.vec = vec_ld(0,(vector float*)(pt )) ;
330 b.vec = vec_ld(0,(vector float*)(pt + buffer_size)) ;
331 c.vec = vatan2f(b.vec,a.vec) ;
332 a.x[0] = a.x[0]*a.x[0]+b.x[0]*b.x[0] ;
333 a.x[1] = a.x[1]*a.x[1]+b.x[1]*b.x[1] ;
334 a.x[2] = a.x[2]*a.x[2]+b.x[2]*b.x[2] ;
335 a.x[3] = a.x[3]*a.x[3]+b.x[3]*b.x[3] ;
336 d.vec = vsqrtf(a.vec) ;
337 vec_st(c.vec,0,(vector float*)(pt + buffer_size)) ;
338 vec_st(d.vec,0,(vector float*)(pt )) ;
339 j += 4 ;
340 pt += 4 ;
341 } else {
342#endif
343 float Dx = *(pt ) ;
344 float Dy = *(pt + buffer_size) ;
345 *(pt ) = sqrtf(Dx*Dx + Dy*Dy) ;
346 *(pt + buffer_size) = atan2f(Dy, Dx) ;
347 j += 1 ;
348 pt += 1 ;
349#if defined( MACOSX ) && defined( __ALTIVEC__ )
350 }
351#endif
352
353 }
354 }
355 }
356
357 /* -----------------------------------------------------------------
358 * Do the job
359 * -------------------------------------------------------------- */
360 if(K > 0) {
361 int p ;
362
363 /* Offsets to move in the buffer */
364 const int yo = 1 ;
365 const int xo = M ;
366 const int so = M*N ;
367
368 /* Offsets to move in the descriptor. */
369 /* Use Lowe's convention. */
370 const int binto = 1 ;
371 const int binyo = NBO * NBP ;
372 const int binxo = NBO ;
373 const int bino = NBO * NBP * NBP ;
374
375 for(p = 0 ; p < K ; ++p, descr_pt += bino) {
376 /* The SIFT descriptor is a three dimensional histogram of the position
377 * and orientation of the gradient. There are NBP bins for each spatial
378 * dimesions and NBO bins for the orientation dimesion, for a total of
379 * NBP x NBP x NBO bins.
380 *
381 * The support of each spatial bin has an extension of SBP = 3sigma
382 * pixels, where sigma is the scale of the keypoint. Thus all the bins
383 * together have a support SBP x NBP pixels wide . Since weighting and
384 * interpolation of pixel is used, another half bin is needed at both
385 * ends of the extension. Therefore, we need a square window of SBP x
386 * (NBP + 1) pixels. Finally, since the patch can be arbitrarly rotated,
387 * we need to consider a window 2W += sqrt(2) x SBP x (NBP + 1) pixels
388 * wide.
389 */
390 const float x = (float) *P_pt++ ;
391 const float y = (float) *P_pt++ ;
392 const float s = (float) (mode == SCALESPACE) ? (*P_pt++) : 0.0 ;
393 const float theta0 = (float) *P_pt++ ;
394
395 const float st0 = sinf(theta0) ;
396 const float ct0 = cosf(theta0) ;
397 const int xi = (int) floor(x+0.5) ; /* Round-off */
398 const int yi = (int) floor(y+0.5) ;
399 const int si = (int) floor(s+0.5) - smin ;
400 const float sigma = sigma0 * powf(2, s / S) ;
401 const float SBP = magnif * sigma ;
402 const int W = (int) floor( sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ;
403 int bin ;
404 int dxi ;
405 int dyi ;
406 const float* pt ;
407 float* dpt ;
408
409 /* Check that keypoints are within bounds . */
410
411 if(xi < 0 ||
412 xi > N-1 ||
413 yi < 0 ||
414 yi > M-1 ||
415 ((mode==SCALESPACE) &&
416 (si < 0 ||
417 si > dimensions[2]-1) ) )
418 continue ;
419
420 /* Center the scale space and the descriptor on the current keypoint.
421 * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0).
422 */
423 pt = buffer_pt + xi*xo + yi*yo + si*so ;
424 dpt = descr_pt + (NBP/2) * binyo + (NBP/2) * binxo ;
425
426#define atd(dbinx,dbiny,dbint) (*(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo))
427
428 /*
429 * Process each pixel in the window and in the (1,1)-(M-1,N-1)
430 * rectangle.
431 */
432 for(dxi = max(-W, 1-xi) ; dxi <= min(+W, N-2-xi) ; ++dxi) {
433 for(dyi = max(-W, 1-yi) ; dyi <= min(+W, M-2-yi) ; ++dyi) {
434
435 /* Compute the gradient. */
436 float mod = *(pt + dxi*xo + dyi*yo + 0 ) ;
437 float angle = *(pt + dxi*xo + dyi*yo + buffer_size ) ;
438#ifdef LOWE_COMPATIBLE
439 float theta = fast_mod(-angle + theta0) ;
440#else
441 float theta = fast_mod(angle - theta0) ;
442#endif
443 /* Get the fractional displacement. */
444 float dx = ((float)(xi+dxi)) - x;
445 float dy = ((float)(yi+dyi)) - y;
446
447 /* Get the displacement normalized w.r.t. the keypoint orientation
448 * and extension. */
449 float nx = ( ct0 * dx + st0 * dy) / SBP ;
450 float ny = (-st0 * dx + ct0 * dy) / SBP ;
451 float nt = NBO * theta / (2*M_PI) ;
452
453 /* Get the gaussian weight of the sample. The gaussian window
454 * has a standard deviation of NBP/2. Note that dx and dy are in
455 * the normalized frame, so that -NBP/2 <= dx <= NBP/2. */
456 const float wsigma = NBP/2 ;
457 float win = expf(-(nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ;
458
459 /* The sample will be distributed in 8 adijacient bins.
460 * Now we get the ``lower-left'' bin. */
461 int binx = fast_floor( nx - 0.5 ) ;
462 int biny = fast_floor( ny - 0.5 ) ;
463 int bint = fast_floor( nt ) ;
464 float rbinx = nx - (binx+0.5) ;
465 float rbiny = ny - (biny+0.5) ;
466 float rbint = nt - bint ;
467 int dbinx ;
468 int dbiny ;
469 int dbint ;
470
471 /* Distribute the current sample into the 8 adijacient bins. */
472 for(dbinx = 0 ; dbinx < 2 ; ++dbinx) {
473 for(dbiny = 0 ; dbiny < 2 ; ++dbiny) {
474 for(dbint = 0 ; dbint < 2 ; ++dbint) {
475
476 if( binx+dbinx >= -(NBP/2) &&
477 binx+dbinx < (NBP/2) &&
478 biny+dbiny >= -(NBP/2) &&
479 biny+dbiny < (NBP/2) ) {
480 float weight = win
481 * mod
482 * fabsf(1 - dbinx - rbinx)
483 * fabsf(1 - dbiny - rbiny)
484 * fabsf(1 - dbint - rbint) ;
485
486 atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ;
487 }
488 }
489 }
490 }
491 }
492 }
493
494 {
495 /* Normalize the histogram to L2 unit length. */
496 normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ;
497
498 /* Truncate at 0.2. */
499 for(bin = 0; bin < NBO*NBP*NBP ; ++bin) {
500 if (descr_pt[bin] > 0.2) descr_pt[bin] = 0.2;
501 }
502
503 /* Normalize again. */
504 normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ;
505 }
506 }
507 }
508
509 /* Restore pointer to the beginning of the descriptors. */
510 descr_pt -= NBO*NBP*NBP*K ;
511
512 {
513 int k ;
514 double* L_pt ;
515 out[OUT_L] = mxCreateDoubleMatrix(NBP*NBP*NBO, K, mxREAL) ;
516 L_pt = mxGetPr(out[OUT_L]) ;
517 for(k = 0 ; k < NBP*NBP*NBO*K ; ++k) {
518 L_pt[k] = descr_pt[k] ;
519 }
520 }
521
522 mxFree(descr_pt) ;
523 mxFree(buffer_pt) ;
524}