VLFeat.org

API docs

  • Home
    • Download and Install
    • API docs
    • Matlab docs
    • About VLFeat
  • Tutorials
    • SIFT
    • MSER
    • IKM
    • HIKM
    • AIB
    • Utils
  • Main Page
  • Related Pages
  • Data Structures
  • Files
  • Examples

mser.c

Go to the documentation of this file.
00001 
00007 /* AUTORIGHTS
00008 Copyright 2007 (c) Andrea Vedaldi and Brian Fulkerson
00009 
00010 This file is part of VLFeat, available in the terms of the GNU
00011 General Public License version 2.
00012 */
00013 
00184 #include "mser.h"
00185 
00186 #include<stdlib.h>
00187 #include<string.h>
00188 #include<assert.h>
00189 
00201 VL_INLINE void
00202 adv(int ndims, int const *dims, int *subs)
00203 {
00204   int d = 0 ;
00205   while(d < ndims) {
00206     if( ++subs[d]  < dims[d] ) return ;
00207     subs[d++] = 0 ;
00208   }
00209 }
00210 
00226 VL_INLINE vl_uint
00227 climb (VlMserReg* r, vl_uint idx) 
00228 {
00229   
00230   vl_uint prev_idx = idx ;
00231   vl_uint next_idx ;
00232   vl_uint root_idx ;
00233 
00234   /* move towards root to find it */
00235   while (1) {
00236     
00237     /* next jump to the root */
00238     next_idx = r [idx] .shortcut ;
00239     
00240     /* recycle shortcut to remember how we came here */
00241     r [idx] .shortcut = prev_idx ;
00242     
00243     /* stop if the root is found */
00244     if( next_idx == idx ) break ;
00245 
00246     /* next guy */
00247     prev_idx = idx ;
00248     idx      = next_idx ;
00249   }
00250 
00251   root_idx = idx ;
00252 
00253   /* move backward to update shortcuts */
00254   while (1) {
00255     
00256     /* get previously visited one */
00257     prev_idx = r [idx] .shortcut ;
00258     
00259     /* update shortcut to point to the new root */
00260     r [idx] .shortcut = root_idx ;
00261 
00262     /* stop if the first visited node is reached */
00263     if( prev_idx == idx ) break ;
00264     
00265     /* next guy */
00266     idx = prev_idx ;
00267   }
00268 
00269   return root_idx ;
00270 }
00271 
00282 VL_EXPORT
00283 VlMserFilt*
00284 vl_mser_new (int ndims, int const* dims)
00285 {
00286   VlMserFilt* f ;
00287   int *strides, k ;
00288 
00289   f = vl_calloc (sizeof(VlMserFilt), 1) ;
00290 
00291   f-> ndims   = ndims ;
00292   f-> dims    = vl_malloc (sizeof(int) * ndims) ;
00293   f-> subs    = vl_malloc (sizeof(int) * ndims) ;
00294   f-> dsubs   = vl_malloc (sizeof(int) * ndims) ;
00295   f-> strides = vl_malloc (sizeof(int) * ndims) ;
00296 
00297   /* shortcuts */
00298   strides = f-> strides ;
00299 
00300   /* copy dims to f->dims */
00301   for(k = 0 ; k < ndims ; ++k) {
00302     f-> dims [k] = dims [k] ;
00303   }
00304   
00305   /* compute strides to move into the N-dimensional image array */
00306   strides [0] = 1 ;
00307   for(k = 1 ; k < ndims ; ++k) {
00308     strides [k] = strides [k-1] * dims [k-1] ;
00309   }
00310   
00311   /* total number of pixels */
00312   f-> nel = strides [ndims-1] * dims [ndims-1] ;
00313   
00314   /* dof of ellipsoids */
00315   f-> dof = ndims * (ndims + 1) / 2 + ndims ;
00316 
00317   /* more buffers */
00318   f-> perm   = vl_malloc (sizeof(vl_uint)   * f-> nel) ;
00319   f-> joins  = vl_malloc (sizeof(vl_uint)   * f-> nel) ;
00320   f-> r      = vl_malloc (sizeof(VlMserReg) * f-> nel) ;
00321 
00322   f-> er     = 0 ;
00323   f-> rer    = 0 ;
00324   f-> mer    = 0 ;
00325   f-> rmer   = 0 ;
00326   f-> ell    = 0 ;
00327   f-> rell   = 0 ;
00328 
00329   /* other parameters */
00330   f-> delta         = 5 ;
00331   f-> max_area      = 0.75 ;
00332   f-> min_area      = 3.0 / f-> nel ;
00333   f-> max_variation = 0.25 ;
00334   f-> min_diversity = 0.2 ;
00335 
00336   return f ;
00337 }
00338 
00346 VL_EXPORT
00347 void
00348 vl_mser_delete (VlMserFilt* f)
00349 {
00350   if(f) {
00351     if(f-> acc   )  vl_free( f-> acc    ) ;
00352     if(f-> ell   )  vl_free( f-> ell    ) ;
00353 
00354     if(f-> er    )  vl_free( f-> er     ) ;
00355     if(f-> r     )  vl_free( f-> r      ) ;
00356     if(f-> joins )  vl_free( f-> joins  ) ;
00357     if(f-> perm  )  vl_free( f-> perm   ) ;
00358     
00359     if(f-> strides) vl_free( f-> strides) ;
00360     if(f-> dsubs  ) vl_free( f-> dsubs  ) ;
00361     if(f-> subs   ) vl_free( f-> subs   ) ;
00362     if(f-> dims   ) vl_free( f-> dims   ) ;
00363     vl_free (f) ;
00364   }
00365 }
00366 
00367 
00380 VL_EXPORT
00381 void
00382 vl_mser_process (VlMserFilt* f, vl_mser_pix const* im)
00383 {
00384   /* shortcuts */
00385   vl_uint        nel     = f-> nel  ;
00386   vl_uint       *perm    = f-> perm ;
00387   vl_uint       *joins   = f-> joins ;
00388   int            ndims   = f-> ndims ;
00389   int           *dims    = f-> dims ;
00390   int           *subs    = f-> subs ;
00391   int           *dsubs   = f-> dsubs ;
00392   int           *strides = f-> strides ;
00393   VlMserReg     *r       = f-> r ;
00394   VlMserExtrReg *er      = f-> er ;
00395   vl_uint       *mer     = f-> mer ;
00396   int            delta   = f-> delta ;
00397 
00398   int njoins = 0 ;
00399   int ner    = 0 ;
00400   int nmer   = 0 ;
00401   int nbig   = 0 ;
00402   int nsmall = 0 ;
00403   int nbad   = 0 ;
00404   int ndup   = 0 ;
00405 
00406   int i, j, k ;
00407 
00408   /* delete any previosuly computed ellipsoid */
00409   f-> nell = 0 ;
00410 
00411   /* -----------------------------------------------------------------
00412    *                                          Sort pixels by intensity
00413    * -------------------------------------------------------------- */
00414   
00415   {
00416     vl_uint buckets [ VL_MSER_PIX_MAXVAL ] ;
00417 
00418     /* clear buckets */
00419     memset (buckets, 0, sizeof(vl_uint) * VL_MSER_PIX_MAXVAL ) ;
00420 
00421     /* compute bucket size (how many pixels for each intensity
00422        value) */
00423     for(i = 0 ; i < nel ; ++i) {
00424       vl_mser_pix v = im [i] ;
00425       ++ buckets [v] ;
00426     }
00427 
00428     /* cumulatively add bucket sizes */
00429     for(i = 1 ; i < VL_MSER_PIX_MAXVAL ; ++i) {
00430       buckets [i] += buckets [i-1] ;
00431     }
00432     
00433     /* empty buckets computing pixel ordering */
00434     for(i = nel ; i >= 1 ; ) {
00435       vl_mser_pix v = im [ --i ] ;
00436       vl_uint j = -- buckets [v] ;
00437       perm [j] = i ;
00438     }
00439   }
00440 
00441   /* initialize the forest with all void nodes */
00442   for(i = 0 ; i < nel ; ++i) {
00443     r [i] .parent = VL_MSER_VOID_NODE ;
00444   }
00445 
00446   /* -----------------------------------------------------------------
00447    *                        Compute regions and count extremal regions
00448    * -------------------------------------------------------------- */
00449   /* 
00450      In the following:
00451 
00452      idx    : index of the current pixel
00453      val    : intensity of the current pixel
00454      r_idx  : index of the root of the current pixel
00455      n_idx  : index of the neighbors of the current pixel
00456      nr_idx : index of the root of the neighbor of the current pixel
00457 
00458   */
00459   
00460   /* process each pixel by increasing intensity */
00461   for(i = 0 ; i < nel ; ++i) {
00462     
00463     /* pop next node xi */
00464     vl_uint     idx = perm [i] ;  
00465     vl_mser_pix val = im [idx] ;
00466     vl_uint     r_idx ;
00467     
00468     /* add the pixel to the forest as a root for now */
00469     r [idx] .parent   = idx ;
00470     r [idx] .shortcut = idx ;
00471     r [idx] .area     = 1 ;
00472     r [idx] .height   = 1 ;
00473 
00474     r_idx = idx ;
00475    
00476     /* convert the index IDX into the subscript SUBS; also initialize
00477        DSUBS to (-1,-1,...,-1) */
00478     {
00479       vl_uint temp = idx ;
00480       for(k = ndims - 1 ; k >= 0 ; --k) {
00481         dsubs [k] = -1 ;
00482         subs  [k] = temp / strides [k] ;
00483         temp      = temp % strides [k] ;
00484       }
00485     }
00486     
00487     /* examine the neighbors of the current pixel */
00488     while (1) {
00489       vl_uint n_idx = 0 ;
00490       vl_bool good = 1 ;
00491 
00492       /* 
00493          Compute the neighbor subscript as NSUBS+SUB, the
00494          corresponding neighbor index NINDEX and check that the
00495          neighbor is within the image domain.
00496       */
00497       for(k = 0 ; k < ndims && good ; ++k) {
00498         int temp  = dsubs [k] + subs [k] ;
00499         good     &= (0 <= temp) && (temp < dims [k]) ;
00500         n_idx    += temp * strides [k] ;
00501       }
00502 
00503       /* 
00504          The neighbor should be processed if the following conditions
00505          are met:
00506 
00507          1. The neighbor is within image boundaries.
00508 
00509          2. The neighbor is indeed different from the current node
00510             (the opposite happens when DSUB=(0,0,...,0)).
00511 
00512          3. The neighbor is already in the forest, meaning that it has
00513             already been processed.
00514       */
00515       if (good && 
00516           n_idx != idx &&
00517           r [n_idx] .parent != VL_MSER_VOID_NODE ) {
00518 
00519         vl_mser_pix nr_val = 0 ;
00520         vl_uint     nr_idx = 0 ;
00521         int         hgt   = r [ r_idx] .height ;
00522         int         n_hgt = r [nr_idx] .height ;
00523         
00524         /*
00525           Now we join the two subtrees rooted at
00526           
00527            R_IDX = ROOT(  IDX) 
00528           NR_IDX = ROOT(N_IDX).
00529           
00530           Note that R_IDX = ROOT(IDX) might change as we process more
00531           neighbors, so we need keep updating it. 
00532         */
00533         
00534          r_idx = climb(r,   idx) ;
00535         nr_idx = climb(r, n_idx) ;
00536         
00537         /*  
00538           At this point we have three possibilities:
00539           
00540           (A) ROOT(IDX) == ROOT(NR_IDX). In this case the two trees
00541               have already been joined and we do not do anything.
00542           
00543           (B) I(ROOT(IDX)) == I(ROOT(NR_IDX)). In this case the pixel
00544               IDX is extending an extremal region with the same
00545               intensity value. Since ROOT(NR_IDX) will NOT be an
00546               extremal region of the full image, ROOT(IDX) can be
00547               safely addedd as children of ROOT(NR_IDX) if this
00548               reduces the height according to the union rank
00549               heuristic.
00550                
00551           (C) I(ROOT(IDX)) > I(ROOT(NR_IDX)). In this case the pixel
00552               IDX is starting a new extremal region. Thus ROOT(NR_IDX)
00553               WILL be an extremal region of the final image and the
00554               only possibility is to add ROOT(NR_IDX) as children of
00555               ROOT(IDX), which becomes parent.
00556         */
00557 
00558         if( r_idx != nr_idx ) { /* skip if (A) */
00559 
00560           nr_val = im [nr_idx] ;
00561 
00562           if( nr_val == val && hgt < n_hgt ) {
00563 
00564             /* ROOT(IDX) becomes the child */
00565             r [r_idx]  .parent   = nr_idx ;
00566             r [r_idx]  .shortcut = nr_idx ;          
00567             r [nr_idx] .area    += r [r_idx] .area ;
00568             r [nr_idx] .height   = VL_MAX(n_hgt, hgt+1) ;
00569 
00570             joins [njoins++] = r_idx ;
00571 
00572           } else {
00573 
00574             /* cases ROOT(IDX) becomes the parent */
00575             r [nr_idx] .parent   = r_idx ;
00576             r [nr_idx] .shortcut = r_idx ;
00577             r [r_idx]  .area    += r [nr_idx] .area ;
00578             r [r_idx]  .height   = VL_MAX(hgt, n_hgt + 1) ;
00579 
00580             joins [njoins++] = nr_idx ; 
00581 
00582             /* count if extremal */
00583             if (nr_val != val) ++ ner ;
00584 
00585           } /* check b vs c */
00586         } /* check a vs b or c */        
00587       } /* neighbor done */
00588 
00589       /* move to next neighbor */      
00590       k = 0 ;
00591       while(++ dsubs [k] > 1) {
00592         dsubs [k++] = -1 ;
00593         if(k == ndims) goto done_all_neighbors ;
00594       }
00595     } /* next neighbor */
00596   done_all_neighbors : ;
00597   } /* next pixel */    
00598 
00599   /* the last root is extremal too */
00600   ++ ner ;
00601 
00602   /* save back */
00603   f-> njoins = njoins ;
00604 
00605   f-> stats. num_extremal = ner ;
00606 
00607   /* -----------------------------------------------------------------
00608    *                                          Extract extremal regions
00609    * -------------------------------------------------------------- */
00610 
00611   /* 
00612      Extremal regions are extracted and stored into the array ER.  The
00613      structure R is also updated so that .SHORTCUT indexes the
00614      corresponding extremal region if any (otherwise it is set to
00615      VOID).
00616   */
00617  
00618   /* make room */
00619   if (f-> rer < ner) {
00620     if (er) vl_free (er) ;
00621     f->er  = er = vl_malloc (sizeof(VlMserExtrReg) * ner) ;
00622     f->rer = ner ;      
00623   } ;
00624 
00625   /* save back */
00626   f-> nmer = ner ;
00627 
00628   /* count again */
00629   ner = 0 ;
00630 
00631   /* scan all regions Xi */
00632   for(i = 0 ; i < nel ; ++i) {
00633 
00634     /* pop next node xi */
00635     vl_uint     idx = perm [i] ;  
00636 
00637     vl_mser_pix val   = im [idx] ;
00638     vl_uint     p_idx = r  [idx] .parent ;
00639     vl_mser_pix p_val = im [p_idx] ;
00640 
00641     /* is extremal ? */
00642     vl_bool is_extr = (p_val > val) || idx == p_idx ;
00643     
00644     if( is_extr ) {
00645 
00646       /* if so, add it */      
00647       er [ner] .index      = idx ;
00648       er [ner] .parent     = ner ;
00649       er [ner] .value      = im [idx] ;
00650       er [ner] .area       = r  [idx] .area ;
00651       
00652       /* link this region to this extremal region */
00653       r [idx] .shortcut = ner ;
00654 
00655       /* increase count */
00656       ++ ner ;
00657     } else {      
00658       /* link this region to void */
00659       r [idx] .shortcut =   VL_MSER_VOID_NODE ;
00660     }
00661   }
00662 
00663   /* -----------------------------------------------------------------
00664    *                                   Link extremal regions in a tree
00665    * -------------------------------------------------------------- */
00666 
00667   for(i = 0 ; i < ner ; ++i) {
00668 
00669     vl_uint idx = er [i] .index ;
00670 
00671     do {
00672       idx = r[idx] .parent ;
00673     } while (r[idx] .shortcut == VL_MSER_VOID_NODE) ;
00674 
00675     er[i] .parent   = r[idx] .shortcut ;
00676     er[i] .shortcut = i ;
00677   }
00678 
00679   /* -----------------------------------------------------------------
00680    *                            Compute variability of +DELTA branches
00681    * -------------------------------------------------------------- */
00682   /* For each extremal region Xi of value VAL we look for the biggest
00683    * parent that has value not greater than VAL+DELTA. This is dubbed
00684    * `top parent'. */
00685 
00686   for(i = 0 ; i < ner ; ++i) {
00687 
00688     /* Xj is the current region the region and Xj are the parents */
00689     int     top_val = er [i] .value + delta ;
00690     int     top     = er [i] .shortcut ;
00691    
00692     /* examine all parents */
00693     while (1) {
00694       int next     = er [top]  .parent ;
00695       int next_val = er [next] .value ;
00696       
00697       /* Break if:
00698        * - there is no node above the top or
00699        * - the next node is above the top value. 
00700        */
00701       if (next == top || next_val > top_val) break ;
00702             
00703       /* so next could be the top */
00704       top = next ;
00705     }
00706     
00707     /* calculate branch variation */
00708     {
00709       int area     = er [i  ] .area ;
00710       int area_top = er [top] .area ;
00711       er [i] .variation  = (float) (area_top - area) / area ;
00712       er [i] .max_stable = 1 ;
00713     }
00714         
00715     /* Optimization: since extremal regions are processed by
00716      * increasing intensity, all next extremal regions being processed
00717      * have value at least equal to the one of Xi. If any of them has
00718      * parent the parent of Xi (this comprises the parent itself), we
00719      * can safely skip most intermediate node along the branch and
00720      * skip directly to the top to start our search. */
00721     {
00722       int parent = er [i] .parent ;
00723       int curr   = er [parent] .shortcut ;
00724       er [parent] .shortcut =  VL_MAX (top, curr) ;
00725     }
00726   }
00727     
00728   /* -----------------------------------------------------------------
00729    *                                  Select maximally stable branches
00730    * -------------------------------------------------------------- */
00731     
00732   nmer = ner ;
00733   for(i = 0 ; i < ner ; ++i) {
00734     vl_uint    parent = er [i     ] .parent ;
00735     vl_mser_pix   val = er [i     ] .value ;
00736     float     var = er [i     ] .variation ;
00737     vl_mser_pix p_val = er [parent] .value ;
00738     float   p_var = er [parent] .variation ;
00739     vl_uint     loser ;
00740     
00741     /* 
00742        Notice that R_parent = R_{l+1} only if p_val = val + 1. If not,
00743        this and the parent region coincide and there is nothing to do.
00744     */
00745     if(p_val > val + 1) continue ;
00746 
00747     /* decide which one to keep and put that in loser */
00748     if(var < p_var) loser = parent ; else loser = i ;
00749     
00750     /* make loser NON maximally stable */
00751     if(er [loser] .max_stable) {
00752       -- nmer ;
00753       er [loser] .max_stable = 0 ;
00754     }
00755   }
00756   
00757   f-> stats. num_unstable = ner - nmer ;
00758 
00759   /* -----------------------------------------------------------------
00760    *                                                 Further filtering
00761    * -------------------------------------------------------------- */
00762   /* It is critical for correct duplicate detection to remove regions
00763    * from the bottom (smallest one first).                          */
00764   {
00765     float max_area = (float) f-> max_area * nel ;
00766     float min_area = (float) f-> min_area * nel ;
00767     float max_var  = (float) f-> max_variation ;
00768     float min_div  = (float) f-> min_diversity ;
00769 
00770     /* scan all extremal regions (intensity value order) */
00771     for(i = ner-1 ; i >= 0L  ; --i) {
00772       
00773       /* process only maximally stable extremal regions */
00774       if (! er [i] .max_stable) continue ;
00775       
00776       if (er [i] .variation >= max_var ) { ++ nbad ;   goto remove ; }
00777       if (er [i] .area      >  max_area) { ++ nbig ;   goto remove ; }
00778       if (er [i] .area      <  min_area) { ++ nsmall ; goto remove ; }
00779       
00780       /* 
00781        * Remove duplicates 
00782        */
00783       if (min_div < 1.0) {
00784         vl_uint   parent = er [i] .parent ;
00785         int       area, p_area ;
00786         float div ;
00787         
00788         /* check all but the root mser */
00789         if(parent != i) {
00790           
00791           /* search for the maximally stable parent region */
00792           while(! er [parent] .max_stable) {
00793             vl_uint next = er [parent] .parent ;
00794             if(next == parent) break ;
00795             parent = next ;
00796           }
00797           
00798           /* Compare with the parent region; if the current and parent
00799            * regions are too similar, keep only the parent. */
00800           area    = er [i]      .area ;
00801           p_area  = er [parent] .area ;
00802           div     = (float) (p_area - area) / (float) p_area ;
00803           
00804           if (div < min_div) { ++ ndup ; goto remove ; }
00805         } /* remove dups end */
00806 
00807       }
00808       continue ;
00809     remove :
00810       er [i] .max_stable = 0 ;
00811       -- nmer ;      
00812     } /* check next region */
00813 
00814     f-> stats .num_abs_unstable = nbad ;
00815     f-> stats .num_too_big      = nbig ;
00816     f-> stats .num_too_small    = nsmall ;
00817     f-> stats .num_duplicates   = ndup ;
00818   }
00819   /* -----------------------------------------------------------------
00820    *                                                   Save the result
00821    * -------------------------------------------------------------- */
00822 
00823   /* make room */
00824   if (f-> rmer < nmer) {
00825     if (mer) vl_free (mer) ;
00826     f->mer  = mer = vl_malloc( sizeof(vl_uint) * nmer) ;
00827     f->rmer = nmer ;      
00828   }
00829 
00830   /* save back */
00831   f-> nmer = nmer ;
00832 
00833   j = 0 ;
00834   for (i = 0 ; i < ner ; ++i) {
00835     if (er [i] .max_stable) mer [j++] = er [i] .index ;
00836   }
00837 }
00838 
00847 VL_EXPORT
00848 void
00849 vl_mser_ell_fit (VlMserFilt* f)
00850 {
00851   /* shortcuts */
00852   int                nel = f-> nel ;
00853   int                dof = f-> dof ;
00854   int              *dims = f-> dims ;
00855   int              ndims = f-> ndims ;
00856   int              *subs = f-> subs ;
00857   int             njoins = f-> njoins ;
00858   vl_uint         *joins = f-> joins ;
00859   VlMserReg           *r = f-> r ;
00860   vl_uint           *mer = f-> mer ;
00861   int               nmer = f-> nmer ;
00862   vl_mser_acc       *acc = f-> acc ;
00863   vl_mser_acc       *ell = f-> ell ; 
00864 
00865   int d, index, i, j ;
00866   
00867   /* already fit ? */
00868   if (f->nell == f->nmer) return ;
00869   
00870   /* make room */
00871   if (f->rell < f->nmer) {
00872     if (f->ell) vl_free (f->ell) ;
00873     f->ell  = vl_malloc (sizeof(float) * f->nmer * f->dof) ;
00874     f->rell = f-> nmer ;
00875   }
00876 
00877   if (f->acc == 0) {
00878     f->acc = vl_malloc (sizeof(float) * f->nel) ;
00879   }
00880  
00881   acc = f-> acc ;
00882   ell = f-> ell ; 
00883      
00884   /* -----------------------------------------------------------------
00885    *                                                 Integrate moments
00886    * -------------------------------------------------------------- */
00887      
00888   /* for each dof */
00889   for(d = 0 ; d < f->dof ; ++d) {
00890 
00891     /* start from the upper-left pixel (0,0,...,0) */
00892     memset (subs, 0, sizeof(int) * ndims) ;
00893         
00894     /* step 1: fill acc pretending that each region has only one pixel */
00895     if(d < ndims) {
00896       /* 1-order ................................................... */
00897   
00898       for(index = 0 ; index < nel ; ++ index) {
00899         acc [index] = subs [d] ;
00900         adv(ndims, dims, subs) ;
00901       }      
00902     }
00903     else {      
00904       /* 2-order ................................................... */
00905 
00906       /* map the dof d to a second order moment E[x_i x_j] */      
00907       i = d - ndims ; 
00908       j = 0 ;
00909       while(i > j) {
00910         i -= j + 1 ;
00911         j ++ ;
00912       }      
00913       /* initialize acc with  x_i * x_j */
00914       for(index = 0 ; index < nel ; ++ index){
00915         acc [index] = subs [i] * subs [j] ;
00916         adv(ndims, dims, subs) ;
00917       }
00918     }
00919         
00920     /* step 2: integrate */
00921     for(i = 0 ; i < njoins ; ++i) {      
00922       vl_uint index  = joins [i] ;
00923       vl_uint parent = r [index] .parent ;
00924       acc [parent] += acc [index] ;
00925     }
00926     
00927     /* step 3: save back to ellpises */
00928     for(i = 0 ; i < nmer ; ++i) {      
00929       vl_uint idx = mer [i] ;
00930       ell [d + dof*i] = acc [idx] ;
00931     }
00932     
00933   }  /* next dof */
00934 
00935   /* -----------------------------------------------------------------
00936    *                                           Compute central moments
00937    * -------------------------------------------------------------- */
00938 
00939   for(index = 0 ; index < nmer ; ++index) {
00940     float  *pt  = ell + index * dof ;
00941     vl_uint    idx  = mer [index] ;
00942     float  area = r [idx] .area ;
00943     
00944     for(d = 0 ; d < dof ; ++d) {
00945 
00946       pt [d] /= area ; 
00947 
00948       if(d >= ndims) {
00949         /* remove squared mean from moment to get variance */
00950         i = d - ndims ; 
00951         j = 0 ;
00952         while(i > j) {
00953           i -= j + 1 ;
00954           j ++ ;
00955         }
00956         pt [d] -= pt [i] * pt [j] ;
00957       }
00958 
00959     }
00960   }
00961 
00962   /* save back */
00963   f-> nell = nmer ;
00964 }
00965 
Copyright © 2008 Andrea Vedaldi and Brian Fulkerson