#include "sift.h" /** SIFTLOCALMAX Find local maximizers Returns the indexes of the local maximizers of the 3-dimensional array F. Say, we have a Q-dimensional array F. A local maximizer is an element whose value is greater than the value of all its neighbors. The neighbors of an element i1...iQ are the subscripts j1...jQ such that iq-1 <= jq <= iq (excluding i1...iQ itself). For example, if Q=1 the neighbors of an element are its predecessor and successor in the linear order; if Q=2, its neighbors are the elements immediately to its north, south, west, est, north-west, north-est, south-west and south-est (8-neighborhood). Points on the boundary of F are ignored (and never selected as local maximizers). SEL=SIFTLOCALMAX(F,THRESH) accepts an element as a mazimizer only if it is at least THRES greater than all its neighbors. SEL=SIFTLOCALMAX(F,THRESH,P) look for neighbors only in the first P dimensions of the Q-dimensional array F. This is useful to process F in ``slices''. REMARK. Matrices (2-array) with a singleton dimension are interpreted as vectors (1-array). So for example SIFTLOCALMAX([0 1 0]) and SIFTLOCALMAX([0 1 0]') both return 2 as an aswer. However, if [0 1 0] is to be interpreted as a 1x2 matrix, then the correct answer is the empty set, as all elements are on the boundary. Unfortunately MATLAB does not distinguish between vectors and 2-matrices with a singleton dimension. To forece the interpretation of all matrices as 2-arrays, use SIFTLOCALMAX(F,TRESH,2) (but note that in this case the result is always empty!). **/ #define NDIMS 3 F2D* siftlocalmax(F2D* in, float thresh, int intervals, int M, int N) { int ndims, ptoffset=0, maxIter = 0; int offsets[NDIMS]; int midx[NDIMS]; int dims[NDIMS]; I2D* neighbors ; int nneighbors ; F2D* out; /** We pass dogss[o], which has >1 intervals If >1 intervals, then the dimensions of in[F] will be 1 x intervals If =1 interval, then the dimensions of in[F] will be the size of the dogss[o] image We will check for this condition. **/ ndims = NDIMS; /* Since we have intervals number of images of size M x N */ dims[0] = M; dims[1] = N; dims[2] = intervals-1; /* If there are only two dimensions and if one is singleton, then assume that a vector has been provided as input (and treat this as a COLUMN matrix with p=1). We do this because Matlab does not distinguish between vectors and 1xN or Mx1 matrices and because the cases 1xN and Mx1 are trivial (the result is alway empty). */ /* ------------------------------------------------------------------ * Do the job * --------------------------------------------------------------- */ int maxima_size = M*N ; I2D* maxima_start = iMallocHandle(1, maxima_size); int* maxima_iterator = maxima_start->data ; int* maxima_end = maxima_start->data + maxima_size ; int i,h,o,j; F2D* pt; pt = in; /* Compute the offsets between dimensions. */ offsets[0] = 1 ; for(i = 1 ; i < ndims ; ++i) { offsets[i] = offsets[i-1]*dims[i-1] ; } /* Multi-index. */ for(i = 0 ; i < ndims ; ++i) midx[i] = 1 ; /* Neighbors. */ nneighbors = 1 ; o=0 ; for(i = 0 ; i < ndims ; ++i) { nneighbors *= 3 ; midx[i] = -1 ; o -= offsets[i] ; } nneighbors -= 1 ; neighbors = iMallocHandle(1,nneighbors); /* Precompute offsets from offset(-1,...,-1,0,...0) to * offset(+1,...,+1,0,...,0). */ i = 0 ; while(1) { if(o != 0) { asubsref(neighbors, i) = o ; i++; } h = 0 ; while( o += offsets[h], (++midx[h]) > 1 ) { o -= 3*offsets[h] ; midx[h] = -1 ; if(++h >= ndims) goto stop ; } } stop: ; /* Starts at the corner (1,1,...,1,0,0,...0) */ for(h = 0 ; h < ndims ; ++h) { midx[h] = 1 ; ptoffset += offsets[h] ; } /* --------------------------------------------------------------- * Loop * ------------------------------------------------------------ */ /* If any dimension in the first P is less than 3 elements wide then just return the empty matrix (if we proceed without doing anything we break the carry reporting algorithm below). */ for(h=0 ; h < ndims ; ++h) if(dims[h] < 3) goto end ; while(1) { /* Propagate carry along multi index midx */ h = 0 ; while(midx[h] >= dims[h] - 1) { midx[h] = 1 ; if(++h >= ndims) goto next_layer ; ++midx[h] ; } /* Scan neighbors */ { float v = asubsref(pt, ptoffset); //*pt ; int is_greater = (v>=thresh) ? 1 : 0; assert(ptoffset < pt->width*pt->height); i = 0 ; while(is_greater && i < nneighbors) { if(v > asubsref(pt, ptoffset + asubsref(neighbors,i))) is_greater *= 1; else is_greater *= 0; i = i+1; } /* Add the local maximum */ if(is_greater) { /* Need more space? */ if( &(maxima_iterator[maxIter]) == maxima_end) { int *temp, i, j; maxima_size += M*N ; free(maxima_start); maxima_start = iMallocHandle(1, maxima_size); maxima_end = maxima_start->data + maxima_size ; maxima_iterator = maxima_end - M*N ; maxIter = 0; } maxima_iterator[maxIter] = ptoffset + 1; maxIter++; } /* Go to next element */ ptoffset += 1 ; ++midx[0] ; continue ; next_layer: ; if( h >= ndims ) goto end ; while((++midx[h]) >= dims[h]) { midx[h] = 0 ; if(++h >= ndims) goto end ; } } } end:; /* Return. */ { int i=0; out = fMallocHandle(1, maxIter); for(i=0; i