static VlHIKMTree* matlab_to_hikm (mxArray const *mtree, int method_type) { VlHIKMTree *tree ; mxArray *mK, *mdepth ; int K = 0, depth = 0; VL_USE_MATLAB_ENV ; if (mxGetClassID (mtree) != mxSTRUCT_CLASS) { mexErrMsgTxt("TREE must be a MATLAB structure.") ; } mK = mxGetField(mtree, 0, "K") ; mdepth = mxGetField(mtree, 0, "depth") ; if (!mK || !uIsRealScalar (mK) || (K = (int) *mxGetPr (mK)) < 1) { mexErrMsgTxt("TREE.K must be a DOUBLE not smaller than one.") ; } if (!mdepth || !uIsRealScalar (mdepth) || (depth = (int) *mxGetPr (mdepth)) < 1) { mexErrMsgTxt("TREE.DEPTH must be a DOUBLE not smaller than one.") ; } tree = mxMalloc (sizeof(VlHIKMTree)) ; tree-> depth = depth ; tree-> K = K ; tree-> M = -1 ; /* to be initialized later */ tree-> method= method_type ; tree-> root = xcreate (tree, mtree, 0) ; return tree ; }
/** @brief MATLAB Driver. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M,N,S=0,smin=0,K,num_levels=0 ; const int* dimensions ; const double* P_pt ; const double* G_pt ; float* descr_pt ; float* buffer_pt ; float sigma0 ; float magnif = 3.0f ; /* Spatial bin extension factor. */ int NBP = 4 ; /* Number of bins for one spatial direction (even). */ int NBO = 8 ; /* Number of bins for the ortientation. */ int mode = NOSCALESPACE ; int buffer_size=0; enum {IN_G=0,IN_P,IN_SIGMA0,IN_S,IN_SMIN} ; enum {OUT_L=0} ; /* ------------------------------------------------------------------ ** Check the arguments ** --------------------------------------------------------------- */ if (nin < 3) { mexErrMsgTxt("At least three arguments are required") ; } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if( !uIsRealScalar(in[IN_SIGMA0]) ) { mexErrMsgTxt("SIGMA0 should be a real scalar") ; } if(!mxIsDouble(in[IN_G]) || mxGetNumberOfDimensions(in[IN_G]) > 3) { mexErrMsgTxt("G should be a real matrix or 3-D array") ; } sigma0 = (float) *mxGetPr(in[IN_SIGMA0]) ; dimensions = mxGetDimensions(in[IN_G]) ; M = dimensions[0] ; N = dimensions[1] ; G_pt = mxGetPr(in[IN_G]) ; P_pt = mxGetPr(in[IN_P]) ; K = mxGetN(in[IN_P]) ; if( !uIsRealMatrix(in[IN_P],-1,-1)) { mexErrMsgTxt("P should be a real matrix") ; } if ( mxGetM(in[IN_P]) == 4) { /* Standard (scale space) mode */ mode = SCALESPACE ; num_levels = dimensions[2] ; if(nin < 5) { mexErrMsgTxt("Five arguments are required in standard mode") ; } if( !uIsRealScalar(in[IN_S]) ) { mexErrMsgTxt("S should be a real scalar") ; } if( !uIsRealScalar(in[IN_SMIN]) ) { mexErrMsgTxt("SMIN should be a real scalar") ; } if( !uIsRealMatrix(in[IN_P],4,-1)) { mexErrMsgTxt("When the e mode P should be a 4xK matrix.") ; } S = (int)(*mxGetPr(in[IN_S])) ; smin = (int)(*mxGetPr(in[IN_SMIN])) ; } else if ( mxGetM(in[IN_P]) == 3 ) { mode = NOSCALESPACE ; num_levels = 1 ; S = 1 ; smin = 0 ; } else { mexErrMsgTxt("P should be either a 3xK or a 4xK matrix.") ; } /* Parse the property-value pairs */ { char str [80] ; int arg = (mode == SCALESPACE) ? IN_SMIN + 1 : IN_SIGMA0 + 1 ; while(arg < nin) { int k ; if( !uIsString(in[arg],-1) ) { mexErrMsgTxt("The first argument in a property-value pair" " should be a string") ; } mxGetString(in[arg], str, 80) ; #ifdef WINDOWS for(k = 0 ; properties[k] && strcmpi(str, properties[k]) ; ++k) ; #else for(k = 0 ; properties[k] && strcasecmp(str, properties[k]) ; ++k) ; #endif switch (k) { case PROP_NBP: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'NumSpatialBins' should be real scalar") ; } NBP = (int) *mxGetPr(in[arg+1]) ; if( NBP <= 0 || (NBP & 0x1) ) { mexErrMsgTxt("'NumSpatialBins' must be positive and even") ; } break ; case PROP_NBO: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'NumOrientBins' should be a real scalar") ; } NBO = (int) *mxGetPr(in[arg+1]) ; if( NBO <= 0 ) { mexErrMsgTxt("'NumOrientlBins' must be positive") ; } break ; case PROP_MAGNIF: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'Magnif' should be a real scalar") ; } magnif = (float) *mxGetPr(in[arg+1]) ; if( magnif <= 0 ) { mexErrMsgTxt("'Magnif' must be positive") ; } break ; case PROP_UNKNOWN: mexErrMsgTxt("Property unknown.") ; break ; } arg += 2 ; } } /* ----------------------------------------------------------------- * Pre-compute gradient and angles * -------------------------------------------------------------- */ /* Alloc two buffers and make sure their size is multiple of 128 for * better alignment (used also by the Altivec code below.) */ buffer_size = (M*N*num_levels + 0x7f) & (~ 0x7f) ; buffer_pt = (float*) mxMalloc( sizeof(float) * 2 * buffer_size ) ; descr_pt = (float*) mxCalloc( NBP*NBP*NBO*K, sizeof(float) ) ; { /* Offsets to move in the scale space. */ const int yo = 1 ; const int xo = M ; const int so = M*N ; int x,y,s ; #define at(x,y) (*(pt + (x)*xo + (y)*yo)) /* Compute the gradient */ for(s = 0 ; s < num_levels ; ++s) { const double* pt = G_pt + s*so ; for(x = 1 ; x < N-1 ; ++x) { for(y = 1 ; y < M-1 ; ++y) { float Dx = 0.5 * ( at(x+1,y) - at(x-1,y) ) ; float Dy = 0.5 * ( at(x,y+1) - at(x,y-1) ) ; buffer_pt[(x*xo+y*yo+s*so) + 0 ] = Dx ; buffer_pt[(x*xo+y*yo+s*so) + buffer_size] = Dy ; } } } /* Compute angles and modules */ { float* pt = buffer_pt ; int j = 0 ; while (j < N*M*num_levels) { #if defined( MACOSX ) && defined( __ALTIVEC__ ) if( ((unsigned int)pt & 0x7) == 0 && j+3 < N*M*num_levels ) { /* If aligned to 128 bit and there are at least 4 pixels left */ float4 a, b, c, d ; a.vec = vec_ld(0,(vector float*)(pt )) ; b.vec = vec_ld(0,(vector float*)(pt + buffer_size)) ; c.vec = vatan2f(b.vec,a.vec) ; a.x[0] = a.x[0]*a.x[0]+b.x[0]*b.x[0] ; a.x[1] = a.x[1]*a.x[1]+b.x[1]*b.x[1] ; a.x[2] = a.x[2]*a.x[2]+b.x[2]*b.x[2] ; a.x[3] = a.x[3]*a.x[3]+b.x[3]*b.x[3] ; d.vec = vsqrtf(a.vec) ; vec_st(c.vec,0,(vector float*)(pt + buffer_size)) ; vec_st(d.vec,0,(vector float*)(pt )) ; j += 4 ; pt += 4 ; } else { #endif float Dx = *(pt ) ; float Dy = *(pt + buffer_size) ; *(pt ) = sqrtf(Dx*Dx + Dy*Dy) ; if (*pt > 0) *(pt + buffer_size) = atan2f(Dy, Dx) ; else *(pt + buffer_size) = 0 ; j += 1 ; pt += 1 ; #if defined( MACOSX ) && defined( __ALTIVEC__ ) } #endif } } } /* ----------------------------------------------------------------- * Do the job * -------------------------------------------------------------- */ if(K > 0) { int p ; /* Offsets to move in the buffer */ const int yo = 1 ; const int xo = M ; const int so = M*N ; /* Offsets to move in the descriptor. */ /* Use Lowe's convention. */ const int binto = 1 ; const int binyo = NBO * NBP ; const int binxo = NBO ; const int bino = NBO * NBP * NBP ; for(p = 0 ; p < K ; ++p, descr_pt += bino) { /* The SIFT descriptor is a three dimensional histogram of the position * and orientation of the gradient. There are NBP bins for each spatial * dimesions and NBO bins for the orientation dimesion, for a total of * NBP x NBP x NBO bins. * * The support of each spatial bin has an extension of SBP = 3sigma * pixels, where sigma is the scale of the keypoint. Thus all the bins * together have a support SBP x NBP pixels wide . Since weighting and * interpolation of pixel is used, another half bin is needed at both * ends of the extension. Therefore, we need a square window of SBP x * (NBP + 1) pixels. Finally, since the patch can be arbitrarly rotated, * we need to consider a window 2W += sqrt(2) x SBP x (NBP + 1) pixels * wide. */ const float x = (float) *P_pt++ ; const float y = (float) *P_pt++ ; const float s = (float) (mode == SCALESPACE) ? (*P_pt++) : 0.0 ; const float theta0 = (float) *P_pt++ ; const float st0 = sinf(theta0) ; const float ct0 = cosf(theta0) ; const int xi = (int) floor(x+0.5) ; /* Round-off */ const int yi = (int) floor(y+0.5) ; const int si = (int) floor(s+0.5) - smin ; const float sigma = sigma0 * powf(2, s / S) ; const float SBP = magnif * sigma ; const int W = (int) floor( sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ; int bin ; int dxi ; int dyi ; const float* pt ; float* dpt ; /* Check that keypoints are within bounds . */ if(xi < 0 || xi > N-1 || yi < 0 || yi > M-1 || ((mode==SCALESPACE) && (si < 0 || si > dimensions[2]-1) ) ) continue ; /* Center the scale space and the descriptor on the current keypoint. * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0). */ pt = buffer_pt + xi*xo + yi*yo + si*so ; dpt = descr_pt + (NBP/2) * binyo + (NBP/2) * binxo ; #define atd(dbinx,dbiny,dbint) (*(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo)) /* * Process each pixel in the window and in the (1,1)-(M-1,N-1) * rectangle. */ for(dxi = max(-W, 1-xi) ; dxi <= min(+W, N-2-xi) ; ++dxi) { for(dyi = max(-W, 1-yi) ; dyi <= min(+W, M-2-yi) ; ++dyi) { /* Compute the gradient. */ float mod = *(pt + dxi*xo + dyi*yo + 0 ) ; float angle = *(pt + dxi*xo + dyi*yo + buffer_size ) ; #ifdef LOWE_COMPATIBLE float theta = fast_mod(-angle + theta0) ; #else float theta = fast_mod(angle - theta0) ; #endif /* Get the fractional displacement. */ float dx = ((float)(xi+dxi)) - x; float dy = ((float)(yi+dyi)) - y; /* Get the displacement normalized w.r.t. the keypoint orientation * and extension. */ float nx = ( ct0 * dx + st0 * dy) / SBP ; float ny = (-st0 * dx + ct0 * dy) / SBP ; float nt = NBO * theta / (2*M_PI) ; /* Get the gaussian weight of the sample. The gaussian window * has a standard deviation of NBP/2. Note that dx and dy are in * the normalized frame, so that -NBP/2 <= dx <= NBP/2. */ const float wsigma = NBP/2 ; float win = expf(-(nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ; /* The sample will be distributed in 8 adijacient bins. * Now we get the ``lower-left'' bin. */ int binx = fast_floor( nx - 0.5 ) ; int biny = fast_floor( ny - 0.5 ) ; int bint = fast_floor( nt ) ; float rbinx = nx - (binx+0.5) ; float rbiny = ny - (biny+0.5) ; float rbint = nt - bint ; int dbinx ; int dbiny ; int dbint ; /* Distribute the current sample into the 8 adijacient bins. */ for(dbinx = 0 ; dbinx < 2 ; ++dbinx) { for(dbiny = 0 ; dbiny < 2 ; ++dbiny) { for(dbint = 0 ; dbint < 2 ; ++dbint) { if( binx+dbinx >= -(NBP/2) && binx+dbinx < (NBP/2) && biny+dbiny >= -(NBP/2) && biny+dbiny < (NBP/2) ) { float weight = win * mod * fabsf(1 - dbinx - rbinx) * fabsf(1 - dbiny - rbiny) * fabsf(1 - dbint - rbint) ; atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ; } } } } } } { /* Normalize the histogram to L2 unit length. */ normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ; /* Truncate at 0.2. */ for(bin = 0; bin < NBO*NBP*NBP ; ++bin) { if (descr_pt[bin] > 0.2) descr_pt[bin] = 0.2; } /* Normalize again. */ normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ; } } } /* Restore pointer to the beginning of the descriptors. */ descr_pt -= NBO*NBP*NBP*K ; { int k ; double* L_pt ; out[OUT_L] = mxCreateDoubleMatrix(NBP*NBP*NBO, K, mxREAL) ; L_pt = mxGetPr(out[OUT_L]) ; for(k = 0 ; k < NBP*NBP*NBO*K ; ++k) { L_pt[k] = descr_pt[k] ; } } mxFree(descr_pt) ; mxFree(buffer_pt) ; }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int K1, K2, ND ; void* L1_pt ; void* L2_pt ; double thresh = 1.5 ; mxClassID data_class ; enum {L1=0,L2,THRESH} ; enum {MATCHES=0,D} ; /* ------------------------------------------------------------------ ** Check the arguments ** --------------------------------------------------------------- */ if (nin < 2) { mexErrMsgTxt("At least two input arguments required"); } else if (nout > 2) { mexErrMsgTxt("Too many output arguments"); } if(!mxIsNumeric(in[L1]) || !mxIsNumeric(in[L2]) || mxGetNumberOfDimensions(in[L1]) > 2 || mxGetNumberOfDimensions(in[L2]) > 2) { mexErrMsgTxt("L1 and L2 must be two dimensional numeric arrays") ; } K1 = mxGetN(in[L1]) ; K2 = mxGetN(in[L2]) ; ND = mxGetM(in[L1]) ; if(mxGetM(in[L2]) != ND) { mexErrMsgTxt("L1 and L2 must have the same number of rows") ; } data_class = mxGetClassID(in[L1]) ; if(mxGetClassID(in[L2]) != data_class) { mexErrMsgTxt("L1 and L2 must be of the same class") ; } L1_pt = mxGetData(in[L1]) ; L2_pt = mxGetData(in[L2]) ; if(nin == 3) { if(!uIsRealScalar(in[THRESH])) { mexErrMsgTxt("THRESH should be a real scalar") ; } thresh = *mxGetPr(in[THRESH]) ; } else if(nin > 3) { mexErrMsgTxt("At most three arguments are allowed") ; } /* ------------------------------------------------------------------ ** Do the job ** --------------------------------------------------------------- */ { Pair* pairs_begin = (Pair*) mxMalloc(sizeof(Pair) * (K1+K2)) ; Pair* pairs_iterator = pairs_begin ; #define _DISPATCH_COMPARE( MXC ) \ case MXC : \ pairs_iterator = compare_##MXC(pairs_iterator, \ (const TYPEOF_##MXC*) L1_pt, \ (const TYPEOF_##MXC*) L2_pt, \ K1,K2,ND,thresh) ; \ break ; \ switch (data_class) { _DISPATCH_COMPARE( mxDOUBLE_CLASS ) ; _DISPATCH_COMPARE( mxSINGLE_CLASS ) ; _DISPATCH_COMPARE( mxINT8_CLASS ) ; _DISPATCH_COMPARE( mxUINT8_CLASS ) ; default : mexErrMsgTxt("Unsupported numeric class") ; break ; } /* --------------------------------------------------------------- * Finalize * ------------------------------------------------------------ */ { Pair* pairs_end = pairs_iterator ; double* M_pt ; double* D_pt = NULL ; out[MATCHES] = mxCreateDoubleMatrix (2, pairs_end-pairs_begin, mxREAL) ; M_pt = mxGetPr(out[MATCHES]) ; if(nout > 1) { out[D] = mxCreateDoubleMatrix(1, pairs_end-pairs_begin, mxREAL) ; D_pt = mxGetPr(out[D]) ; } for(pairs_iterator = pairs_begin ; pairs_iterator < pairs_end ; ++pairs_iterator) { *M_pt++ = pairs_iterator->k1 + 1 ; *M_pt++ = pairs_iterator->k2 + 1 ; if(nout > 1) { *D_pt++ = pairs_iterator->score ; } } } mxFree(pairs_begin) ; } }
/** @brief Driver. ** ** @param nount number of output arguments. ** @param out output arguments. ** @param nin number of input arguments. ** @param in input arguments. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum { IN_H, IN_ID, IN_NEXT, IN_K, IN_X } ; enum { OUT_H, OUT_ID, OUT_NEXT} ; mxArray *h_, *id_, *next_ ; vl_uint32 * h ; vl_uint32 * next ; vl_uint8 * id ; vl_uint8 const * x ; unsigned int K, i, N, res, last, ndims ; /* ----------------------------------------------------------------- * Check arguments * -------------------------------------------------------------- */ if( nin != 5 ) { mexErrMsgTxt("Five arguments required") ; } else if (nout > 3) { mexErrMsgTxt("At most three output argument.") ; } if(! mxIsNumeric(in[IN_H]) || mxGetClassID(in[IN_H] )!= mxUINT32_CLASS || ! mxIsNumeric(in[IN_NEXT])|| mxGetClassID(in[IN_NEXT])!= mxUINT32_CLASS) { mexErrMsgTxt("H, NEXT must be UINT32.") ; } if(! mxIsNumeric(in[IN_X]) || mxGetClassID(in[IN_X]) != mxUINT8_CLASS) { mexErrMsgTxt("X must be UINT8") ; } if (mxGetM(in[IN_H]) != 1 || mxGetM(in[IN_NEXT]) != 1) { mexErrMsgTxt("H, NEXT must be row vectors") ; } if(! mxIsNumeric(in[IN_ID]) || mxGetClassID(in[IN_ID])!= mxUINT8_CLASS) { mexErrMsgTxt("ID must be UINT8.") ; } ndims = mxGetM(in[IN_ID]) ; res = mxGetN(in[IN_H]) ; if(res != mxGetN(in[IN_ID]) || res != mxGetN(in[IN_NEXT])) { mexErrMsgTxt("H, ID, NEXT must have the same number of columns") ; } if(ndims != mxGetM(in[IN_X])) { mexErrMsgTxt("ID and X must havethe same number of rows") ; } if(! uIsRealScalar(in[IN_K])) { mexErrMsgTxt("K must be a scalar") ; } K = (unsigned int) *mxGetPr(in[IN_K]) ; h_ = mxDuplicateArray(in[IN_H]) ; id_ = mxDuplicateArray(in[IN_ID]) ; next_ = mxDuplicateArray(in[IN_NEXT]) ; N = mxGetN(in[IN_X]) ; h = mxGetData(h_ ) ; id = mxGetData(id_ ) ; next = mxGetData(next_) ; x = mxGetData(in[IN_X]) ; /* Temporary remove mxArray pointers to these buffer as we will mxRealloc them and if the user presses Ctrl-C matlab will attempt to free unvalid memory */ mxSetData(h_, 0) ; mxSetData(id_, 0) ; mxSetData(next_, 0) ; /* search for last occupied slot */ last = res ; for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ; /* REMARK: last and next are 1 based */ if (K > res) { mexErrMsgTxt("K cannot be larger then the size of H") ; } if (last > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* mexPrintf("last:%d\n",last) ;*/ /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ for (i = 0 ; i < N ; ++i) { /* hash */ unsigned int h1, h2 ; unsigned int j, p = 0 ; h1 = fnv_hash(x + i * ndims, ndims) % K ; h2 = h1 | 0x1 ; /* this needs to be odd */ /* search first free or matching position */ p = h1 % K ; for (j = 0 ; j < K ; ++j) { if (is_null (id + p * ndims, ndims) || is_equal(id + p * ndims, x + i * ndims, ndims)) break ; h1 += h2 ; p = h1 % K ; } /* search or make a free slot in the bucket */ while (! is_null (id + p * ndims, ndims) && ! is_equal(id + p * ndims, x + i * ndims, ndims)) { if (next [p] > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* append */ if (next [p] == 0) { if (last >= res) { size_t res_ = res + VL_MAX(res / 2, 2) ; h = mxRealloc(h, res_ * sizeof(vl_uint32) ) ; next = mxRealloc(next, res_ * sizeof(vl_uint32) ) ; id = mxRealloc(id, res_ * sizeof(vl_uint8) * ndims) ; memset (h + res, 0, (res_ - res) * sizeof(vl_uint32) ) ; memset (next + res, 0, (res_ - res) * sizeof(vl_uint32) ) ; memset (id + res * ndims, 0, (res_ - res) * sizeof(vl_uint8) * ndims) ; res = res_ ; } next [p] = ++ last ; } p = next [p] - 1 ; } /* accumulate */ h [p] += 1 ; /* mexPrintf("p %d dims %d i %d N %d\n ", p, ndims, i, N) ;*/ cpy(id + p * ndims, x + i * ndims, ndims) ; } mxSetData(h_, mxRealloc(h, last * sizeof(vl_uint32) )) ; mxSetData(next_, mxRealloc(next, last * sizeof(vl_uint32) )) ; mxSetData(id_, mxRealloc(id, last * sizeof(vl_uint8 ) * ndims)) ; mxSetN(h_, last) ; mxSetN(id_, last) ; mxSetN(next_, last) ; mxSetM(h_, 1) ; mxSetM(next_, 1) ; mxSetM(id_, ndims) ; out[OUT_H] = h_ ; out[OUT_ID] = id_ ; out[OUT_NEXT] = next_ ; }
/* driver */ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_I=0, IN_ER} ; enum {OUT_MEMBERS} ; idx_t i ; int k, nel, ndims ; mwSize const * dims ; val_t const * I_pt ; int last = 0 ; int last_expanded = 0 ; val_t value = 0 ; double const * er_pt ; int* subs_pt ; /* N-dimensional subscript */ int* nsubs_pt ; /* diff-subscript to point to neigh. */ idx_t* strides_pt ; /* strides to move in image array */ val_t* visited_pt ; /* flag */ idx_t* members_pt ; /* region members */ /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin != 2) { mexErrMsgTxt("Two arguments required.") ; } else if (nout > 4) { mexErrMsgTxt("Too many output arguments."); } if(mxGetClassID(in[IN_I]) != mxUINT8_CLASS) { mexErrMsgTxt("I must be of class UINT8.") ; } if(!uIsRealScalar(in[IN_ER])) { mexErrMsgTxt("ER must be a DOUBLE scalar.") ; } /* get dimensions */ nel = mxGetNumberOfElements(in[IN_I]) ; ndims = mxGetNumberOfDimensions(in[IN_I]) ; dims = mxGetDimensions(in[IN_I]) ; I_pt = mxGetData(in[IN_I]) ; /* allocate stuff */ subs_pt = mxMalloc( sizeof(int) * ndims ) ; nsubs_pt = mxMalloc( sizeof(int) * ndims ) ; strides_pt = mxMalloc( sizeof(idx_t) * ndims ) ; visited_pt = mxMalloc( sizeof(val_t) * nel ) ; members_pt = mxMalloc( sizeof(idx_t) * nel ) ; er_pt = mxGetPr(in[IN_ER]) ; /* compute strides to move into the N-dimensional image array */ strides_pt [0] = 1 ; for(k = 1 ; k < ndims ; ++k) { strides_pt [k] = strides_pt [k-1] * dims [k-1] ; } /* load first pixel */ memset(visited_pt, 0, sizeof(val_t) * nel) ; { idx_t idx = (idx_t) *er_pt ; if( idx < 1 || idx > nel ) { char buff[80] ; snprintf(buff,80,"ER=%d out of range [1,%d]",idx,nel) ; mexErrMsgTxt(buff) ; } members_pt [last++] = idx - 1 ; } value = I_pt[ members_pt[0] ] ; /* ----------------------------------------------------------------- * Fill region * -------------------------------------------------------------- */ while(last_expanded < last) { /* pop next node xi */ idx_t index = members_pt[last_expanded++] ; /* convert index into a subscript sub; also initialize nsubs to (-1,-1,...,-1) */ { idx_t temp = index ; for(k = ndims-1 ; k >=0 ; --k) { nsubs_pt [k] = -1 ; subs_pt [k] = temp / strides_pt [k] ; temp = temp % strides_pt [k] ; } } /* process neighbors of xi */ while( true ) { int good = true ; idx_t nindex = 0 ; /* compute NSUBS+SUB, the correspoinding neighbor index NINDEX and check that the pixel is within image boundaries. */ for(k = 0 ; k < ndims && good ; ++k) { int temp = nsubs_pt [k] + subs_pt [k] ; good &= 0 <= temp && temp < dims[k] ; nindex += temp * strides_pt [k] ; } /* process neighbor 1 - the pixel is within image boundaries; 2 - the pixel is indeed different from the current node (this happens when nsub=(0,0,...,0)); 3 - the pixel has value not greather than val is a pixel older than xi 4 - the pixel has not been visited yet */ if(good && nindex != index && I_pt [nindex] <= value && ! visited_pt [nindex] ) { /* mark as visited */ visited_pt [nindex] = 1 ; /* add to list */ members_pt [last++] = nindex ; } /* move to next neighbor */ k = 0 ; while(++ nsubs_pt [k] > 1) { nsubs_pt [k++] = -1 ; if(k == ndims) goto done_all_neighbors ; } } /* next neighbor */ done_all_neighbors : ; } /* goto pop next member */ /* * Save results */ { mwSize dims[2] ; int unsigned * pt ; dims[0] = last ; out[OUT_MEMBERS] = mxCreateNumericArray(1,dims,mxUINT32_CLASS,mxREAL); pt = mxGetData(out[OUT_MEMBERS]) ; for (i = 0 ; i < last ; ++i) { *pt++ = members_pt[i] + 1 ; } } /* free stuff */ mxFree( members_pt ) ; mxFree( visited_pt ) ; mxFree( strides_pt ) ; mxFree( nsubs_pt ) ; mxFree( subs_pt ) ; }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_GRAD=0,IN_FRAMES,IN_END} ; enum {OUT_DESCRIPTORS} ; int verbose = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; mxArray *grad_array ; vl_sift_pix *grad ; int M, N ; double magnif = -1 ; double *ikeys = 0 ; int nikeys = 0 ; int i,j ; VL_USE_MATLAB_ENV ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if (nin < 2) { mexErrMsgTxt("Two arguments required.") ; } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if (mxGetNumberOfDimensions (in[IN_GRAD]) != 3 || mxGetClassID (in[IN_GRAD]) != mxSINGLE_CLASS || mxGetDimensions (in[IN_GRAD])[0] != 2 ) { mexErrMsgTxt("GRAD must be a 2xMxN matrix of class SINGLE.") ; } if (!uIsRealMatrix(in[IN_FRAMES], 4, -1)) { mexErrMsgTxt("FRAMES must be a 4xN matrix.") ; } nikeys = mxGetN (in[IN_FRAMES]) ; ikeys = mxGetPr(in[IN_FRAMES]) ; while ((opt = uNextOption(in, nin, options, &next, &optarg)) >= 0) { switch (opt) { case opt_verbose : ++ verbose ; break ; case opt_magnif : if (!uIsRealScalar(optarg) || (magnif = *mxGetPr(optarg)) < 0) { mexErrMsgTxt("MAGNIF must be a non-negative scalar.") ; } break ; default : assert(0) ; break ; } } grad_array = mxDuplicateArray(in[IN_GRAD]) ; grad = (vl_sift_pix*) mxGetData (grad_array) ; M = mxGetDimensions(in[IN_GRAD])[1] ; N = mxGetDimensions(in[IN_GRAD])[2] ; /* transpose angles */ for (i = 1 ; i < 2*M*N ; i+=2) { grad [i] = VL_PI/2 - grad [i] ; } /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ { VlSiftFilt *filt = 0 ; vl_uint8 *descr = 0 ; /* create a filter to process the image */ filt = vl_sift_new (M, N, -1, -1, 0) ; if (magnif >= 0) vl_sift_set_magnif (filt, magnif) ; if (verbose) { mexPrintf("siftdescriptor: filter settings:\n") ; mexPrintf("siftdescriptor: magnif = %g\n", vl_sift_get_magnif (filt)) ; mexPrintf("siftdescriptor: num of frames = %d\n", nikeys) ; } { mwSize dims [2] ; dims [0] = 128 ; dims [1] = nikeys ; out[OUT_DESCRIPTORS]= mxCreateNumericArray (2, dims, mxUINT8_CLASS, mxREAL) ; descr = mxGetData(out[OUT_DESCRIPTORS]) ; } /* ............................................................... * Process each octave * ............................................................ */ for (i = 0 ; i < nikeys ; ++i) { vl_sift_pix buf [128], rbuf [128] ; double y = *ikeys++ - 1 ; double x = *ikeys++ - 1 ; double s = *ikeys++ ; double th = VL_PI / 2 - *ikeys++ ; vl_sift_calc_raw_descriptor (filt, grad, buf, M, N, x, y, s, th) ; transpose_descriptor (rbuf, buf) ; for (j = 0 ; j < 128 ; ++j) { double x = 512.0 * rbuf [j] ; x = (x < 255.0) ? x : 255.0 ; *descr++ = (vl_uint8) (x) ; } } /* cleanup */ mxDestroyArray (grad_array) ; vl_sift_delete (filt) ; } /* job done */ }
/** @brief MEX entry point */ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_I = 0, IN_END } ; enum {OUT_SEEDS = 0, OUT_FRAMES } ; int verbose = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; /* algorithm parameters */ double delta = -1 ; double max_area = -1 ; double min_area = -1 ; double max_variation = -1 ; double min_diversity = -1 ; int nel ; int ndims ; mwSize const* dims ; vl_mser_pix const *data ; VL_USE_MATLAB_ENV ; /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin < 1) { mexErrMsgTxt("At least one input argument is required.") ; } if (nout > 2) { mexErrMsgTxt("Too many output arguments."); } if(mxGetClassID(in[IN_I]) != mxUINT8_CLASS) { mexErrMsgTxt("I must be of class UINT8") ; } /* get dimensions */ nel = mxGetNumberOfElements(in[IN_I]) ; ndims = mxGetNumberOfDimensions(in[IN_I]) ; dims = mxGetDimensions(in[IN_I]) ; data = mxGetData(in[IN_I]) ; while ((opt = uNextOption(in, nin, options, &next, &optarg)) >= 0) { switch (opt) { case opt_verbose : ++ verbose ; break ; case opt_delta : if (!uIsRealScalar(optarg) || (delta = *mxGetPr(optarg)) < 0) { mexErrMsgTxt("'Delta' must be non-negative.") ; } break ; case opt_max_area : if (!uIsRealScalar(optarg) || (max_area = *mxGetPr(optarg)) < 0 || max_area > 1) { mexErrMsgTxt("'MaxArea' must be in the range [0,1].") ; } break ; case opt_min_area : if (!uIsRealScalar(optarg) || (min_area = *mxGetPr(optarg)) < 0 || min_area > 1) { mexErrMsgTxt("'MinArea' must be in the range [0,1].") ; } break ; case opt_max_variation : if (!uIsRealScalar(optarg) || (max_variation = *mxGetPr(optarg)) < 0) { mexErrMsgTxt("'MaxVariation' must be non negative.") ; } break ; case opt_min_diversity : if (!uIsRealScalar(optarg) || (min_diversity = *mxGetPr(optarg)) < 0 || min_diversity > 1.0) { mexErrMsgTxt("'MinDiversity' must be in the [0,1] range.") ; } break ; default : assert(0) ; break ; } } /* ----------------------------------------------------------------- * Run algorithm * -------------------------------------------------------------- */ { VlMserFilt *filt ; vl_uint const *regions ; float const *frames ; int i, j, nregions, nframes, dof ; mwSize odims [2] ; double *pt ; /* new filter */ { int * vlDims = mxMalloc(sizeof(int) * ndims) ; for (i = 0 ; i < ndims ; ++i) vlDims [i] = dims [i] ; filt = vl_mser_new (ndims, vlDims) ; mxFree(vlDims) ; } if (!filt) { mexErrMsgTxt("Could not create an MSER filter.") ; } if (delta >= 0) vl_mser_set_delta (filt, (vl_mser_pix) delta) ; if (max_area >= 0) vl_mser_set_max_area (filt, max_area) ; if (min_area >= 0) vl_mser_set_min_area (filt, min_area) ; if (max_variation >= 0) vl_mser_set_max_variation (filt, max_variation) ; if (min_diversity >= 0) vl_mser_set_min_diversity (filt, min_diversity) ; if (verbose) { mexPrintf("mser: parameters:\n") ; mexPrintf("mser: delta = %d\n", vl_mser_get_delta (filt)) ; mexPrintf("mser: max_area = %g\n", vl_mser_get_max_area (filt)) ; mexPrintf("mser: min_area = %g\n", vl_mser_get_min_area (filt)) ; mexPrintf("mser: max_variation = %g\n", vl_mser_get_max_variation (filt)) ; mexPrintf("mser: min_diversity = %g\n", vl_mser_get_min_diversity (filt)) ; } /* process the image */ vl_mser_process (filt, data) ; /* save regions back to array */ nregions = vl_mser_get_regions_num (filt) ; regions = vl_mser_get_regions (filt) ; odims [0] = nregions ; out [OUT_SEEDS] = mxCreateNumericArray (1, odims, mxDOUBLE_CLASS,mxREAL) ; pt = mxGetPr (out [OUT_SEEDS]) ; for (i = 0 ; i < nregions ; ++i) pt [i] = regions [i] + 1 ; /* optionally compute and save ellipsoids */ if (nout > 1) { vl_mser_ell_fit (filt) ; nframes = vl_mser_get_ell_num (filt) ; dof = vl_mser_get_ell_dof (filt) ; frames = vl_mser_get_ell (filt) ; odims [0] = dof ; odims [1] = nframes ; out [OUT_FRAMES] = mxCreateNumericArray (2, odims, mxDOUBLE_CLASS, mxREAL) ; pt = mxGetPr (out [OUT_FRAMES]) ; for (i = 0 ; i < nframes ; ++i) { for (j = 0 ; j < dof ; ++j) { pt [i * dof + j] = frames [i * dof + j] + ((j < ndims)?1.0:0.0) ; } } } if (verbose) { VlMserStats const* s = vl_mser_get_stats (filt) ; int tot = s-> num_extremal ; mexPrintf("mser: statistics:\n") ; mexPrintf("mser: %d extremal regions of which\n", tot) ; #define REMAIN(test,num) \ mexPrintf("mser: %5d (%7.3g %% of previous) " test "\n", \ tot-(num),100.0*(double)(tot-(num))/(tot+VL_EPSILON_D)) ; \ tot -= (num) ; REMAIN("maximally stable,", s-> num_unstable ) ; REMAIN("stable enough,", s-> num_abs_unstable) ; REMAIN("small enough,", s-> num_too_big ) ; REMAIN("big enough,", s-> num_too_small ) ; REMAIN("diverse enough.", s-> num_duplicates ) ; } /* cleanup */ vl_mser_delete (filt) ; } }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M,N,S,smin,K ; const int* dimensions ; const double* P_pt ; const double* G_pt ; double* TH_pt ; double sigma0 ; double H_pt [ NBINS ] ; enum {IN_P=0,IN_G,IN_S,IN_SMIN,IN_SIGMA0} ; enum {OUT_Q=0} ; /* ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin != 5) { mexErrMsgTxt("Exactly five input arguments required."); } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if( !uIsRealScalar(in[IN_S]) ) { mexErrMsgTxt("S should be a real scalar") ; } if( !uIsRealScalar(in[IN_SMIN]) ) { mexErrMsgTxt("SMIN should be a real scalar") ; } if( !uIsRealScalar(in[IN_SIGMA0]) ) { mexErrMsgTxt("SIGMA0 should be a real scalar") ; } if( !uIsRealMatrix(in[IN_P],3,-1)) { mexErrMsgTxt("P should be a 3xK real matrix") ; } if(mxGetNumberOfDimensions(in[IN_G]) != 3) { mexErrMsgTxt("SSO must be a three dimensional array") ; } dimensions = mxGetDimensions(in[IN_G]) ; M = dimensions[0] ; N = dimensions[1] ; S = (int)(*mxGetPr(in[IN_S])) ; smin = (int)(*mxGetPr(in[IN_SMIN])) ; sigma0 = *mxGetPr(in[IN_SIGMA0]) ; K = mxGetN(in[IN_P]) ; P_pt = mxGetPr(in[IN_P]) ; G_pt = mxGetPr(in[IN_G]) ; /* If the input array is empty, then output an empty array as well. */ if(K == 0) { out[OUT_Q] = mxCreateDoubleMatrix(4,0,mxREAL) ; return ; } /* ------------------------------------------------------------------ * Do the job * --------------------------------------------------------------- */ { int p ; const int yo = 1 ; const int xo = M ; const int so = M*N ; int buffer_size = K*4 ; double* buffer_start = (double*) mxMalloc( buffer_size *sizeof(double)) ; double* buffer_iterator = buffer_start ; double* buffer_end = buffer_start + buffer_size ; for(p = 0 ; p < K ; ++p, TH_pt += 2) { const double x = *P_pt++ ; const double y = *P_pt++ ; const double s = *P_pt++ ; int xi = ((int) (x+0.5)) ; /* Round them off. */ int yi = ((int) (y+0.5)) ; int si = ((int) (s+0.5)) - smin ; int xs ; int ys ; double sigmaw = win_factor * sigma0 * pow(2, ((double)s) / S) ; int W = (int) ceil(3.0 * sigmaw) ; int bin ; const double* pt ; /* Make sure that the rounded off keypoint index is within bound. */ if(xi < 0 || xi > N-1 || yi < 0 || yi > M-1 || si < 0 || si > dimensions[2]-1 ) { mexPrintf("Dropping %d: W %d x %d y %d si [%d,%d,%d,%d]\n",p,W,xi,yi,si,M,N,dimensions[2]) ; continue ; } /* Clear histogram buffer. */ { int i ; for(i = 0 ; i < NBINS ; ++i) H_pt[i] = 0 ; } pt = G_pt + xi*xo + yi*yo + si*so ; #define at(dx,dy) (*(pt + (dx)*xo + (dy)*yo)) for(xs = max(-W, 1-xi) ; xs <= min(+W, N -2 -xi) ; ++xs) { for(ys = max(-W, 1-yi) ; ys <= min(+W, M -2 -yi) ; ++ys) { double Dx = 0.5 * ( at(xs+1,ys) - at(xs-1,ys) ) ; double Dy = 0.5 * ( at(xs,ys+1) - at(xs,ys-1) ) ; double dx = ((double)(xi+xs)) - x; double dy = ((double)(yi+ys)) - y; if(dx*dx + dy*dy > W*W+0.5) continue ; { double win = exp( - (dx*dx + dy*dy)/(2*sigmaw*sigmaw) ) ; double mod = sqrt(Dx*Dx + Dy*Dy) ; double theta = fmod(atan2(Dy, Dx) + 2*M_PI, 2*M_PI) ; bin = (int) floor( NBINS * theta / (2*M_PI) ) ; H_pt[bin] += mod*win ; } } } /* Smooth histogram */ { int iter, i ; for (iter = 0; iter < 6; iter++) { double prev; prev = H_pt[NBINS-1]; for (i = 0; i < NBINS; i++) { float newh = (prev + H_pt[i] + H_pt[(i+1) % NBINS]) / 3.0; prev = H_pt[i] ; H_pt[i] = newh ; } } } /* Find most strong peaks. */ { int i ; double maxh = H_pt[0] ; for(i = 1 ; i < NBINS ; ++i) maxh = max(maxh, H_pt[i]) ; for(i = 0 ; i < NBINS ; ++i) { double h0 = H_pt[i] ; double hm = H_pt[(i-1+NBINS) % NBINS] ; double hp = H_pt[(i+1+NBINS) % NBINS] ; if( h0 > 0.8*maxh && h0 > hm && h0 > hp ) { double di = -0.5 * (hp-hm) / (hp+hm-2*h0) ; /*di=0;*/ double th = 2*M_PI*(i+di+0.5)/NBINS ; if( buffer_iterator == buffer_end ) { int offset = buffer_iterator - buffer_start ; buffer_size += 4*max(1, K/16) ; buffer_start = (double*) mxRealloc(buffer_start, buffer_size*sizeof(double)) ; buffer_end = buffer_start + buffer_size ; buffer_iterator = buffer_start + offset ; } *buffer_iterator++ = x ; *buffer_iterator++ = y ; *buffer_iterator++ = s ; *buffer_iterator++ = th ; } } /* Scan histogram */ } /* Find peaks */ } /* Save back the result. */ { double* result ; int NL = (buffer_iterator - buffer_start)/4 ; out[OUT_Q] = mxCreateDoubleMatrix(4, NL, mxREAL) ; result = mxGetPr(out[OUT_Q]); memcpy(result, buffer_start, sizeof(double) * 4 * NL) ; } mxFree(buffer_start) ; } }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M,N,S,smin,K ; const int* dimensions ; const double* P_pt ; const double* D_pt ; double threshold = 0.01 ; /*0.02 ;*/ double r = 10.0 ; double* result ; enum {IN_P=0,IN_D,IN_SMIN,IN_THRESHOLD,IN_R} ; enum {OUT_Q=0} ; /* ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin < 3) { mexErrMsgTxt("At least three input arguments required."); } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if( !uIsRealMatrix(in[IN_P],3,-1) ) { mexErrMsgTxt("P must be a 3xK real matrix") ; } if( !mxIsDouble(in[IN_D]) || mxGetNumberOfDimensions(in[IN_D]) != 3) { mexErrMsgTxt("G must be a three dimensional real array.") ; } if( !uIsRealScalar(in[IN_SMIN]) ) { mexErrMsgTxt("SMIN must be a real scalar.") ; } if(nin >= 4) { if(!uIsRealScalar(in[IN_THRESHOLD])) { mexErrMsgTxt("THRESHOLD must be a real scalar.") ; } threshold = *mxGetPr(in[IN_THRESHOLD]) ; } if(nin >= 5) { if(!uIsRealScalar(in[IN_R])) { mexErrMsgTxt("R must be a real scalar.") ; } r = *mxGetPr(in[IN_R]) ; } dimensions = mxGetDimensions(in[IN_D]) ; M = dimensions[0] ; N = dimensions[1] ; S = dimensions[2] ; smin = (int)(*mxGetPr(in[IN_SMIN])) ; if(S < 3 || M < 3 || N < 3) { mexErrMsgTxt("All dimensions of DOG must be not less than 3.") ; } K = mxGetN(in[IN_P]) ; P_pt = mxGetPr(in[IN_P]) ; D_pt = mxGetPr(in[IN_D]) ; /* If the input array is empty, then output an empty array as well. */ if( K == 0) { out[OUT_Q] = mxDuplicateArray(in[IN_P]) ; return ; } /* ----------------------------------------------------------------- * Do the job * -------------------------------------------------------------- */ { double* buffer = (double*) mxMalloc(K*3*sizeof(double)) ; double* buffer_iterator = buffer ; int p ; const int yo = 1 ; const int xo = M ; const int so = M*N ; for(p = 0 ; p < K ; ++p) { int x = ((int)*P_pt++) ; int y = ((int)*P_pt++) ; int s = ((int)*P_pt++) - smin ; int iter ; double b[3] ; /* Local maxima extracted from the DOG * have coorrinates 1<=x<=N-2, 1<=y<=M-2 * and 1<=s-mins<=S-2. This is also the range of the points * that we can refine. */ if(x < 1 || x > N-2 || y < 1 || y > M-2 || s < 1 || s > S-2) { continue ; } #define at(dx,dy,ds) (*(pt + (dx)*xo + (dy)*yo + (ds)*so)) { const double* pt = D_pt + y*yo + x*xo + s*so ; double Dx=0,Dy=0,Ds=0,Dxx=0,Dyy=0,Dss=0,Dxy=0,Dxs=0,Dys=0 ; int dx = 0 ; int dy = 0 ; int j, i, jj, ii ; for(iter = 0 ; iter < max_iter ; ++iter) { double A[3*3] ; #define Aat(i,j) (A[(i)+(j)*3]) x += dx ; y += dy ; pt = D_pt + y*yo + x*xo + s*so ; /* Compute the gradient. */ Dx = 0.5 * (at(+1,0,0) - at(-1,0,0)) ; Dy = 0.5 * (at(0,+1,0) - at(0,-1,0)); Ds = 0.5 * (at(0,0,+1) - at(0,0,-1)) ; /* Compute the Hessian. */ Dxx = (at(+1,0,0) + at(-1,0,0) - 2.0 * at(0,0,0)) ; Dyy = (at(0,+1,0) + at(0,-1,0) - 2.0 * at(0,0,0)) ; Dss = (at(0,0,+1) + at(0,0,-1) - 2.0 * at(0,0,0)) ; Dxy = 0.25 * ( at(+1,+1,0) + at(-1,-1,0) - at(-1,+1,0) - at(+1,-1,0) ) ; Dxs = 0.25 * ( at(+1,0,+1) + at(-1,0,-1) - at(-1,0,+1) - at(+1,0,-1) ) ; Dys = 0.25 * ( at(0,+1,+1) + at(0,-1,-1) - at(0,-1,+1) - at(0,+1,-1) ) ; /* Solve linear system. */ Aat(0,0) = Dxx ; Aat(1,1) = Dyy ; Aat(2,2) = Dss ; Aat(0,1) = Aat(1,0) = Dxy ; Aat(0,2) = Aat(2,0) = Dxs ; Aat(1,2) = Aat(2,1) = Dys ; b[0] = - Dx ; b[1] = - Dy ; b[2] = - Ds ; /* Gauss elimination */ for(j = 0 ; j < 3 ; ++j) { double maxa = 0 ; double maxabsa = 0 ; int maxi = -1 ; double tmp ; /* look for the maximally stable pivot */ for (i = j ; i < 3 ; ++i) { double a = Aat (i,j) ; double absa = abs (a) ; if (absa > maxabsa) { maxa = a ; maxabsa = absa ; maxi = i ; } } /* if singular give up */ if (maxabsa < 1e-10f) { b[0] = 0 ; b[1] = 0 ; b[2] = 0 ; break ; } i = maxi ; /* swap j-th row with i-th row and normalize j-th row */ for(jj = j ; jj < 3 ; ++jj) { tmp = Aat(i,jj) ; Aat(i,jj) = Aat(j,jj) ; Aat(j,jj) = tmp ; Aat(j,jj) /= maxa ; } tmp = b[j] ; b[j] = b[i] ; b[i] = tmp ; b[j] /= maxa ; /* elimination */ for (ii = j+1 ; ii < 3 ; ++ii) { double x = Aat(ii,j) ; for (jj = j ; jj < 3 ; ++jj) { Aat(ii,jj) -= x * Aat(j,jj) ; } b[ii] -= x * b[j] ; } } /* backward substitution */ for (i = 2 ; i > 0 ; --i) { double x = b[i] ; for (ii = i-1 ; ii >= 0 ; --ii) { b[ii] -= x * Aat(ii,i) ; } } /* If the translation of the keypoint is big, move the keypoint * and re-iterate the computation. Otherwise we are all set. */ dx= ((b[0] > 0.6 && x < N-2) ? 1 : 0 ) + ((b[0] < -0.6 && x > 1 ) ? -1 : 0 ) ; dy= ((b[1] > 0.6 && y < M-2) ? 1 : 0 ) + ((b[1] < -0.6 && y > 1 ) ? -1 : 0 ) ; if( dx == 0 && dy == 0 ) break ; } { double val = at(0,0,0) + 0.5 * (Dx * b[0] + Dy * b[1] + Ds * b[2]) ; double score = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ; double xn = x + b[0] ; double yn = y + b[1] ; double sn = s + b[2] ; if(fabs(val) > threshold && score < (r+1)*(r+1)/r && score >= 0 && fabs(b[0]) < 1.5 && fabs(b[1]) < 1.5 && fabs(b[2]) < 1.5 && xn >= 0 && xn <= N-1 && yn >= 0 && yn <= M-1 && sn >= 0 && sn <= S-1) { *buffer_iterator++ = xn ; *buffer_iterator++ = yn ; *buffer_iterator++ = sn+smin ; } } } } /* Copy the result into an array. */ { int NL = (buffer_iterator - buffer)/3 ; out[OUT_Q] = mxCreateDoubleMatrix(3, NL, mxREAL) ; result = mxGetPr(out[OUT_Q]); memcpy(result, buffer, sizeof(double) * 3 * NL) ; } mxFree(buffer) ; } }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M, N ; const double* F_pt ; int ndims ; int pdims = -1 ; int* offsets ; int* midx ; int* neighbors ; int nneighbors ; int* dims ; enum {F=0,THRESHOLD,P} ; enum {MAXIMA=0} ; double threshold = - mxGetInf() ; /* ------------------------------------------------------------------ * Check the arguments * --------------------------------------------------------------- */ if (nin < 1) { mexErrMsgTxt("At least one input argument is required."); } else if (nin > 3) { mexErrMsgTxt("At most three arguments are allowed.") ; } else if (nout > 1) { mexErrMsgTxt("Too many output arguments"); } /* The input must be a real matrix. */ if (!mxIsDouble(in[F]) || mxIsComplex(in[F])) { mexErrMsgTxt("Input must be real matrix."); } if(nin > 1) { if(!uIsRealScalar(in[THRESHOLD])) { mexErrMsgTxt("THRESHOLD must be a real scalar.") ; } threshold = *mxGetPr(in[THRESHOLD]) ; } if(nin > 2) { if(!uIsRealScalar(in[P])) mexErrMsgTxt("P must be a non-negative integer") ; pdims = (int) *mxGetPr(in[P]) ; if(pdims < 0) mexErrMsgTxt("P must be a non-negative integer") ; } ndims = mxGetNumberOfDimensions(in[F]) ; { /* We need to make a copy because in one special case (see below) we need to adjust dims[]. */ int d ; const int* const_dims = (int*) mxGetDimensions(in[F]) ; dims = mxMalloc(sizeof(int)*ndims) ; for(d=0 ; d < ndims ; ++d) dims[d] = const_dims[d] ; } M = dims[0] ; N = dims[1] ; F_pt = mxGetPr(in[F]) ; /* 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). */ if((ndims == 2) && (pdims < 0) && (M == 1 || N == 1)) { pdims = 1 ; M = (M>N)?M:N ; N = 1 ; dims[0]=M ; dims[1]=N ; } /* search the local maxima along the first p dimensions only */ if(pdims < 0) pdims = ndims ; if(pdims > ndims) { mxFree(dims) ; mexErrMsgTxt("P must not be greater than the number of dimensions") ; } /* ------------------------------------------------------------------ * Do the job * --------------------------------------------------------------- */ { int maxima_size = M*N ; int* maxima_start = (int*) mxMalloc(sizeof(int) * maxima_size) ; int* maxima_iterator = maxima_start ; int* maxima_end = maxima_start + maxima_size ; int i,h,o ; const double* pt = F_pt ; /* Compute the offsets between dimensions. */ offsets = (int*) mxMalloc(sizeof(int) * ndims) ; offsets[0] = 1 ; for(h = 1 ; h < ndims ; ++h) offsets[h] = offsets[h-1]*dims[h-1] ; /* Multi-index. */ midx = (int*) mxMalloc(sizeof(int) * ndims) ; for(h = 0 ; h < ndims ; ++h) midx[h] = 1 ; /* Neighbors. */ nneighbors = 1 ; o=0 ; for(h = 0 ; h < pdims ; ++h) { nneighbors *= 3 ; midx[h] = -1 ; o -= offsets[h] ; } nneighbors -= 1 ; neighbors = (int*) mxMalloc(sizeof(int) * nneighbors) ; /* Precompute offsets from offset(-1,...,-1,0,...0) to * offset(+1,...,+1,0,...,0). */ i = 0 ; while(true) { if(o != 0) neighbors[i++] = o ; h = 0 ; while( o += offsets[h], (++midx[h]) > 1 ) { o -= 3*offsets[h] ; midx[h] = -1 ; if(++h >= pdims) goto stop ; } } stop: ; /* Starts at the corner (1,1,...,1,0,0,...0) */ for(h = 0 ; h < pdims ; ++h) { midx[h] = 1 ; pt += offsets[h] ; } for(h = pdims ; h < ndims ; ++h) { midx[h] = 0 ; } /* --------------------------------------------------------------- * 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 < pdims ; ++h) if(dims[h] < 3) goto end ; while(true) { /* Propagate carry along multi index midx */ h = 0 ; while((midx[h]) >= dims[h] - 1) { pt += 2*offsets[h] ; /* skip first and last el. */ midx[h] = 1 ; if(++h >= pdims) goto next_layer ; ++midx[h] ; } /* for(h = 0 ; h < ndims ; ++h ) mexPrintf("%d ", midx[h]) ; mexPrintf(" -- %d -- pdims %d \n", pt - F_pt,pdims) ; */ /* Scan neighbors */ { double v = *pt ; bool is_greater = (v >= threshold) ; i = 0 ; while(is_greater && i < nneighbors) is_greater &= v > *(pt + neighbors[i++]) ; /* Add the local maximum */ if(is_greater) { /* Need more space? */ if(maxima_iterator == maxima_end) { maxima_size += M*N ; maxima_start = (int*) mxRealloc(maxima_start, maxima_size*sizeof(int)) ; maxima_end = maxima_start + maxima_size ; maxima_iterator = maxima_end - M*N ; } *maxima_iterator++ = pt - F_pt + 1 ; } /* Go to next element */ pt += 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. */ { double* M_pt ; out[MAXIMA] = mxCreateDoubleMatrix (1, maxima_iterator-maxima_start, mxREAL) ; maxima_end = maxima_iterator ; maxima_iterator = maxima_start ; M_pt = mxGetPr(out[MAXIMA]) ; while(maxima_iterator != maxima_end) { *M_pt++ = *maxima_iterator++ ; } } /* Release space. */ mxFree(offsets) ; mxFree(neighbors) ; mxFree(midx) ; mxFree(maxima_start) ; } mxFree(dims) ; }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_I=0,IN_END} ; enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ; int verbose = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; vl_sift_pix const *data ; int M, N ; int O = - 1 ; int S = 3 ; int o_min = 0 ; double edge_thresh = -1 ; double peak_thresh = -1 ; double norm_thresh = -1 ; mxArray *ikeys_array = 0 ; double *ikeys = 0 ; int nikeys = -1 ; vl_bool force_orientations = 0 ; VL_USE_MATLAB_ENV ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if (nin < 1) { mexErrMsgTxt("One argument required.") ; } else if (nout > 2) { mexErrMsgTxt("Too many output arguments."); } if (mxGetNumberOfDimensions (in[IN_I]) != 2 || mxGetClassID (in[IN_I]) != mxSINGLE_CLASS ) { mexErrMsgTxt("I must be a matrix of class SINGLE") ; } data = (vl_sift_pix*) mxGetData (in[IN_I]) ; M = mxGetM (in[IN_I]) ; N = mxGetN (in[IN_I]) ; while ((opt = uNextOption(in, nin, options, &next, &optarg)) >= 0) { switch (opt) { case opt_verbose : ++ verbose ; break ; case opt_octaves : if (!uIsRealScalar(optarg) || (O = (int) *mxGetPr(optarg)) < 0) { mexErrMsgTxt("'Octaves' must be a positive integer.") ; } break ; case opt_levels : if (! uIsRealScalar(optarg) || (S = (int) *mxGetPr(optarg)) < 1) { mexErrMsgTxt("'Levels' must be a positive integer.") ; } break ; case opt_first_octave : if (!uIsRealScalar(optarg)) { mexErrMsgTxt("'FirstOctave' must be an integer") ; } o_min = (int) *mxGetPr(optarg) ; break ; case opt_edge_thresh : if (!uIsRealScalar(optarg) || (edge_thresh = *mxGetPr(optarg)) < 1) { mexErrMsgTxt("'EdgeThresh' must be not smaller than 1.") ; } break ; case opt_peak_thresh : if (!uIsRealScalar(optarg) || (peak_thresh = *mxGetPr(optarg)) < 0) { mexErrMsgTxt("'PeakThresh' must be a non-negative real.") ; } break ; case opt_norm_thresh : if (!uIsRealScalar(optarg) || (norm_thresh = *mxGetPr(optarg)) < 0) { mexErrMsgTxt("'NormThresh' must be a non-negative real.") ; } break ; case opt_frames : if (!uIsRealMatrix(optarg, 4, -1)) { mexErrMsgTxt("'Frames' must be a 4 x N matrix.x") ; } ikeys_array = mxDuplicateArray (optarg) ; nikeys = mxGetN (optarg) ; ikeys = mxGetPr (ikeys_array) ; if (! check_sorted (ikeys, nikeys)) { qsort (ikeys, nikeys, 4 * sizeof(double), korder) ; } break ; case opt_orientations : force_orientations = 1 ; break ; default : assert(0) ; break ; } } /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ { VlSiftFilt *filt ; vl_bool first ; double *frames = 0 ; vl_uint8 *descr = 0 ; int nframes = 0, reserved = 0, i,j,q ; /* create a filter to process the image */ filt = vl_sift_new (M, N, O, S, o_min) ; if (peak_thresh >= 0) vl_sift_set_peak_thresh (filt, peak_thresh) ; if (edge_thresh >= 0) vl_sift_set_edge_thresh (filt, edge_thresh) ; if (norm_thresh >= 0) vl_sift_set_norm_thresh (filt, norm_thresh) ; if (verbose) { mexPrintf("siftmx: filter settings:\n") ; mexPrintf("siftmx: octaves (O) = %d\n", vl_sift_get_octave_num (filt)) ; mexPrintf("siftmx: levels (S) = %d\n", vl_sift_get_level_num (filt)) ; mexPrintf("siftmx: first octave (o_min) = %d\n", vl_sift_get_octave_first (filt)) ; mexPrintf("siftmx: edge thresh = %g\n", vl_sift_get_edge_thresh (filt)) ; mexPrintf("siftmx: peak thresh = %g\n", vl_sift_get_peak_thresh (filt)) ; mexPrintf("siftmx: norm thresh = %g\n", vl_sift_get_norm_thresh (filt)) ; mexPrintf((nikeys >= 0) ? "siftmx: will source frames? yes (%d)\n" : "siftmx: will source frames? no\n", nikeys) ; mexPrintf("siftmx: will force orientations? %s\n", force_orientations ? "yes" : "no") ; } /* ............................................................... * Process each octave * ............................................................ */ i = 0 ; first = 1 ; while (true) { int err ; VlSiftKeypoint const *keys = 0 ; int nkeys = 0 ; if (verbose) { mexPrintf ("siftmx: processing octave %d\n", vl_sift_get_octave_index (filt)) ; } /* Calculate the GSS for the next octave .................... */ if (first) { err = vl_sift_process_first_octave (filt, data) ; first = 0 ; } else { err = vl_sift_process_next_octave (filt) ; } if (err) break ; if (verbose > 1) { printf("siftmx: GSS octave %d computed\n", vl_sift_get_octave_index (filt)); } /* Run detector ............................................. */ if (nikeys < 0) { vl_sift_detect (filt) ; keys = vl_sift_get_keypoints (filt) ; nkeys = vl_sift_get_keypoints_num (filt) ; i = 0 ; if (verbose > 1) { printf ("siftmx: detected %d (unoriented) keypoints\n", nkeys) ; } } else { nkeys = nikeys ; } /* For each keypoint ........................................ */ for (; i < nkeys ; ++i) { double angles [4] ; int nangles ; VlSiftKeypoint ik ; VlSiftKeypoint const *k ; /* Obtain keypoint orientations ........................... */ if (nikeys >= 0) { vl_sift_keypoint_init (filt, &ik, ikeys [4 * i + 1] - 1, ikeys [4 * i + 0] - 1, ikeys [4 * i + 2]) ; if (ik.o != vl_sift_get_octave_index (filt)) { break ; } k = &ik ; /* optionally compute orientations too */ if (force_orientations) { nangles = vl_sift_calc_keypoint_orientations (filt, angles, k) ; } else { angles [0] = VL_PI / 2 - ikeys [4 * i + 3] ; nangles = 1 ; } } else { k = keys + i ; nangles = vl_sift_calc_keypoint_orientations (filt, angles, k) ; } /* For each orientation ................................... */ for (q = 0 ; q < nangles ; ++q) { vl_sift_pix buf [128] ; vl_sift_pix rbuf [128] ; /* compute descriptor (if necessary) */ if (nout > 1) { vl_sift_calc_keypoint_descriptor (filt, buf, k, angles [q]) ; transpose_descriptor (rbuf, buf) ; } /* make enough room for all these keypoints and more */ if (reserved < nframes + 1) { reserved += 2 * nkeys ; frames = mxRealloc (frames, 4 * sizeof(double) * reserved) ; if (nout > 1) { descr = mxRealloc (descr, 128 * sizeof(double) * reserved) ; } } /* Save back with MATLAB conventions. Notice tha the input * image was the transpose of the actual image. */ frames [4 * nframes + 0] = k -> y + 1 ; frames [4 * nframes + 1] = k -> x + 1 ; frames [4 * nframes + 2] = k -> sigma ; frames [4 * nframes + 3] = VL_PI / 2 - angles [q] ; if (nout > 1) { for (j = 0 ; j < 128 ; ++j) { double x = 512.0 * rbuf [j] ; x = (x < 255.0) ? x : 255.0 ; descr [128 * nframes + j] = (vl_uint8) (x) ; } } ++ nframes ; } /* next orientation */ } /* next keypoint */ } /* next octave */ if (verbose) { mexPrintf ("siftmx: found %d keypoints\n", nframes) ; } /* ............................................................... * Save back * ............................................................ */ { int dims [2] ; /* create an empty array */ dims [0] = 0 ; dims [1] = 0 ; out[OUT_FRAMES] = mxCreateNumericArray (2, dims, mxDOUBLE_CLASS, mxREAL) ; /* set array content to be the frames buffer */ dims [0] = 4 ; dims [1] = nframes ; mxSetDimensions (out[OUT_FRAMES], dims, 2) ; mxSetPr (out[OUT_FRAMES], frames) ; if (nout > 1) { /* create an empty array */ dims [0] = 0 ; dims [1] = 0 ; out[OUT_DESCRIPTORS]= mxCreateNumericArray (2, dims, mxUINT8_CLASS, mxREAL) ; /* set array content to be the descriptors buffer */ dims [0] = 128 ; dims [1] = nframes ; mxSetDimensions (out[OUT_DESCRIPTORS], dims, 2) ; mxSetData (out[OUT_DESCRIPTORS], descr) ; } } /* cleanup */ vl_sift_delete (filt) ; if (ikeys_array) mxDestroyArray(ikeys_array) ; } /* end: do job */ }