Esempio n. 1
0
/** -------------------------------------------------------------------
 ** @brief Create a new MSER filter
 **
 ** Initializes a new MSER filter for images of the specified
 ** dimensions. Images are @a ndims -dimensional arrays of dimensions
 ** @a dims.
 **
 ** @param ndims number of dimensions.
 ** @param dims  dimensions.
 **/
VL_EXPORT
VlMserFilt*
vl_mser_new (int ndims, int const* dims)
{
  VlMserFilt* f ;
  int *strides, k ;

  f = (VlMserFilt*) vl_calloc (sizeof(VlMserFilt), 1) ;

  f-> ndims   = ndims ;
  f-> dims    = (int*) vl_malloc (sizeof(int) * ndims) ;
  f-> subs    = (int*) vl_malloc (sizeof(int) * ndims) ;
  f-> dsubs   = (int*) vl_malloc (sizeof(int) * ndims) ;
  f-> strides = (int*) vl_malloc (sizeof(int) * ndims) ;

  /* shortcuts */
  strides = f-> strides ;

  /* copy dims to f->dims */
  for(k = 0 ; k < ndims ; ++k) {
    f-> dims [k] = dims [k] ;
  }
  
  /* compute strides to move into the N-dimensional image array */
  strides [0] = 1 ;
  for(k = 1 ; k < ndims ; ++k) {
    strides [k] = strides [k-1] * dims [k-1] ;
  }
  
  /* total number of pixels */
  f-> nel = strides [ndims-1] * dims [ndims-1] ;
  
  /* dof of ellipsoids */
  f-> dof = ndims * (ndims + 1) / 2 + ndims ;

  /* more buffers */
  f-> perm   = (vl_uint*) vl_malloc (sizeof(vl_uint)   * f-> nel) ;
  f-> joins  = (vl_uint*) vl_malloc (sizeof(vl_uint)   * f-> nel) ;
  f-> r      = (VlMserReg*) vl_malloc (sizeof(VlMserReg) * f-> nel) ;

  f-> er     = 0 ;
  f-> rer    = 0 ;
  f-> mer    = 0 ;
  f-> rmer   = 0 ;
  f-> ell    = 0 ;
  f-> rell   = 0 ;

  /* other parameters */
  f-> delta         = 5 ;
  f-> max_area      = 0.75 ;
  f-> min_area      = 3.0 / f-> nel ;
  f-> max_variation = 0.25 ;
  f-> min_diversity = 0.2 ;

  return f ;
}
Esempio n. 2
0
VL_EXPORT VlDsiftFilter *
vl_dsift_new (int imWidth, int imHeight)
{
  VlDsiftFilter * self = vl_malloc (sizeof(VlDsiftFilter)) ;
  self->imWidth  = imWidth ;
  self->imHeight = imHeight ;

  self->stepX = 5 ;
  self->stepY = 5 ;

  self->boundMinX = 0 ;
  self->boundMinY = 0 ;
  self->boundMaxX = imWidth - 1 ;
  self->boundMaxY = imHeight - 1 ;

  self->geom.numBinX = 4 ;
  self->geom.numBinY = 4 ;
  self->geom.numBinT = 8 ;
  self->geom.binSizeX = 5 ;
  self->geom.binSizeY = 5 ;

  self->useFlatWindow = VL_FALSE ;
  self->windowSize = 2.0 ;

  self->convTmp1 = vl_malloc(sizeof(float) * self->imWidth * self->imHeight) ;
  self->convTmp2 = vl_malloc(sizeof(float) * self->imWidth * self->imHeight) ;

  self->numBinAlloc = 0 ;
  self->numFrameAlloc = 0 ;
  self->numGradAlloc = 0 ;

  self->descrSize = 0 ;
  self->numFrames = 0 ;
  self->grads = NULL ;
  self->frames = NULL ;
  self->descrs = NULL ;

  _vl_dsift_update_buffers(self) ;
  return self ;
}
Esempio n. 3
0
static void
VL_XCAT(_vl_kmeans_set_centers_, SFX)
(VlKMeans * self,
 TYPE const * centers,
 vl_size dimension,
 vl_size numCenters)
{
  self->dimension = dimension ;
  self->numCenters = numCenters ;
  self->centers = vl_malloc (sizeof(TYPE) * dimension * numCenters) ;
  memcpy ((TYPE*)self->centers, centers,
          sizeof(TYPE) * dimension * numCenters) ;
}
Esempio n. 4
0
vl_aib_prob * vl_aib_new_Pc(vl_aib_prob * Pcx, vl_aib_node nvalues, vl_aib_node nlabels)
{
    vl_aib_prob * Pc = vl_malloc(sizeof(vl_aib_prob)*nlabels);
    vl_aib_node r, c;
    for(c=0; c<nlabels; c++)
    {
        vl_aib_prob sum = 0;
        for(r=0; r<nvalues; r++)
            sum += Pcx[r*nlabels+c];
        Pc[c] = sum;
    }
    return Pc;
}
Esempio n. 5
0
VL_EXPORT VlArray *
vl_array_init (VlArray* self, vl_type type,
               vl_size numDimensions, vl_size const * dimensions)
{
  assert (numDimensions <= VL_ARRAY_MAX_NUM_DIMENSIONS) ;
  self->type = type ;
  self->numDimensions = numDimensions ;
  memcpy(self->dimensions, dimensions, sizeof(vl_size) * numDimensions) ;
  self->data = vl_malloc(vl_get_type_size(type) * vl_array_get_num_elements (self)) ;
  self->isEnvelope = VL_FALSE ;
  self->isSparse = VL_FALSE ;
  return self ;
}
Esempio n. 6
0
double * vl_aib_new_Pc(double * Pcx, vl_uint nvalues, vl_uint nlabels)
{
    double * Pc = vl_malloc(sizeof(double)*nlabels);
    vl_uint r, c;
    for(c=0; c<nlabels; c++)
    {
        double sum = 0;
        for(r=0; r<nvalues; r++)
            sum += Pcx[r*nlabels+c];
        Pc[c] = sum;
    }
    return Pc;
}
Esempio n. 7
0
VL_EXPORT
VlQS *
vl_quickshift_new(vl_qs_type const * image, int height, int width,
                       int channels)
{
  VlQS * q = vl_malloc(sizeof(VlQS));

  q->image    = (vl_qs_type *)image;
  q->height   = height;
  q->width    = width;
  q->channels = channels;

  q->medoid   = VL_FALSE;
  q->tau      = VL_MAX(height,width)/50;
  q->sigma    = VL_MAX(2, q->tau/3);

  q->dists    = vl_malloc(sizeof(vl_qs_type)*height*width);
  q->parents  = vl_malloc(sizeof(int)*height*width); 
  q->density  = vl_malloc(sizeof(vl_qs_type)*height*width);

  return q;
}
Esempio n. 8
0
size_t
read_VlKDTree(FILE *fp, VlKDForest * self, VlKDTree *tree)
{
    size_t n = 0;
    vl_size i;

    n += fread(&(tree->numUsedNodes), sizeof(vl_size), 1, fp);
    n += fread(&(tree->numAllocatedNodes), sizeof(vl_size), 1, fp);
    n += fread(&(tree->depth), sizeof(unsigned int), 1, fp);

    tree->nodes = vl_malloc(sizeof(VlKDTreeNode) * tree->numAllocatedNodes);
    for(i = 0;i < tree->numAllocatedNodes; i++){
        n += read_VlKDTreeNode(fp, &tree->nodes[i]);
    }

    tree->dataIndex = vl_malloc(sizeof(VlKDTreeDataIndexEntry) * self->numData);
    for(i = 0;i < self->numData ; i++){
        n += read_VlKDTreeDataIndexEntry(fp, &tree->dataIndex[i]);
    }

    return n;
}
Esempio n. 9
0
VL_EXPORT
VlHIKMTree *
vl_hikm_new (int method)
{
  VlHIKMTree *f = vl_malloc (sizeof(VlHIKMTree)) ;
  f -> M          = 0 ;
  f -> K          = 0 ;
  f -> max_niters = 200 ;
  f -> method     = method ;
  f -> verb       = 0 ;
  f -> depth      = 0 ;
  f -> root       = 0 ;
  return f ;
}
Esempio n. 10
0
VlIKMFilt *
vl_ikm_new (int method)
{
  VlIKMFilt *f =  vl_malloc (sizeof(VlIKMFilt)) ;
  f -> centers = 0 ;
  f -> inter_dist = 0 ;

  f -> M = 0 ;
  f -> K = 0 ;
  f -> method     = method ;
  f -> max_niters = 200 ;
  f -> verb       = 0 ;

  return f ;
}
Esempio n. 11
0
VL_EXPORT
int
vl_pgm_insert(FILE* f, VlPgmImage const *im, void const *data)
{
  vl_size bpp = vl_pgm_get_bpp (im) ;
  vl_size data_size = vl_pgm_get_npixels (im) ;
  size_t c ;

  VlThreadSpecificState * threadState = vl_get_thread_specific_state() ;

  /* write preamble */
  fprintf(f,
          "P5\n%d\n%d\n%d\n",
          (signed)im->width,
          (signed)im->height,
          (signed)im->max_value) ;

  /* take care of endianness */
#if defined(VL_ARCH_LITTLE_ENDIAN)
  if (bpp == 2) {
    vl_uindex i ;
    vl_uint8* temp = (vl_uint8* )vl_malloc (2 * data_size) ;
    memcpy(temp, data, 2 * data_size) ;
    for(i = 0 ; i < 2 * data_size ; i += 2) {
      vl_uint8 tmp = temp [i] ;
      temp [i]   = temp [i+1] ;
      temp [i+1] = tmp ;
    }
    c = fwrite(temp, 2, data_size, f) ;
    vl_free (temp) ;
  }
  else {
#endif
    c = fwrite(data, bpp, data_size, f) ;
#if defined(VL_ARCH_LITTLE_ENDIAN)
  }
#endif

  if(c != data_size) {
       snprintf(threadState->lastErrorMessage, VL_ERR_MSG_LEN,
             "Error writing PGM data") ;
    return (threadState->lastError = VL_ERR_PGM_IO) ;

  }
  return 0 ;
}
Esempio n. 12
0
VL_EXPORT VlKDForest *
vl_kdforest_new (vl_type dataType,
                 vl_size dimension, vl_size numTrees)
{
  VlKDForest * self = vl_malloc (sizeof(VlKDForest)) ;

  assert(dataType == VL_TYPE_FLOAT || dataType == VL_TYPE_DOUBLE) ;
  assert(dimension >= 1) ;
  assert(numTrees >= 1) ;

  self -> rand = vl_get_rand () ;
  self -> dataType = dataType ;
  self -> numData = 0 ;
  self -> data = 0 ;
  self -> dimension = dimension ;
  self -> numTrees = numTrees ;
  self -> trees = 0 ;
  self -> thresholdingMethod = VL_KDTREE_MEDIAN ;
  self -> splitHeapSize = (numTrees == 1) ? 1 : VL_KDTREE_SPLIT_HEALP_SIZE ;
  self -> splitHeapNumNodes = 0 ;

  self -> searchHeapArray = 0 ;
  self -> searchHeapNumNodes = 0 ;

  self -> searchMaxNumComparisons = 0 ;
  self -> searchIdBook = 0 ;
  self -> searchId = 0 ;

  switch (self->dataType) {
    case VL_TYPE_FLOAT:
      self -> distanceFunction = (void(*)(void))
      vl_get_vector_comparison_function_f (VlDistanceL2) ;
      break ;
    case VL_TYPE_DOUBLE :
      self -> distanceFunction = (void(*)(void))
      vl_get_vector_comparison_function_d (VlDistanceL2) ;
      break ;
    default :
      abort() ;
  }

  return self ;
}
Esempio n. 13
0
VL_EXPORT VlKMeans *
vl_kmeans_new (vl_type dataType,
               VlVectorComparisonType distance)
{
  VlKMeans * self = vl_malloc(sizeof(VlKMeans)) ;

  self->algorithm = VlKMeansLloyd ;
  self->distance = distance ;
  self->dataType = dataType ;

  self->verbosity = 0 ;
  self->maxNumIterations = 100 ;
  self->numRepetitions = 1 ;

  self->centers = NULL ;
  self->centerDistances = NULL ;

  vl_kmeans_reset (self) ;

  return self ;
}
Esempio n. 14
0
float *
_vl_dsift_new_kernel (int binSize, int numBins, int binIndex, double windowSize)
{
  int filtLen = 2 * binSize - 1 ;
  float * ker = vl_malloc (sizeof(float) * filtLen) ;
  float * kerIter = ker ;
  float delta = binSize * (binIndex - 0.5F * (numBins - 1)) ;
  /*
  float sigma = 0.5F * ((numBins - 1) * binSize + 1) ;
  float sigma = 0.5F * ((numBins) * binSize) ;
  */
  float sigma = (float) binSize * (float) windowSize ;
  int x ;

  for (x = - binSize + 1 ; x <= + binSize - 1 ; ++ x) {
    float z = (x - delta) / sigma ;
    *kerIter++ = (1.0F - fabsf(x) / binSize) *
      ((binIndex >= 0) ? expf(- 0.5F * z*z) : 1.0F) ;
  }
  return ker ;
}
Esempio n. 15
0
static double
VL_XCAT(_vl_kmeans_update_center_distances_, SFX)
(VlKMeans * self)
{
#if (FLT == VL_TYPE_FLOAT)
  VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ;
#else
  VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ;
#endif

  if (! self->centerDistances) {
    self->centerDistances = vl_malloc (sizeof(TYPE) *
                                       self->numCenters *
                                       self->numCenters) ;
  }
  VL_XCAT(vl_eval_vector_comparison_on_all_pairs_, SFX)(self->centerDistances,
                                                        self->dimension,
                                                        self->centers, self->numCenters,
                                                        NULL, 0,
                                                        distFn) ;
  return self->numCenters * (self->numCenters - 1) / 2 ;
}
Esempio n. 16
0
int
vl_pgm_insert(FILE* f, VlPgmImage const *im, void *data)
{
  int bpp       = vl_pgm_get_bpp       (im) ;
  int data_size = vl_pgm_get_data_size (im) ;
  int c ; 
  
  /* write preamble */
  fprintf(f,
          "P5\n%d\n%d\n%d\n",
          im->width,
          im->height,
          im->max_value) ;

  /* take care of endianness */
  if (bpp == 2 && ! vl_get_endianness() == VL_BIG_ENDIAN) {
    int i ;
    vl_uint8* temp = vl_malloc (2 * data_size) ;
    memcpy(temp, data, 2 * data_size) ;
    for(i = 0 ; i < 2 * data_size ; i += 2) {
      vl_uint8 tmp = temp [i] ;
      temp [i]   = temp [i+1] ;
      temp [i+1] = tmp ;
    }
    c = fwrite(temp, 2, data_size, f) ;
    vl_free (temp) ;
  }
  else {
    c = fwrite(data, bpp, data_size, f) ;
  }
  
  if(c != data_size) {
    vl_err_no = VL_ERR_PGM_IO ;
    snprintf(vl_err_msg, VL_ERR_MSG_LEN,
             "Error writing PGM data") ;
    return vl_err_no ;
  }
  return 0 ;
}
Esempio n. 17
0
VL_EXPORT char *
vl_configuration_to_string_copy ()
{
  char * string = 0 ;
  int length = 0 ;
  char * staticString = vl_static_configuration_to_string_copy() ;
  char * cpuString =
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
  _vl_x86cpu_info_to_string_copy(&vl_get_state()->cpuInfo) ;
#else
  "Generic CPU" ;
#endif
#if defined(DEBUG)
  int const debug = 1 ;
#else
  int const debug = 0 ;
#endif

  while (string == 0) {
    if (length > 0) {
      string = vl_malloc(sizeof(char) * length) ;
      if (string == NULL) break ;
    }
    length = snprintf(string, length,
                      "VLFeat version %s\n"
                      "    Static config: %s\n"
                      "    %d CPU(s): %s\n"
                      "    Debug: %s\n",
                      vl_get_version_string (),
                      staticString,
                      vl_get_num_cpus(), cpuString,
                      VL_YESNO(debug)) ;
    length += 1 ;
  }

  if (staticString) vl_free(staticString) ;
  if (cpuString) vl_free(cpuString) ;
  return string ;
}
Esempio n. 18
0
File: host.c Progetto: 0x27/encuadro
char *
_vl_x86cpu_info_to_string_copy (VlX86CpuInfo const *self)
{
  char * string = 0 ;
  int length = 0 ;
  while (string == 0) {
    if (length > 0) {
      string = vl_malloc(sizeof(char) * length) ;
      if (string == NULL) break ;
    }
    length = snprintf(string, length, "%s%s%s%s%s%s%s",
                      self->vendor.string,
                      self->hasMMX   ? " MMX" : "",
                      self->hasSSE   ? " SSE" : "",
                      self->hasSSE2  ? " SSE2" : "",
                      self->hasSSE3  ? " SSE3" : "",
                      self->hasSSE41 ? " SSE41" : "",
                      self->hasSSE42 ? " SSE42" : "") ;
    length += 1 ;
  }
  return string ;
}
Esempio n. 19
0
bool HogExtractor::Extract(const vector<Mat> &images, Mat *feats)
{
    if (feats == nullptr)
    {
        return false;
    }

    *feats = Mat();
    for (auto image: images)
    {
        // Convert Mat to float array
        float image_data[image.total()];
        int k = 0;
        for (int i = 0; i < image.rows; ++i)
            for (int j = 0; j < image.cols; ++j, ++k)
            {
                image_data[k] = image.at<int>(i, j);
            }

        // Extract HOG features
        vl_hog_put_image(hog_, image_data, image.rows, image.cols,
                image.channels(), cell_size_);
        set_feat_dim(vl_hog_get_width(hog_) * vl_hog_get_height(hog_)
                * vl_hog_get_dimension(hog_));
        float *hog_arr = (float*)vl_malloc(feat_dim() * sizeof(float));
        vl_hog_extract(hog_, hog_arr);

        // Convert float array to Mat
        Mat feat_row(1, feat_dim(), CV_32F);
        for (int i = 0; i < feat_dim(); ++i)
        {
            feat_row.at<float>(0, i) = hog_arr[i];
        }
        vl_free(hog_arr);

        feats->push_back(feat_row);
    }
    return true;
}
Esempio n. 20
0
VL_EXPORT
int vl_pgm_read_new_f (char const *name,  VlPgmImage *im, float** data)
{
  int err = 0 ;
  size_t npixels ;
  vl_uint8 *idata ;

  err = vl_pgm_read_new (name, im, &idata) ;
  if (err) {
    return err ;
  }

  npixels = vl_pgm_get_npixels(im) ;
  *data = (float*)vl_malloc (sizeof(float) * npixels) ;
  {
    size_t k ;
    float scale = 1.0f / im->max_value ;
    for (k = 0 ; k < npixels ; ++ k) (*data)[k] = scale * idata[k] ;
  }

  vl_free (idata) ;
  return 0 ;
}
Esempio n. 21
0
float * _vl_dsift_new_kernel (int binSize, int numBins, int binIndex)
{  
  int filtLen = 2 * binSize - 1 ;
  float * ker = vl_malloc (sizeof(float) * filtLen) ;
  float * kerIter = ker ;
  float delta = binSize * (binIndex - 0.5F * (numBins - 1)) ;
  float sigma = 0.5F * ((numBins - 1) * binSize + 1) ;
  /* this is what standard SIFT would use. Above is what Oxford
     uses 
  float sigma = 0.5F * ((numBins) * binSize) ;
  */
  int x ;
  
  for (x = - binSize + 1 ; x <= + binSize - 1 ; ++ x) {
    float z = (x - delta) / sigma ;
    *kerIter++ = (1.0f - fabsf(x) / binSize) * 
      ((binIndex >= 0) ? expf(- 0.5F * z*z) : 1.0F) ;

    /* *kerIter++ = (1.0f - fabsf(x) / binSize)  ; */

  }
  return ker ;
}
Esempio n. 22
0
VL_EXPORT
int vl_pgm_read_new (char const *name, VlPgmImage *im, vl_uint8** data)
{
  int err = 0 ;
  VlThreadSpecificState * threadState = vl_get_thread_specific_state() ;

  FILE *f = fopen (name, "rb") ;

  if (! f) {
    snprintf(threadState->lastErrorMessage, VL_ERR_MSG_LEN,
             "Error opening PGM file `%s' for reading", name) ;
    return (threadState->lastError = VL_ERR_PGM_IO) ;
  }

  err = vl_pgm_extract_head(f, im) ;
  if (err) {
    fclose (f) ;
    return err ;
  }

  if (vl_pgm_get_bpp(im) > 1) {
    snprintf(threadState->lastErrorMessage, VL_ERR_MSG_LEN,
             "vl_pgm_read(): PGM with BPP > 1 not supported") ;
    return (threadState->lastError =  VL_ERR_BAD_ARG) ;
  }

  *data = (vl_uint8*)vl_malloc (vl_pgm_get_npixels(im) * sizeof(vl_uint8)) ;
  err = vl_pgm_extract_data(f, im, *data) ;

  if (err) {
    vl_free (data) ;
    fclose (f) ;
  }

  fclose (f) ;
  return err ;
}
Esempio n. 23
0
VlScaleSpace *
vl_scalespace_new_with_geometry (VlScaleSpaceGeometry geom)
{

  vl_index o ;
  vl_size numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ;
  vl_size numOctaves = geom.lastOctave - geom.firstOctave + 1 ;
  VlScaleSpace *self ;

  assert(is_valid_geometry(geom)) ;
  numOctaves = geom.lastOctave - geom.firstOctave + 1 ;
  numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ;

  self = vl_calloc(1, sizeof(VlScaleSpace)) ;
  if (self == NULL) goto err_alloc_self ;
  self->geom = geom ;
  self->octaves = vl_calloc(numOctaves, sizeof(float*)) ;
  if (self->octaves == NULL) goto err_alloc_octave_list ;
  for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
    VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ;
    vl_size octaveSize = ogeom.width * ogeom.height * numSublevels ;
    self->octaves[o - self->geom.firstOctave] = vl_malloc(octaveSize * sizeof(float)) ;
    if (self->octaves[o - self->geom.firstOctave] == NULL) goto err_alloc_octaves;
  }
  return self ;

err_alloc_octaves:
  for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
    if (self->octaves[o - self->geom.firstOctave]) {
      vl_free(self->octaves[o - self->geom.firstOctave]) ;
    }
  }
err_alloc_octave_list:
  vl_free(self) ;
err_alloc_self:
  return NULL ;
}
Esempio n. 24
0
int
main (int argc, char** argv)
{
  float * X ;
  float * Y ;
  vl_size numDimensions = 1000 ;
  vl_size numSamples    = 2000 ;
  float * result = vl_malloc (sizeof(float) * numSamples * numSamples) ;
  VlFloatVectorComparisonFunction f ;

  init_data (numDimensions, numSamples, &X, &Y) ;

  X+=1 ;
  Y+=1 ;

  vl_set_simd_enabled (VL_FALSE) ;
  f = vl_get_vector_comparison_function_f (VlDistanceL2) ;
  vl_tic () ;
  vl_eval_vector_comparison_on_all_pairs_f (result, numDimensions, X, numSamples, Y, numSamples, f) ;
  VL_PRINTF("Float L2 distnace: %.3f s\n", vl_toc ()) ;

  vl_set_simd_enabled (VL_TRUE) ;
  f = vl_get_vector_comparison_function_f (VlDistanceL2) ;
  vl_tic () ;
  vl_eval_vector_comparison_on_all_pairs_f (result, numDimensions, X, numSamples, Y, numSamples, f) ;
  VL_PRINTF("Float L2 distance (SIMD): %.3f s\n", vl_toc ()) ;

  X-- ;
  Y-- ;

  vl_free (X) ;
  vl_free (Y) ;
  vl_free (result) ;

  return 0 ;
}
Esempio n. 25
0
VL_EXPORT vl_size
vl_kdforest_query (VlKDForest * self,
                   VlKDForestNeighbor * neighbors,
                   vl_size numNeighbors,
                   void const * query)
{
  vl_uindex i, ti ;
  vl_bool exactSearch = (self->searchMaxNumComparisons == 0) ;
  VlKDForestSearchState * searchState  ;
  vl_size numAddedNeighbors = 0 ;

  assert (neighbors) ;
  assert (numNeighbors > 0) ;
  assert (query) ;

  /* this number is used to differentiate a query from the next */
  self -> searchId += 1 ;
  self -> searchNumRecursions = 0 ;

  if (! self -> searchHeapArray) {
    /* count number of tree nodes */
    /* add support structures */
    vl_size maxNumNodes = 0 ;
    for (ti = 0 ; ti < self->numTrees ; ++ti) {
      maxNumNodes += self->trees[ti]->numUsedNodes ;
    }
    self -> searchHeapArray = vl_malloc (sizeof(VlKDForestSearchState) * maxNumNodes) ;
    self -> searchIdBook = vl_calloc (sizeof(vl_uindex), self->numData) ;

    for (ti = 0 ; ti < self->numTrees ; ++ti) {
      double * searchBounds = vl_malloc(sizeof(double) * 2 * self->dimension) ;
      double * iter = searchBounds  ;
      double * end = iter + 2 * self->dimension ;
      while (iter < end) {
        *iter++ = - VL_INFINITY_F ;
        *iter++ = + VL_INFINITY_F ;
      }
      vl_kdtree_calc_bounds_recursively (self->trees[ti], 0, searchBounds) ;
      vl_free (searchBounds) ;
    }
  }

  self->searchNumComparisons = 0 ;
  self->searchNumSimplifications = 0 ;

  /* put the root node into the search heap */
  self->searchHeapNumNodes = 0 ;
  for (ti = 0 ; ti < self->numTrees ; ++ ti) {
    searchState = self->searchHeapArray + self->searchHeapNumNodes ;
    searchState -> tree = self->trees[ti] ;
    searchState -> nodeIndex = 0 ;
    searchState -> distanceLowerBound = 0 ;
    vl_kdforest_search_heap_push (self->searchHeapArray, &self->searchHeapNumNodes) ;
  }

  /* branch and bound */
  while (exactSearch || self->searchNumComparisons < self->searchMaxNumComparisons)
  {
    /* pop the next optimal search node */
    VlKDForestSearchState * searchState ;

    /* break if search space completed */
    if (self->searchHeapNumNodes == 0) {
      break ;
    }

    searchState = self->searchHeapArray +
      vl_kdforest_search_heap_pop (self->searchHeapArray, &self->searchHeapNumNodes) ;

    /* break if no better solution may exist */
    if (numAddedNeighbors == numNeighbors &&
        neighbors[0].distance < searchState->distanceLowerBound) {
      self->searchNumSimplifications ++ ;
      break ;
    }

    vl_kdforest_query_recursively (self,
                                   searchState->tree,
                                   searchState->nodeIndex,
                                   neighbors,
                                   numNeighbors,
                                   &numAddedNeighbors,
                                   searchState->distanceLowerBound,
                                   query) ;
  }

  /* sort neighbors by increasing distance */
  for (i = numAddedNeighbors ;  i < numNeighbors ; ++ i) {
    neighbors[i].index = -1 ;
    neighbors[i].distance = VL_NAN_F ;
  }
  while (numAddedNeighbors) {
    vl_kdforest_neighbor_heap_pop (neighbors, &numAddedNeighbors) ;
  }

  return self->searchNumComparisons ;
}
Esempio n. 26
0
VL_EXPORT
void
vl_mser_ell_fit (VlMserFilt* f)
{
  /* shortcuts */
  int                nel = f-> nel ;
  int                dof = f-> dof ;
  int              *dims = f-> dims ;
  int              ndims = f-> ndims ;
  int              *subs = f-> subs ;
  int             njoins = f-> njoins ;
  vl_uint         *joins = f-> joins ;
  VlMserReg           *r = f-> r ;
  vl_uint           *mer = f-> mer ;
  int               nmer = f-> nmer ;
  vl_mser_acc       *acc = f-> acc ;
  vl_mser_acc       *ell = f-> ell ;

  int d, index, i, j ;

  /* already fit ? */
  if (f->nell == f->nmer) return ;

  /* make room */
  if (f->rell < f->nmer) {
    if (f->ell) vl_free (f->ell) ;
    f->ell  = vl_malloc (sizeof(float) * f->nmer * f->dof) ;
    f->rell = f-> nmer ;
  }

  if (f->acc == 0) {
    f->acc = vl_malloc (sizeof(float) * f->nel) ;
  }

  acc = f-> acc ;
  ell = f-> ell ;

  /* -----------------------------------------------------------------
   *                                                 Integrate moments
   * -------------------------------------------------------------- */

  /* for each dof */
  for(d = 0 ; d < f->dof ; ++d) {

    /* start from the upper-left pixel (0,0,...,0) */
    memset (subs, 0, sizeof(int) * ndims) ;

    /* step 1: fill acc pretending that each region has only one pixel */
    if(d < ndims) {
      /* 1-order ................................................... */

      for(index = 0 ; index < nel ; ++ index) {
        acc [index] = subs [d] ;
        adv(ndims, dims, subs) ;
      }
    }
    else {
      /* 2-order ................................................... */

      /* map the dof d to a second order moment E[x_i x_j] */
      i = d - ndims ;
      j = 0 ;
      while(i > j) {
        i -= j + 1 ;
        j ++ ;
      }
      /* initialize acc with  x_i * x_j */
      for(index = 0 ; index < nel ; ++ index){
        acc [index] = subs [i] * subs [j] ;
        adv(ndims, dims, subs) ;
      }
    }

    /* step 2: integrate */
    for(i = 0 ; i < njoins ; ++i) {
      vl_uint index  = joins [i] ;
      vl_uint parent = r [index] .parent ;
      acc [parent] += acc [index] ;
    }

    /* step 3: save back to ellpises */
    for(i = 0 ; i < nmer ; ++i) {
      vl_uint idx = mer [i] ;
      ell [d + dof*i] = acc [idx] ;
    }

  }  /* next dof */

  /* -----------------------------------------------------------------
   *                                           Compute central moments
   * -------------------------------------------------------------- */

  for(index = 0 ; index < nmer ; ++index) {
    float  *pt  = ell + index * dof ;
    vl_uint    idx  = mer [index] ;
    float  area = r [idx] .area ;

    for(d = 0 ; d < dof ; ++d) {

      pt [d] /= area ;

      if(d >= ndims) {
        /* remove squared mean from moment to get variance */
        i = d - ndims ;
        j = 0 ;
        while(i > j) {
          i -= j + 1 ;
          j ++ ;
        }
        pt [d] -= pt [i] * pt [j] ;
      }

    }
  }

  /* save back */
  f-> nell = nmer ;
}
Esempio n. 27
0
/** -------------------------------------------------------------------
 ** @brief Process image
 **
 ** The functions calculates the Maximally Stable Extremal Regions
 ** (MSERs) of image @a im using the MSER filter @a f.
 **
 ** The filter @a f must have been initialized to be compatible with
 ** the dimensions of @a im.
 **
 ** @param f MSER filter.
 ** @param im image data.
 **/
VL_EXPORT
void
vl_mser_process (VlMserFilt* f, vl_mser_pix const* im)
{
  /* shortcuts */
  vl_uint        nel     = f-> nel  ;
  vl_uint       *perm    = f-> perm ;
  vl_uint       *joins   = f-> joins ;
  int            ndims   = f-> ndims ;
  int           *dims    = f-> dims ;
  int           *subs    = f-> subs ;
  int           *dsubs   = f-> dsubs ;
  int           *strides = f-> strides ;
  VlMserReg     *r       = f-> r ;
  VlMserExtrReg *er      = f-> er ;
  vl_uint       *mer     = f-> mer ;
  int            delta   = f-> delta ;

  int njoins = 0 ;
  int ner    = 0 ;
  int nmer   = 0 ;
  int nbig   = 0 ;
  int nsmall = 0 ;
  int nbad   = 0 ;
  int ndup   = 0 ;

  int i, j, k ;

  /* delete any previosuly computed ellipsoid */
  f-> nell = 0 ;

  /* -----------------------------------------------------------------
   *                                          Sort pixels by intensity
   * -------------------------------------------------------------- */

  {
    vl_uint buckets [ VL_MSER_PIX_MAXVAL ] ;

    /* clear buckets */
    memset (buckets, 0, sizeof(vl_uint) * VL_MSER_PIX_MAXVAL ) ;

    /* compute bucket size (how many pixels for each intensity
       value) */
    for(i = 0 ; i < (int) nel ; ++i) {
      vl_mser_pix v = im [i] ;
      ++ buckets [v] ;
    }

    /* cumulatively add bucket sizes */
    for(i = 1 ; i < VL_MSER_PIX_MAXVAL ; ++i) {
      buckets [i] += buckets [i-1] ;
    }

    /* empty buckets computing pixel ordering */
    for(i = nel ; i >= 1 ; ) {
      vl_mser_pix v = im [ --i ] ;
      vl_uint j = -- buckets [v] ;
      perm [j] = i ;
    }
  }

  /* initialize the forest with all void nodes */
  for(i = 0 ; i < (int) nel ; ++i) {
    r [i] .parent = VL_MSER_VOID_NODE ;
  }

  /* -----------------------------------------------------------------
   *                        Compute regions and count extremal regions
   * -------------------------------------------------------------- */
  /*
     In the following:

     idx    : index of the current pixel
     val    : intensity of the current pixel
     r_idx  : index of the root of the current pixel
     n_idx  : index of the neighbors of the current pixel
     nr_idx : index of the root of the neighbor of the current pixel

  */

  /* process each pixel by increasing intensity */
  for(i = 0 ; i < (int) nel ; ++i) {

    /* pop next node xi */
    vl_uint     idx = perm [i] ;
    vl_mser_pix val = im [idx] ;
    vl_uint     r_idx ;

    /* add the pixel to the forest as a root for now */
    r [idx] .parent   = idx ;
    r [idx] .shortcut = idx ;
    r [idx] .area     = 1 ;
    r [idx] .height   = 1 ;

    r_idx = idx ;

    /* convert the index IDX into the subscript SUBS; also initialize
       DSUBS to (-1,-1,...,-1) */
    {
      vl_uint temp = idx ;
      for(k = ndims - 1 ; k >= 0 ; --k) {
        dsubs [k] = -1 ;
        subs  [k] = temp / strides [k] ;
        temp      = temp % strides [k] ;
      }
    }

    /* examine the neighbors of the current pixel */
    while (1) {
      vl_uint n_idx = 0 ;
      vl_bool good = 1 ;

      /*
         Compute the neighbor subscript as NSUBS+SUB, the
         corresponding neighbor index NINDEX and check that the
         neighbor is within the image domain.
      */
      for(k = 0 ; k < ndims && good ; ++k) {
        int temp  = dsubs [k] + subs [k] ;
        good     &= (0 <= temp) && (temp < dims [k]) ;
        n_idx    += temp * strides [k] ;
      }

      /*
         The neighbor should be processed if the following conditions
         are met:

         1. The neighbor is within image boundaries.

         2. The neighbor is indeed different from the current node
            (the opposite happens when DSUB=(0,0,...,0)).

         3. The neighbor is already in the forest, meaning that it has
            already been processed.
      */
      if (good &&
          n_idx != idx &&
          r [n_idx] .parent != VL_MSER_VOID_NODE ) {

        vl_mser_pix nr_val = 0 ;
        vl_uint     nr_idx = 0 ;

         /*
          Now we join the two subtrees rooted at

           R_IDX = ROOT(  IDX)
          NR_IDX = ROOT(N_IDX).

          Note that R_IDX = ROOT(IDX) might change as we process more
          neighbors, so we need keep updating it.
        */
         r_idx = climb(r,   idx) ;
        nr_idx = climb(r, n_idx) ;

        int         hgt   = r [ r_idx] .height ;
        int         n_hgt = r [nr_idx] .height ;

       
        /*
          At this point we have three possibilities:

          (A) ROOT(IDX) == ROOT(NR_IDX). In this case the two trees
              have already been joined and we do not do anything.

          (B) I(ROOT(IDX)) == I(ROOT(NR_IDX)). In this case the pixel
              IDX is extending an extremal region with the same
              intensity value. Since ROOT(NR_IDX) will NOT be an
              extremal region of the full image, ROOT(IDX) can be
              safely added as children of ROOT(NR_IDX) if this
              reduces the height according to the union rank
              heuristic.

          (C) I(ROOT(IDX)) > I(ROOT(NR_IDX)). In this case the pixel
              IDX is starting a new extremal region. Thus ROOT(NR_IDX)
              WILL be an extremal region of the final image and the
              only possibility is to add ROOT(NR_IDX) as children of
              ROOT(IDX), which becomes parent.
        */

        if( r_idx != nr_idx ) { /* skip if (A) */

          nr_val = im [nr_idx] ;

          if( nr_val == val && hgt < n_hgt ) {

            /* ROOT(IDX) becomes the child */
            r [r_idx]  .parent   = nr_idx ;
            r [r_idx]  .shortcut = nr_idx ;
            r [nr_idx] .area    += r [r_idx] .area ;
            r [nr_idx] .height   = VL_MAX(n_hgt, hgt+1) ;

            joins [njoins++] = r_idx ;

          } else {

            /* cases ROOT(IDX) becomes the parent */
            r [nr_idx] .parent   = r_idx ;
            r [nr_idx] .shortcut = r_idx ;
            r [r_idx]  .area    += r [nr_idx] .area ;
            r [r_idx]  .height   = VL_MAX(hgt, n_hgt + 1) ;

            joins [njoins++] = nr_idx ;

            /* count if extremal */
            if (nr_val != val) ++ ner ;

          } /* check b vs c */
        } /* check a vs b or c */
      } /* neighbor done */

      /* move to next neighbor */
      k = 0 ;
      while(++ dsubs [k] > 1) {
        dsubs [k++] = -1 ;
        if(k == ndims) goto done_all_neighbors ;
      }
    } /* next neighbor */
  done_all_neighbors : ;
  } /* next pixel */

  /* the last root is extremal too */
  ++ ner ;

  /* save back */
  f-> njoins = njoins ;

  f-> stats. num_extremal = ner ;

  /* -----------------------------------------------------------------
   *                                          Extract extremal regions
   * -------------------------------------------------------------- */

  /*
     Extremal regions are extracted and stored into the array ER.  The
     structure R is also updated so that .SHORTCUT indexes the
     corresponding extremal region if any (otherwise it is set to
     VOID).
  */

  /* make room */
  if (f-> rer < ner) {
    if (er) vl_free (er) ;
    f->er  = er = vl_malloc (sizeof(VlMserExtrReg) * ner) ;
    f->rer = ner ;
  } ;

  /* save back */
  f-> nmer = ner ;

  /* count again */
  ner = 0 ;

  /* scan all regions Xi */
  for(i = 0 ; i < (int) nel ; ++i) {

    /* pop next node xi */
    vl_uint     idx = perm [i] ;

    vl_mser_pix val   = im [idx] ;
    vl_uint     p_idx = r  [idx] .parent ;
    vl_mser_pix p_val = im [p_idx] ;

    /* is extremal ? */
    vl_bool is_extr = (p_val > val) || idx == p_idx ;

    if( is_extr ) {

      /* if so, add it */
      er [ner] .index      = idx ;
      er [ner] .parent     = ner ;
      er [ner] .value      = im [idx] ;
      er [ner] .area       = r  [idx] .area ;

      /* link this region to this extremal region */
      r [idx] .shortcut = ner ;

      /* increase count */
      ++ ner ;
    } else {
      /* link this region to void */
      r [idx] .shortcut =   VL_MSER_VOID_NODE ;
    }
  }

  /* -----------------------------------------------------------------
   *                                   Link extremal regions in a tree
   * -------------------------------------------------------------- */

  for(i = 0 ; i < ner ; ++i) {

    vl_uint idx = er [i] .index ;

    do {
      idx = r[idx] .parent ;
    } while (r[idx] .shortcut == VL_MSER_VOID_NODE) ;

    er[i] .parent   = r[idx] .shortcut ;
    er[i] .shortcut = i ;
  }

  /* -----------------------------------------------------------------
   *                            Compute variability of +DELTA branches
   * -------------------------------------------------------------- */
  /* For each extremal region Xi of value VAL we look for the biggest
   * parent that has value not greater than VAL+DELTA. This is dubbed
   * `top parent'. */

  for(i = 0 ; i < ner ; ++i) {

    /* Xj is the current region the region and Xj are the parents */
    int     top_val = er [i] .value + delta ;
    int     top     = er [i] .shortcut ;

    /* examine all parents */
    while (1) {
      int next     = er [top]  .parent ;
      int next_val = er [next] .value ;

      /* Break if:
       * - there is no node above the top or
       * - the next node is above the top value.
       */
      if (next == top || next_val > top_val) break ;

      /* so next could be the top */
      top = next ;
    }

    /* calculate branch variation */
    {
      int area     = er [i  ] .area ;
      int area_top = er [top] .area ;
      er [i] .variation  = (float) (area_top - area) / area ;
      er [i] .max_stable = 1 ;
    }

    /* Optimization: since extremal regions are processed by
     * increasing intensity, all next extremal regions being processed
     * have value at least equal to the one of Xi. If any of them has
     * parent the parent of Xi (this comprises the parent itself), we
     * can safely skip most intermediate node along the branch and
     * skip directly to the top to start our search. */
    {
      int parent = er [i] .parent ;
      int curr   = er [parent] .shortcut ;
      er [parent] .shortcut =  VL_MAX (top, curr) ;
    }
  }

  /* -----------------------------------------------------------------
   *                                  Select maximally stable branches
   * -------------------------------------------------------------- */

  nmer = ner ;
  for(i = 0 ; i < ner ; ++i) {
    vl_uint    parent = er [i     ] .parent ;
    vl_mser_pix   val = er [i     ] .value ;
    float     var = er [i     ] .variation ;
    vl_mser_pix p_val = er [parent] .value ;
    float   p_var = er [parent] .variation ;
    vl_uint     loser ;

    /*
       Notice that R_parent = R_{l+1} only if p_val = val + 1. If not,
       this and the parent region coincide and there is nothing to do.
    */
    if(p_val > val + 1) continue ;

    /* decide which one to keep and put that in loser */
    if(var < p_var) loser = parent ; else loser = i ;

    /* make loser NON maximally stable */
    if(er [loser] .max_stable) {
      -- nmer ;
      er [loser] .max_stable = 0 ;
    }
  }

  f-> stats. num_unstable = ner - nmer ;

  /* -----------------------------------------------------------------
   *                                                 Further filtering
   * -------------------------------------------------------------- */
  /* It is critical for correct duplicate detection to remove regions
   * from the bottom (smallest one first).                          */
  {
    float max_area = (float) f-> max_area * nel ;
    float min_area = (float) f-> min_area * nel ;
    float max_var  = (float) f-> max_variation ;
    float min_div  = (float) f-> min_diversity ;

    /* scan all extremal regions (intensity value order) */
    for(i = ner-1 ; i >= 0L  ; --i) {

      /* process only maximally stable extremal regions */
      if (! er [i] .max_stable) continue ;

      if (er [i] .variation >= max_var ) { ++ nbad ;   goto remove ; }
      if (er [i] .area      >  max_area) { ++ nbig ;   goto remove ; }
      if (er [i] .area      <  min_area) { ++ nsmall ; goto remove ; }

      /*
       * Remove duplicates
       */
      if (min_div < 1.0) {
        vl_uint   parent = er [i] .parent ;
        int       area, p_area ;
        float div ;

        /* check all but the root mser */
        if((int) parent != i) {

          /* search for the maximally stable parent region */
          while(! er [parent] .max_stable) {
            vl_uint next = er [parent] .parent ;
            if(next == parent) break ;
            parent = next ;
          }

          /* Compare with the parent region; if the current and parent
           * regions are too similar, keep only the parent. */
          area    = er [i]      .area ;
          p_area  = er [parent] .area ;
          div     = (float) (p_area - area) / (float) p_area ;

          if (div < min_div) { ++ ndup ; goto remove ; }
        } /* remove dups end */

      }
      continue ;
    remove :
      er [i] .max_stable = 0 ;
      -- nmer ;
    } /* check next region */

    f-> stats .num_abs_unstable = nbad ;
    f-> stats .num_too_big      = nbig ;
    f-> stats .num_too_small    = nsmall ;
    f-> stats .num_duplicates   = ndup ;
  }
  /* -----------------------------------------------------------------
   *                                                   Save the result
   * -------------------------------------------------------------- */

  /* make room */
  if (f-> rmer < nmer) {
    if (mer) vl_free (mer) ;
    f->mer  = mer = vl_malloc( sizeof(vl_uint) * nmer) ;
    f->rmer = nmer ;
  }

  /* save back */
  f-> nmer = nmer ;

  j = 0 ;
  for (i = 0 ; i < ner ; ++i) {
    if (er [i] .max_stable) mer [j++] = er [i] .index ;
  }
}
Esempio n. 28
0
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  enum {IN_FOREST = 0, IN_DATA, IN_QUERY, IN_END} ;
  enum {OUT_INDEX = 0, OUT_DISTANCE} ;

  int            verbose = 0 ;
  int            opt ;
  int            next = IN_END ;
  mxArray const *optarg ;

  VlKDForest * forest ;
  mxArray const * forest_array = in[IN_FOREST] ;
  mxArray const * data_array = in[IN_DATA] ;
  mxArray const * query_array = in[IN_QUERY] ;
  mxArray * index_array ;
  mxArray * distance_array ;
  void * query ;
  vl_uint32 * index ;
  void * distance ;
  vl_size numNeighbors = 1 ;
  vl_size numQueries ;
  vl_uindex qi, ni;
  unsigned int numComparisons = 0 ;
  unsigned int maxNumComparisons = 0 ;
  VlKDForestNeighbor * neighbors ;
  mxClassID dataClass ;

  VL_USE_MATLAB_ENV ;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */

  if (nin < 3) {
    vlmxError(vlmxErrNotEnoughInputArguments, NULL) ;
  }
  if (nout > 2) {
    vlmxError(vlmxErrTooManyOutputArguments, NULL) ;
  }

  forest = new_kdforest_from_array (forest_array, data_array) ;

  dataClass = mxGetClassID (data_array) ;
  if (mxGetClassID (query_array) != dataClass) {
    vlmxError(vlmxErrInvalidArgument,
             "QUERY must have the same storage class as DATA.") ;
  }
  if (! vlmxIsReal (query_array)) {
    vlmxError(vlmxErrInvalidArgument,
             "QUERY must be real.") ;
  }
  if (! vlmxIsMatrix (query_array, forest->dimension, -1)) {
    vlmxError(vlmxErrInvalidArgument,
             "QUERY must be a matrix with TREE.NUMDIMENSIONS rows.") ;
  }

  while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) {
    switch (opt) {
      case opt_num_neighs :
        if (! vlmxIsScalar(optarg) ||
            (numNeighbors = mxGetScalar(optarg)) < 1) {
          vlmxError(vlmxErrInvalidArgument,
                   "NUMNEIGHBORS must be a scalar not smaller than one.") ;
        }
        break;

      case opt_max_num_comparisons :
        if (! vlmxIsScalar(optarg)) {
          vlmxError(vlmxErrInvalidArgument,
                   "MAXNUMCOMPARISONS must be a scalar.") ;
        }
        maxNumComparisons = mxGetScalar(optarg) ;
        break;

      case opt_verbose :
        ++ verbose ;
        break ;
    }
  }

  vl_kdforest_set_max_num_comparisons (forest, maxNumComparisons) ;

  neighbors = vl_malloc (sizeof(VlKDForestNeighbor) * numNeighbors) ;

  query = mxGetData (query_array) ;
  numQueries = mxGetN (query_array) ;

  out[OUT_INDEX] = index_array = mxCreateNumericMatrix
    (numNeighbors, numQueries, mxUINT32_CLASS, mxREAL) ;

  out[OUT_DISTANCE] = distance_array = mxCreateNumericMatrix
    (numNeighbors, numQueries, dataClass, mxREAL) ;

  index = mxGetData (index_array) ;
  distance = mxGetData (distance_array) ;

  if (verbose) {
    VL_PRINTF ("vl_kdforestquery: number of queries: %d\n", numQueries) ;
    VL_PRINTF ("vl_kdforestquery: number of neighbors per query: %d\n", numNeighbors) ;
    VL_PRINTF ("vl_kdforestquery: max num of comparisons per query: %d\n",
               vl_kdforest_get_max_num_comparisons (forest)) ;
  }

  for (qi = 0 ; qi < numQueries ; ++ qi) {
    numComparisons += vl_kdforest_query (forest, neighbors, numNeighbors,
                                         query) ;
    switch (dataClass) {
      case mxSINGLE_CLASS:
      {
        float * distance_ = (float*) distance ;
        for (ni = 0 ; ni < numNeighbors ; ++ni) {
          *index++     = neighbors[ni].index + 1 ;
          *distance_++ = neighbors[ni].distance ;
        }
        query = (float*)query + vl_kdforest_get_data_dimension (forest) ;
        distance = distance_ ;
        break ;
      }
      case mxDOUBLE_CLASS:
      {
        double * distance_ = (double*) distance ;
        for (ni = 0 ; ni < numNeighbors ; ++ni) {
          *index++     = neighbors[ni].index + 1 ;
          *distance_++ = neighbors[ni].distance ;
        }
        query = (double*)query + vl_kdforest_get_data_dimension (forest)  ;
        distance = distance_ ;
        break ;
      }
      default:
        abort() ;
    }
  }

  if (verbose) {
    VL_PRINTF ("vl_kdforestquery: number of comparisons per query: %.3f\n",
               ((double) numComparisons) / numQueries) ;
    VL_PRINTF ("vl_kdforestquery: number of comparisons per neighbor: %.3f\n",
               ((double) numComparisons) / (numQueries * numNeighbors)) ;
  }

  vl_kdforest_delete (forest) ;
  vl_free (neighbors) ;
}
Esempio n. 29
0
static void
VL_XCAT(_vl_fisher_encode_, SFX)
(TYPE * enc,
 TYPE const * means, vl_size dimension, vl_size numClusters,
 TYPE const * covariances,
 TYPE const * priors,
 TYPE const * data, vl_size numData,
 int flags)
{
  vl_size dim;
  vl_index i_cl, i_d;
  TYPE * posteriors ;
  TYPE * sqrtInvSigma;

  posteriors = vl_malloc(sizeof(TYPE) * numClusters * numData);
  sqrtInvSigma = vl_malloc(sizeof(TYPE) * dimension * numClusters);

  memset(enc, 0, sizeof(TYPE) * 2 * dimension * numClusters) ;

  for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) {
    for(dim = 0; dim < dimension; dim++) {
      sqrtInvSigma[i_cl*dimension + dim] = sqrt(1.0 / covariances[i_cl*dimension + dim]);
    }
  }

  VL_XCAT(vl_get_gmm_data_posteriors_, SFX)(posteriors, numClusters, numData,
                                            priors,
                                            means, dimension,
                                            covariances,
                                            data) ;

#if defined(_OPENMP)
#pragma omp parallel for default(shared) private(i_cl, i_d, dim) num_threads(vl_get_max_threads())
#endif
  for(i_cl = 0; i_cl < (signed)numClusters; ++ i_cl) {
    TYPE uprefix;
    TYPE vprefix;

    TYPE * uk = enc + i_cl*dimension ;
    TYPE * vk = enc + i_cl*dimension + numClusters * dimension ;

    if (priors[i_cl] < 1e-6) { continue ; }

    for(i_d = 0; i_d < (signed)numData; i_d++) {
      TYPE p = posteriors[i_cl + i_d * numClusters] ;
      if (p == 0) continue ;
      for(dim = 0; dim < dimension; dim++) {
        TYPE diff = data[i_d*dimension + dim] - means[i_cl*dimension + dim] ;
        diff *= sqrtInvSigma[i_cl*dimension + dim] ;
        *(uk + dim) += p * diff ;
        *(vk + dim) += p * (diff * diff - 1);
      }
    }

    uprefix = 1/(numData*sqrt(priors[i_cl]));
    vprefix = 1/(numData*sqrt(2*priors[i_cl]));

    for(dim = 0; dim < dimension; dim++) {
      *(uk + dim) = *(uk + dim) * uprefix;
      *(vk + dim) = *(vk + dim) * vprefix;
    }
  }

  vl_free(posteriors);
  vl_free(sqrtInvSigma) ;

  if (flags & VL_FISHER_FLAG_SQUARE_ROOT) {
    for(dim = 0; dim < 2 * dimension * numClusters ; dim++) {
      TYPE z = enc [dim] ;
      if (z >= 0) {
        enc[dim] = VL_XCAT(vl_sqrt_, SFX)(z) ;
      } else {
        enc[dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ;
      }
    }
  }

  if (flags & VL_FISHER_FLAG_NORMALIZED) {
    TYPE n = 0 ;
    for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) {
      TYPE z = enc [dim] ;
      n += z * z ;
    }
    n = VL_XCAT(vl_sqrt_, SFX)(n) ;
    n = VL_MAX(n, 1e-12) ;
    for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) {
      enc[dim] /= n ;
    }
  }
}
Esempio n. 30
0
static double
VL_XCAT(_vl_kmeans_refine_centers_elkan_, SFX)
(VlKMeans * self,
 TYPE const * data,
 vl_size numData)
{
  vl_size d, iteration, x ;
  vl_uint32 c, j ;
  vl_bool allDone ;
  TYPE * distances = vl_malloc (sizeof(TYPE) * numData) ;
  vl_uint32 * assignments = vl_malloc (sizeof(vl_uint32) * numData) ;
  vl_size * clusterMasses = vl_malloc (sizeof(vl_size) * numData) ;

#if (FLT == VL_TYPE_FLOAT)
    VlFloatVectorComparisonFunction distFn = vl_get_vector_comparison_function_f(self->distance) ;
#else
    VlDoubleVectorComparisonFunction distFn = vl_get_vector_comparison_function_d(self->distance) ;
#endif

  TYPE * nextCenterDistances = vl_malloc (sizeof(TYPE) * self->numCenters) ;
  TYPE * pointToClosestCenterUB = vl_malloc (sizeof(TYPE) * numData) ;
  vl_bool * pointToClosestCenterUBIsStrict = vl_malloc (sizeof(vl_bool) * numData) ;
  TYPE * pointToCenterLB = vl_malloc (sizeof(TYPE) * numData * self->numCenters) ;
  TYPE * newCenters = vl_malloc(sizeof(TYPE) * self->dimension * self->numCenters) ;
  TYPE * centerToNewCenterDistances = vl_malloc (sizeof(TYPE) * self->numCenters) ;

  vl_uint32 * permutations = NULL ;
  vl_size * numSeenSoFar = NULL ;

  double energy ;

  vl_size totDistanceComputationsToInit = 0 ;
  vl_size totDistanceComputationsToRefreshUB = 0 ;
  vl_size totDistanceComputationsToRefreshLB = 0 ;
  vl_size totDistanceComputationsToRefreshCenterDistances = 0 ;
  vl_size totDistanceComputationsToNewCenters = 0 ;
  vl_size totDistanceComputationsToFinalize = 0 ;

  if (self->distance == VlDistanceL1) {
    permutations = vl_malloc(sizeof(vl_uint32) * numData * self->dimension) ;
    numSeenSoFar = vl_malloc(sizeof(vl_size) * self->numCenters) ;
    VL_XCAT(_vl_kmeans_sort_data_helper_, SFX)(self, permutations, data, numData) ;
  }

  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  /*                          Initialization                        */
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

  /* An iteration is: get_new_centers + reassign + get_energy.
     This counts as iteration 0, where get_new_centers is assumed
     to be performed before calling the train function by
     the initialization function */

  /* update distances between centers */
  totDistanceComputationsToInit +=
  VL_XCAT(_vl_kmeans_update_center_distances_, SFX)(self) ;

  /* assigmen points to the initial centers and initialize bounds */
  memset(pointToCenterLB, 0, sizeof(TYPE) * self->numCenters *  numData) ;
  for (x = 0 ; x < numData ; ++x) {
    TYPE distance ;

    /* do the first center */
    assignments[x] = 0 ;
    distance = distFn(self->dimension,
                      data + x * self->dimension,
                      (TYPE*)self->centers + 0) ;
    pointToClosestCenterUB[x] = distance ;
    pointToClosestCenterUBIsStrict[x] = VL_TRUE ;
    pointToCenterLB[0 + x * self->numCenters] = distance ;
    totDistanceComputationsToInit += 1 ;

    /* do other centers */
    for (c = 1 ; c < self->numCenters ; ++c) {

      /* Can skip if the center assigned so far is twice as close
         as its distance to the center under consideration */

      if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) *
          pointToClosestCenterUB[x] <=
          ((TYPE*)self->centerDistances)
          [c + assignments[x] * self->numCenters]) {
        continue ;
      }

      distance = distFn(self->dimension,
                        data + x * self->dimension,
                        (TYPE*)self->centers + c * self->dimension) ;
      pointToCenterLB[c + x * self->numCenters] = distance ;
      totDistanceComputationsToInit += 1 ;
      if (distance < pointToClosestCenterUB[x]) {
        pointToClosestCenterUB[x] = distance ;
        assignments[x] = c ;
      }
    }
  }

  /* compute UB on energy */
  energy = 0 ;
  for (x = 0 ; x < numData ; ++x) {
    energy += pointToClosestCenterUB[x] ;
  }

  if (self->verbosity) {
    VL_PRINTF("kmeans: Elkan iter 0: energy = %g, dist. calc. = %d\n",
              energy, totDistanceComputationsToInit) ;
  }

/* #define SANITY*/
#ifdef SANITY
  {
    int xx ; int cc ;
    TYPE tol = 1e-5 ;
    VL_PRINTF("inconsistencies after initial assignments:\n");
    for (xx = 0 ; xx < numData ; ++xx) {
      for (cc = 0 ; cc < self->numCenters ; ++cc) {
        TYPE a = pointToCenterLB[cc + xx * self->numCenters] ;
        TYPE b = distFn(self->dimension,
                        data + self->dimension * xx,
                        (TYPE*)self->centers + self->dimension * cc) ;
        if (cc == assignments[xx]) {
          TYPE z = pointToClosestCenterUB[xx] ;
          if (z+tol<b) VL_PRINTF("UB %d %d = %f < %f\n",
                             cc, xx, z, b) ;
        }
        if (a>b+tol) VL_PRINTF("LB %d %d = %f  > %f\n",
                           cc, xx, a, b) ;
      }
    }
  }
#endif

  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  /*                          Iterations                            */
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

  for (iteration = 1 ; 1; ++iteration) {

    vl_size numDistanceComputationsToRefreshUB = 0 ;
    vl_size numDistanceComputationsToRefreshLB = 0 ;
    vl_size numDistanceComputationsToRefreshCenterDistances = 0 ;
    vl_size numDistanceComputationsToNewCenters = 0 ;

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    /*                         Compute new centers                  */
    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    memset(clusterMasses, 0, sizeof(vl_size) * numData) ;
    for (x = 0 ; x < numData ; ++x) {
      clusterMasses[assignments[x]] ++ ;
    }

    switch (self->distance) {
      case VlDistanceL2:
        memset(newCenters, 0, sizeof(TYPE) * self->dimension * self->numCenters) ;
        for (x = 0 ; x < numData ; ++x) {
          TYPE * cpt = newCenters + assignments[x] * self->dimension ;
          TYPE const * xpt = data + x * self->dimension ;
          for (d = 0 ; d < self->dimension ; ++d) { cpt[d] += xpt[d] ; }
        }
        for (c = 0 ; c < self->numCenters ; ++c) {
          TYPE mass = clusterMasses[c] ;
          TYPE * cpt = newCenters + c * self->dimension ;
          for (d = 0 ; d < self->dimension ; ++d) { cpt[d] /= mass ; }
        }
        break ;
      case VlDistanceL1:
        for (d = 0 ; d < self->dimension ; ++d) {
          vl_uint32 * perm = permutations + d * numData ;
          memset(numSeenSoFar, 0, sizeof(vl_size) * self->numCenters) ;
          for (x = 0; x < numData ; ++x) {
            c = assignments[perm[x]] ;
            if (2 * numSeenSoFar[c] < clusterMasses[c]) {
              newCenters [d + c * self->dimension] =
              data [d + perm[x] * self->dimension] ;
            }
            numSeenSoFar[c] ++ ;
          }
        }
        break ;
      default:
        abort();
    } /* done compute centers */

    /* compute the distance from the old centers to the new centers */
    for (c = 0 ; c < self->numCenters ; ++c) {
      TYPE distance = distFn(self->dimension,
                             newCenters + c * self->dimension,
                             (TYPE*)self->centers + c * self->dimension) ;
      centerToNewCenterDistances[c] = distance ;
      numDistanceComputationsToNewCenters += 1 ;
    }

    /* make the new centers current */
    {
      TYPE * tmp = self->centers ;
      self->centers = newCenters ;
      newCenters = tmp ;
    }

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    /*                Reassign points to a centers                  */
    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    /*
     Update distances between centers.
     */
    numDistanceComputationsToRefreshCenterDistances
    += VL_XCAT(_vl_kmeans_update_center_distances_, SFX)(self) ;

    for (c = 0 ; c < self->numCenters ; ++c) {
      nextCenterDistances[c] = (TYPE) VL_INFINITY_D ;
      for (j = 0 ; j < self->numCenters ; ++j) {
        if (j == c) continue ;
        nextCenterDistances[c] = VL_MIN(nextCenterDistances[c],
                                        ((TYPE*)self->centerDistances)
                                        [j + c * self->numCenters]) ;
      }
    }

    /*
     Update upper bounds on point-to-closest-center distances
     based on the center variation.
     */
    for (x = 0 ; x < numData ; ++x) {
      TYPE a = pointToClosestCenterUB[x] ;
      TYPE b = centerToNewCenterDistances[assignments[x]] ;
      if (self->distance == VlDistanceL1) {
        pointToClosestCenterUB[x] = a + b ;
      } else {
#if (FLT == VL_TYPE_FLOAT)
        TYPE sqrtab =  sqrtf (a * b) ;
#else
        TYPE sqrtab =  sqrt (a * b) ;
#endif
        pointToClosestCenterUB[x] = a + b + 2.0 * sqrtab ;
      }
      pointToClosestCenterUBIsStrict[x] = VL_FALSE ;
    }

    /*
     Update lower bounds on point-to-center distances
     based on the center variation.
     */
    for (x = 0 ; x < numData ; ++x) {
      for (c = 0 ; c < self->numCenters ; ++c) {
        TYPE a = pointToCenterLB[c + x * self->numCenters] ;
        TYPE b = centerToNewCenterDistances[c] ;
        if (a < b) {
          pointToCenterLB[c + x * self->numCenters] = 0 ;
        } else {
          if (self->distance == VlDistanceL1) {
             pointToCenterLB[c + x * self->numCenters]  = a - b ;
          } else {
#if (FLT == VL_TYPE_FLOAT)
            TYPE sqrtab =  sqrtf (a * b) ;
#else
            TYPE sqrtab =  sqrt (a * b) ;
#endif
             pointToCenterLB[c + x * self->numCenters]  = a + b - 2.0 * sqrtab ;
          }
        }
      }
    }

   #ifdef SANITY
    {
      int xx ; int cc ;
      TYPE tol = 1e-5 ;
      VL_PRINTF("inconsistencies before assignments:\n");
      for (xx = 0 ; xx < numData ; ++xx) {
        for (cc = 0 ; cc < self->numCenters ; ++cc) {
          TYPE a = pointToCenterLB[cc + xx * self->numCenters] ;
          TYPE b = distFn(self->dimension,
                          data + self->dimension * xx,
                          (TYPE*)self->centers + self->dimension * cc) ;
          if (cc == assignments[xx]) {
            TYPE z = pointToClosestCenterUB[xx] ;
            if (z+tol<b) VL_PRINTF("UB %d %d = %f < %f\n",
                                            cc, xx, z, b) ;
          }
          if (a>b+tol) VL_PRINTF("LB %d %d = %f  > %f (assign = %d)\n",
                                          cc, xx, a, b, assignments[xx]) ;
        }
      }
    }
#endif

    /*
     Scan the data and to the reassignments. Use the bounds to
     skip as many point-to-center distance calculations as possible.
     */
    for (allDone = VL_TRUE, x = 0 ; x < numData ; ++x) {
      /*
       A point x sticks with its current center assignmets[x]
       the UB to d(x, c[assigmnets[x]]) is not larger than half
       the distance of c[assigments[x]] to any other center c.
       */
      if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) *
          pointToClosestCenterUB[x] <= nextCenterDistances[assignments[x]]) {
        continue ;
      }

      for (c = 0 ; c < self->numCenters ; ++c) {
        vl_uint32 cx = assignments[x] ;
        TYPE distance ;

        /* The point is not reassigned to a given center c
         if either:

         0 - c is already the assigned center
         1 - The UB of d(x, c[assignments[x]]) is smaller than half
             the distance of c[assigments[x]] to c, OR
         2 - The UB of d(x, c[assignmets[x]]) is smaller than the
             LB of the distance of x to c.
         */
        if (cx == c) {
          continue ;
        }
        if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) *
            pointToClosestCenterUB[x] <= ((TYPE*)self->centerDistances)
            [c + cx * self->numCenters]) {
          continue ;
        }
        if (pointToClosestCenterUB[x] <= pointToCenterLB
            [c + x * self->numCenters]) {
          continue ;
        }

        /* If the UB is loose, try recomputing it and test again */
        if (! pointToClosestCenterUBIsStrict[x]) {
          distance = distFn(self->dimension,
                            data + self->dimension * x,
                            (TYPE*)self->centers + self->dimension * cx) ;
          pointToClosestCenterUB[x] = distance ;
          pointToClosestCenterUBIsStrict[x] = VL_TRUE ;
          pointToCenterLB[cx + x * self->numCenters] = distance ;
          numDistanceComputationsToRefreshUB += 1 ;

          if (((self->distance == VlDistanceL1) ? 2.0 : 4.0) *
              pointToClosestCenterUB[x] <= ((TYPE*)self->centerDistances)
              [c + cx * self->numCenters]) {
            continue ;
          }
          if (pointToClosestCenterUB[x] <= pointToCenterLB
              [c + x * self->numCenters]) {
            continue ;
          }
        }

        /*
         Now the UB is strict (equal to d(x, assignments[x])), but
         we still could not exclude that x should be reassigned to
         c. We therefore compute the distance, update the LB,
         and check if a reassigmnet must be made
         */
        distance = distFn(self->dimension,
                          data + x * self->dimension,
                          (TYPE*)self->centers + c *  self->dimension) ;
        numDistanceComputationsToRefreshLB += 1 ;
        pointToCenterLB[c + x * self->numCenters] = distance ;

        if (distance < pointToClosestCenterUB[x]) {
          assignments[x] = c ;
          pointToClosestCenterUB[x] = distance ;
          allDone = VL_FALSE ;
          /* the UB strict flag is already set here */
        }

      } /* assign center */
    } /* next data point */

    totDistanceComputationsToRefreshUB
    += numDistanceComputationsToRefreshUB ;

    totDistanceComputationsToRefreshLB
    += numDistanceComputationsToRefreshLB ;

    totDistanceComputationsToRefreshCenterDistances
    += numDistanceComputationsToRefreshCenterDistances ;

    totDistanceComputationsToNewCenters
    += numDistanceComputationsToNewCenters ;

#ifdef SANITY
    {
      int xx ; int cc ;
      TYPE tol = 1e-5 ;
      VL_PRINTF("inconsistencies after assignments:\n");
      for (xx = 0 ; xx < numData ; ++xx) {
        for (cc = 0 ; cc < self->numCenters ; ++cc) {
          TYPE a = pointToCenterLB[cc + xx * self->numCenters] ;
          TYPE b = distFn(self->dimension,
                          data + self->dimension * xx,
                          (TYPE*)self->centers + self->dimension * cc) ;
          if (cc == assignments[xx]) {
            TYPE z = pointToClosestCenterUB[xx] ;
            if (z+tol<b) VL_PRINTF("UB %d %d = %f < %f\n",
                               cc, xx, z, b) ;
          }
          if (a>b+tol) VL_PRINTF("LB %d %d = %f  > %f (assign = %d)\n",
                             cc, xx, a, b, assignments[xx]) ;
        }
      }
    }
#endif

    /* compute UB on energy */
    energy = 0 ;
    for (x = 0 ; x < numData ; ++x) {
      energy += pointToClosestCenterUB[x] ;
    }

    if (self->verbosity) {
      vl_size numDistanceComputations =
      numDistanceComputationsToRefreshUB +
      numDistanceComputationsToRefreshLB +
      numDistanceComputationsToRefreshCenterDistances +
      numDistanceComputationsToNewCenters ;
      VL_PRINTF("kmeans: Elkan iter %d: energy <= %g, dist. calc. = %d\n",
                iteration,
                energy,
                numDistanceComputations) ;
      if (self->verbosity > 1) {
        VL_PRINTF("kmeans: Elkan iter %d: total dist. calc. per type: "
                  "UB: %.1f%% (%d), LB: %.1f%% (%d), "
                  "intra_center: %.1f%% (%d), "
                  "new_center: %.1f%% (%d)\n",
                  iteration,
                  100.0 * numDistanceComputationsToRefreshUB / numDistanceComputations,
                  numDistanceComputationsToRefreshUB,
                  100.0 *numDistanceComputationsToRefreshLB / numDistanceComputations,
                  numDistanceComputationsToRefreshLB,
                  100.0 * numDistanceComputationsToRefreshCenterDistances / numDistanceComputations,
                  numDistanceComputationsToRefreshCenterDistances,
                  100.0 * numDistanceComputationsToNewCenters / numDistanceComputations,
                  numDistanceComputationsToNewCenters) ;
      }
    }

    /* check termination conditions */
    if (iteration >= self->maxNumIterations) {
      if (self->verbosity) {
        VL_PRINTF("kmeans: Elkan terminating because maximum number of iterations reached\n") ;
      }
      break ;
    }
    if (allDone) {
      if (self->verbosity) {
        VL_PRINTF("kmeans: Elkan terminating because the algorithm fully converged\n") ;
      }
      break ;
    }

  } /* next Elkan iteration */


  /* compute true energy */
  energy = 0 ;
  for (x = 0 ; x < numData ; ++ x) {
    vl_uindex cx = assignments [x] ;
    energy += distFn(self->dimension,
                     data + self->dimension * x,
                     (TYPE*)self->centers + self->dimension * cx) ;
    totDistanceComputationsToFinalize += 1 ;
  }

  {
    vl_size totDistanceComputations =
    totDistanceComputationsToInit +
    totDistanceComputationsToRefreshUB +
    totDistanceComputationsToRefreshLB +
    totDistanceComputationsToRefreshCenterDistances +
    totDistanceComputationsToNewCenters +
    totDistanceComputationsToFinalize ;

    double saving = (double)totDistanceComputations
    / (iteration * self->numCenters * numData) ;

    if (self->verbosity) {
      VL_PRINTF("kmeans: Elkan: total dist. calc.: %d (%.2f %% of Lloyd)\n",
                totDistanceComputations, saving * 100.0) ;
    }

    if (self->verbosity > 1) {
      VL_PRINTF("kmeans: Elkan: total dist. calc. per type: "
                "init: %.1f%% (%d), UB: %.1f%% (%d), LB: %.1f%% (%d), "
                "intra_center: %.1f%% (%d), "
                "new_center: %.1f%% (%d), "
                "finalize: %.1f%% (%d)\n",
                100.0 * totDistanceComputationsToInit / totDistanceComputations,
                totDistanceComputationsToInit,
                100.0 * totDistanceComputationsToRefreshUB / totDistanceComputations,
                totDistanceComputationsToRefreshUB,
                100.0 *totDistanceComputationsToRefreshLB / totDistanceComputations,
                totDistanceComputationsToRefreshLB,
                100.0 * totDistanceComputationsToRefreshCenterDistances / totDistanceComputations,
                totDistanceComputationsToRefreshCenterDistances,
                100.0 * totDistanceComputationsToNewCenters / totDistanceComputations,
                totDistanceComputationsToNewCenters,
                100.0 * totDistanceComputationsToFinalize / totDistanceComputations,
                totDistanceComputationsToFinalize) ;
    }
  }

  if (permutations) { vl_free(permutations) ; }
  if (numSeenSoFar) { vl_free(numSeenSoFar) ; }

  vl_free(distances) ;
  vl_free(assignments) ;
  vl_free(clusterMasses) ;

  vl_free(nextCenterDistances) ;
  vl_free(pointToClosestCenterUB) ;
  vl_free(pointToClosestCenterUBIsStrict) ;
  vl_free(pointToCenterLB) ;
  vl_free(newCenters) ;
  vl_free(centerToNewCenterDistances) ;

  return energy ;
}