vl_localmax.c
Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00008 All rights reserved.
00009 
00010 This file is part of the VLFeat library and is made available under
00011 the terms of the BSD license (see the COPYING file).
00012 */
00013 
00014 #include <mexutils.h>
00015 
00016 #include <stdlib.h>
00017 
00020 #define greater(a,b) ((a) > (b)+threshold)
00021 
00022 void
00023 mexFunction(int nout, mxArray *out[],
00024             int nin, const mxArray *in[])
00025 {
00026   int M, N ;
00027   const double* F_pt ;
00028   int ndims ;
00029   int pdims = -1 ;
00030   int* offsets ;
00031   int* midx ;
00032   int* neighbors ;
00033   int nneighbors ;
00034   int* dims ;
00035   enum {F=0,THRESHOLD,P} ;
00036   enum {MAXIMA=0} ;
00037   double threshold = - mxGetInf() ;
00038 
00039   /* -----------------------------------------------------------------
00040    *                                               Check the arguments
00041    * -------------------------------------------------------------- */
00042 
00043   if (nin < 1) {
00044     mexErrMsgTxt("At least one input argument is required.");
00045   } else if (nin > 3) {
00046     mexErrMsgTxt("At most three arguments are allowed.") ;
00047   } else if (nout > 1) {
00048     mexErrMsgTxt("Too many output arguments");
00049   }
00050 
00051   /* The input must be a real matrix. */
00052   if (!mxIsDouble(in[F]) || mxIsComplex(in[F])) {
00053     mexErrMsgTxt("Input must be real matrix.");
00054   }
00055 
00056   if(nin > 1) {
00057     if(!vlmxIsPlainScalar(in[THRESHOLD])) {
00058       mexErrMsgTxt("THRESHOLD must be a real scalar.") ;
00059     }
00060     threshold = *mxGetPr(in[THRESHOLD]) ;
00061   }
00062 
00063   if(nin > 2) {
00064     if(!vlmxIsPlainScalar(in[P]))
00065       mexErrMsgTxt("P must be a non-negative integer") ;
00066     pdims = (int) *mxGetPr(in[P])  ;
00067     if(pdims < 0)
00068       mexErrMsgTxt("P must be a non-negative integer") ;
00069   }
00070 
00071   ndims = mxGetNumberOfDimensions(in[F]) ;
00072   {
00073     /* We need to make a copy because in one special case (see below)
00074        we need to adjust dims[].
00075     */
00076     int d ;
00077     mwSize const * const_dims = mxGetDimensions(in[F]) ;
00078     dims = mxMalloc(sizeof(int)*ndims) ;
00079     for(d=0 ; d < ndims ; ++d) dims[d] = const_dims[d] ;
00080   }
00081   M = dims[0] ;
00082   N = dims[1] ;
00083   F_pt = mxGetPr(in[F]) ;
00084 
00085   /*
00086      If there are only two dimensions and if one is singleton, then
00087      assume that a vector has been provided as input (and treat this
00088      as a COLUMN matrix with p=1). We do this because Matlab does not
00089      distinguish between vectors and 1xN or Mx1 matrices and because
00090      the cases 1xN and Mx1 are trivial (the result is alway empty).
00091    */
00092   if((ndims == 2) && (pdims < 0) && (M == 1 || N == 1)) {
00093     pdims = 1 ;
00094     M = (M>N)?M:N ;
00095     N = 1 ;
00096     dims[0]=M ;
00097     dims[1]=N ;
00098   }
00099 
00100   /* search the local maxima along the first p dimensions only */
00101   if(pdims < 0)
00102     pdims = ndims ;
00103 
00104   if(pdims > ndims) {
00105     mxFree(dims) ;
00106     mexErrMsgTxt("P must not be greater than the number of dimensions") ;
00107   }
00108 
00109   /* ------------------------------------------------------------------
00110    *                                                         Do the job
00111    * --------------------------------------------------------------- */
00112   {
00113     int maxima_size = M*N ;
00114     int* maxima_start = mxMalloc(sizeof(int) * maxima_size) ;
00115     int* maxima_iterator = maxima_start ;
00116     int* maxima_end = maxima_start + maxima_size ;
00117     int i,h,o ;
00118     const double* pt = F_pt ;
00119 
00120     /* Compute the offsets between dimensions. */
00121     offsets = mxMalloc(sizeof(int) * ndims) ;
00122     offsets[0] = 1 ;
00123     for(h = 1 ; h < ndims ; ++h)
00124       offsets[h] = offsets[h-1]*dims[h-1] ;
00125 
00126     /* Multi-index. */
00127     midx = mxMalloc(sizeof(int) * ndims) ;
00128     for(h = 0 ; h < ndims ; ++h)
00129       midx[h] = 1 ;
00130 
00131     /* Neighbors. */
00132     nneighbors = 1 ;
00133     o=0 ;
00134     for(h = 0 ; h < pdims ; ++h) {
00135       nneighbors *= 3 ;
00136       midx[h] = -1 ;
00137       o -= offsets[h] ;
00138     }
00139     nneighbors -= 1 ;
00140     neighbors = mxMalloc(sizeof(int) * nneighbors) ;
00141     i = 0 ;
00142 
00143     while(VL_TRUE) {
00144       if(o != 0 )
00145         neighbors[i++] = o ;
00146       h = 0 ;
00147       while( o += offsets[h], (++midx[h]) > 1 ) {
00148         o -= 3*offsets[h] ;
00149         midx[h] = -1 ;
00150         if(++h >= pdims)
00151           goto stop ;
00152       }
00153     }
00154   stop: ;
00155 
00156     /* Starts at the corner (1,1,...,1,0,0,...0) */
00157     for(h = 0 ; h < pdims ; ++h) {
00158       midx[h] = 1 ;
00159       pt += offsets[h] ;
00160     }
00161     for(h = pdims ; h < ndims ; ++h) {
00162       midx[h] = 0 ;
00163     }
00164 
00165     /* ---------------------------------------------------------------
00166      *                                                            Loop
00167      * ------------------------------------------------------------ */
00168 
00169     /*
00170       If any dimension in the first P is less than 3 elements wide
00171       then just return the empty matrix (if we proceed without doing
00172       anything we break the carry reporting algorithm below).
00173     */
00174     for(h=0 ; h < pdims ; ++h)
00175       if(dims[h] < 3) goto end ;
00176 
00177     while(VL_TRUE) {
00178       double v ;
00179       bool is_greater;
00180 
00181       /* Propagate carry along multi index midx */
00182       h = 0 ;
00183       while((midx[h]) >= dims[h] - 1) {
00184         pt += 2*offsets[h] ; /* skip first and last el. */
00185         midx[h] = 1 ;
00186         if(++h >= pdims)
00187           goto next_layer ;
00188         ++midx[h] ;
00189       }
00190 
00191       /*
00192         for(h = 0 ; h < ndims ; ++h )
00193           mexPrintf("%d  ", midx[h]) ;
00194         mexPrintf(" -- %d -- pdims %d \n", pt - F_pt,pdims) ;
00195       */
00196 
00197       /*  Scan neighbors */
00198       v = *pt ;
00199       is_greater = (v >= threshold) ;
00200       i = 0  ;
00201       while(is_greater && i < nneighbors)
00202         is_greater &= v > *(pt + neighbors[i++]) ;
00203 
00204         /* Add the local maximum */
00205       if(is_greater) {
00206         /* Need more space? */
00207         if(maxima_iterator == maxima_end) {
00208           maxima_size += M*N ;
00209           maxima_start = mxRealloc(maxima_start,
00210                                    maxima_size*sizeof(int)) ;
00211           maxima_end = maxima_start + maxima_size ;
00212           maxima_iterator = maxima_end - M*N ;
00213         }
00214 
00215         *maxima_iterator++ = pt - F_pt + 1 ;
00216       }
00217 
00218       /* Go to next element */
00219       pt += 1 ;
00220       ++midx[0] ;
00221       continue ;
00222 
00223     next_layer: ;
00224       if( h >= ndims )
00225         goto end ;
00226 
00227       while((++midx[h]) >= dims[h]) {
00228         midx[h] = 0 ;
00229         if(++h >= ndims)
00230           goto end ;
00231       }
00232     }
00233   end:;
00234     /* Return. */
00235     {
00236       double* M_pt ;
00237       out[MAXIMA] = mxCreateDoubleMatrix
00238         (1, maxima_iterator-maxima_start, mxREAL) ;
00239       maxima_end = maxima_iterator ;
00240       maxima_iterator = maxima_start ;
00241       M_pt = mxGetPr(out[MAXIMA]) ;
00242       while(maxima_iterator != maxima_end) {
00243         *M_pt++ = *maxima_iterator++ ;
00244       }
00245     }
00246 
00247     /* Release space. */
00248     mxFree(offsets) ;
00249     mxFree(neighbors) ;
00250     mxFree(midx) ;
00251     mxFree(maxima_start) ;
00252   }
00253   mxFree(dims) ;
00254 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51