scalespace.c
Go to the documentation of this file.
00001 
00008 /*
00009 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00010 All rights reserved.
00011 
00012 This file is part of the VLFeat library and is made available under
00013 the terms of the BSD license (see the COPYING file).
00014 */
00015 
00273 #include "scalespace.h"
00274 #include "mathop.h"
00275 
00276 #include <assert.h>
00277 #include <stdlib.h>
00278 #include <string.h>
00279 #include <math.h>
00280 #include <stdio.h>
00281 
00290 struct _VlScaleSpace
00291 {
00292   VlScaleSpaceGeometry geom ; 
00293   float **octaves ; 
00294 } ;
00295 
00296 /* ---------------------------------------------------------------- */
00305 VlScaleSpaceGeometry
00306 vl_scalespace_get_default_geometry (vl_size width, vl_size height)
00307 {
00308   VlScaleSpaceGeometry geom ;
00309   assert(width >= 1) ;
00310   assert(height >= 1) ;
00311   geom.width = width ;
00312   geom.height = height ;
00313   geom.firstOctave = 0 ;
00314   geom.lastOctave = VL_MAX(floor(vl_log2_d(VL_MIN(width, height))) - 3, 0) ;
00315   geom.octaveResolution= 3 ;
00316   geom.octaveFirstSubdivision = 0 ;
00317   geom.octaveLastSubdivision = geom.octaveResolution - 1 ;
00318   geom.baseScale = 1.6 * pow(2.0, 1.0 / geom.octaveResolution) ;
00319   geom.nominalScale = 0.5 ;
00320   return geom ;
00321 }
00322 
00323 #define is_valid_geometry(geom) (\
00324 geom.firstOctave <= geom.lastOctave && \
00325 geom.octaveResolution >= 1 && \
00326 geom.octaveFirstSubdivision <= geom.octaveLastSubdivision && \
00327 geom.baseScale >= 0.0 && \
00328 geom.nominalScale >= 0.0)
00329 
00336 vl_bool
00337 vl_scalespacegeometry_is_equal (VlScaleSpaceGeometry a,
00338                                 VlScaleSpaceGeometry b)
00339 {
00340   return
00341   a.width == b.width &&
00342   a.height == b.height &&
00343   a.firstOctave == b.firstOctave &&
00344   a.lastOctave == b.lastOctave &&
00345   a.octaveResolution == b.octaveResolution &&
00346   a.octaveFirstSubdivision == b.octaveLastSubdivision &&
00347   a.baseScale == b.baseScale &&
00348   a.nominalScale == b.nominalScale ;
00349 }
00350 
00356 VlScaleSpaceGeometry
00357 vl_scalespace_get_geometry (VlScaleSpace const * self)
00358 {
00359   return self->geom ;
00360 }
00361 
00368 VlScaleSpaceOctaveGeometry
00369 vl_scalespace_get_octave_geometry (VlScaleSpace const * self, vl_index o)
00370 {
00371   VlScaleSpaceOctaveGeometry ogeom ;
00372   ogeom.width = VL_SHIFT_LEFT(self->geom.width, -o) ;
00373   ogeom.height = VL_SHIFT_LEFT(self->geom.height, -o) ;
00374   ogeom.step = pow(2.0, o) ;
00375   return ogeom ;
00376 }
00377 
00389 float *
00390 vl_scalespace_get_level (VlScaleSpace *self, vl_index o, vl_index s)
00391 {
00392   VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ;
00393   float * octave ;
00394   assert(self) ;
00395   assert(o >= self->geom.firstOctave) ;
00396   assert(o <= self->geom.lastOctave) ;
00397   assert(s >= self->geom.octaveFirstSubdivision) ;
00398   assert(s <= self->geom.octaveLastSubdivision) ;
00399 
00400   octave = self->octaves[o - self->geom.firstOctave] ;
00401   return octave + ogeom.width * ogeom.height * (s - self->geom.octaveFirstSubdivision) ;
00402 }
00403 
00414 float const *
00415 vl_scalespace_get_level_const (VlScaleSpace const * self, vl_index o, vl_index s)
00416 {
00417   return vl_scalespace_get_level((VlScaleSpace*)self, o, s) ;
00418 }
00419 
00430 double
00431 vl_scalespace_get_level_sigma (VlScaleSpace const *self, vl_index o, vl_index s)
00432 {
00433   return self->geom.baseScale * pow(2.0, o + (double) s / self->geom.octaveResolution) ;
00434 }
00435 
00450 static void
00451 copy_and_upsample
00452 (float *destination,
00453  float const *source, vl_size width, vl_size height)
00454 {
00455   vl_index x, y, ox, oy ;
00456   float v00, v10, v01, v11 ;
00457 
00458   assert(destination) ;
00459   assert(source) ;
00460 
00461   for(y = 0 ; y < (signed)height ; ++y) {
00462     oy = (y < ((signed)height - 1)) * width ;
00463     v10 = source[0] ;
00464     v11 = source[oy] ;
00465     for(x = 0 ; x < (signed)width ; ++x) {
00466       ox = x < ((signed)width - 1) ;
00467       v00 = v10 ;
00468       v01 = v11 ;
00469       v10 = source[ox] ;
00470       v11 = source[ox + oy] ;
00471       destination[0] = v00 ;
00472       destination[1] = 0.5f * (v00 + v10) ;
00473       destination[2*width] = 0.5f * (v00 + v01) ;
00474       destination[2*width+1] = 0.25f * (v00 + v01 + v10 + v11) ;
00475       destination += 2 ;
00476       source ++;
00477     }
00478     destination += 2*width ;
00479   }
00480 }
00481 
00497 static void
00498 copy_and_downsample
00499 (float *destination,
00500  float const *source,
00501  vl_size width, vl_size height, vl_size numOctaves)
00502 {
00503   vl_index x, y ;
00504   vl_size step = 1 << numOctaves ; /* step = 2^numOctaves */
00505 
00506   assert(destination) ;
00507   assert(source) ;
00508 
00509   if (numOctaves == 0) {
00510     memcpy(destination, source, sizeof(float) * width * height) ;
00511   } else {
00512     for(y = 0 ; y < (signed)height ; y += step) {
00513       float const *p = source + y * width ;
00514       for(x = 0 ; x < (signed)width - ((signed)step - 1) ; x += step) {
00515         *destination++ = *p ;
00516         p += step ;
00517       }
00518     }
00519   }
00520 }
00521 
00522 /* ---------------------------------------------------------------- */
00535 VlScaleSpace *
00536 vl_scalespace_new (vl_size width, vl_size height)
00537 {
00538   VlScaleSpaceGeometry geom ;
00539   geom = vl_scalespace_get_default_geometry(width, height) ;
00540   return vl_scalespace_new_with_geometry(geom) ;
00541 }
00542 
00557 VlScaleSpace *
00558 vl_scalespace_new_with_geometry (VlScaleSpaceGeometry geom)
00559 {
00560 
00561   vl_index o ;
00562   vl_size numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ;
00563   vl_size numOctaves = geom.lastOctave - geom.firstOctave + 1 ;
00564   VlScaleSpace *self ;
00565 
00566   assert(is_valid_geometry(geom)) ;
00567   numOctaves = geom.lastOctave - geom.firstOctave + 1 ;
00568   numSublevels = geom.octaveLastSubdivision - geom.octaveFirstSubdivision + 1 ;
00569 
00570   self = vl_calloc(1, sizeof(VlScaleSpace)) ;
00571   if (self == NULL) goto err_alloc_self ;
00572   self->geom = geom ;
00573   self->octaves = vl_calloc(numOctaves, sizeof(float*)) ;
00574   if (self->octaves == NULL) goto err_alloc_octave_list ;
00575   for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
00576     VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ;
00577     vl_size octaveSize = ogeom.width * ogeom.height * numSublevels ;
00578     self->octaves[o - self->geom.firstOctave] = vl_malloc(octaveSize * sizeof(float)) ;
00579     if (self->octaves[o - self->geom.firstOctave] == NULL) goto err_alloc_octaves;
00580   }
00581   return self ;
00582 
00583 err_alloc_octaves:
00584   for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
00585     if (self->octaves[o - self->geom.firstOctave]) {
00586       vl_free(self->octaves[o - self->geom.firstOctave]) ;
00587     }
00588   }
00589 err_alloc_octave_list:
00590   vl_free(self) ;
00591 err_alloc_self:
00592   return NULL ;
00593 }
00594 
00595 /* ---------------------------------------------------------------- */
00603 VlScaleSpace *
00604 vl_scalespace_new_copy (VlScaleSpace* self)
00605 {
00606   vl_index o  ;
00607   VlScaleSpace * copy = vl_scalespace_new_shallow_copy(self) ;
00608   if (copy == NULL) return NULL ;
00609 
00610   for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
00611     VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self,o) ;
00612     vl_size numSubevels = self->geom.octaveLastSubdivision - self->geom.octaveFirstSubdivision + 1;
00613     memcpy(copy->octaves[o - self->geom.firstOctave],
00614            self->octaves[o - self->geom.firstOctave],
00615            ogeom.width * ogeom.height * numSubevels * sizeof(float)) ;
00616   }
00617   return copy ;
00618 }
00619 
00620 /* ---------------------------------------------------------------- */
00628 VlScaleSpace *
00629 vl_scalespace_new_shallow_copy (VlScaleSpace* self)
00630 {
00631   return vl_scalespace_new_with_geometry (self->geom) ;
00632 }
00633 
00634 /* ---------------------------------------------------------------- */
00640 void
00641 vl_scalespace_delete (VlScaleSpace * self)
00642 {
00643   if (self) {
00644     if (self->octaves) {
00645       vl_index o ;
00646       for (o = self->geom.firstOctave ; o <= self->geom.lastOctave ; ++o) {
00647         if (self->octaves[o - self->geom.firstOctave]) {
00648           vl_free(self->octaves[o - self->geom.firstOctave]) ;
00649         }
00650       }
00651       vl_free(self->octaves) ;
00652     }
00653     vl_free(self) ;
00654   }
00655 }
00656 
00657 /* ---------------------------------------------------------------- */
00658 
00668 void
00669 _vl_scalespace_fill_octave (VlScaleSpace *self, vl_index o)
00670 {
00671   vl_index s ;
00672   VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ;
00673 
00674   for(s = self->geom.octaveFirstSubdivision + 1 ;
00675       s <= self->geom.octaveLastSubdivision ; ++s) {
00676     double sigma = vl_scalespace_get_level_sigma(self, o, s) ;
00677     double previousSigma = vl_scalespace_get_level_sigma(self, o, s - 1) ;
00678     double deltaSigma = sqrtf(sigma*sigma - previousSigma*previousSigma) ;
00679 
00680     float* level = vl_scalespace_get_level (self, o, s) ;
00681     float* previous = vl_scalespace_get_level (self, o, s-1) ;
00682     vl_imsmooth_f (level, ogeom.width,
00683                    previous, ogeom.width, ogeom.height, ogeom.width,
00684                    deltaSigma / ogeom.step, deltaSigma / ogeom.step) ;
00685   }
00686 }
00687 
00699 static void
00700 _vl_scalespace_start_octave_from_image (VlScaleSpace *self,
00701                                         float const *image,
00702                                         vl_index o)
00703 {
00704   float *level ;
00705   double sigma, imageSigma ;
00706   vl_index op ;
00707 
00708   assert(self) ;
00709   assert(image) ;
00710   assert(o >= self->geom.firstOctave) ;
00711   assert(o <= self->geom.lastOctave) ;
00712 
00713   /*
00714    * Copy the image to self->geom.octaveFirstSubdivision of octave o, upscaling or
00715    * downscaling as needed.
00716    */
00717 
00718   level = vl_scalespace_get_level(self, VL_MAX(0, o), self->geom.octaveFirstSubdivision) ;
00719   copy_and_downsample(level, image, self->geom.width, self->geom.height, VL_MAX(0, o)) ;
00720 
00721   for (op = -1 ; op >= o ; --op) {
00722     VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, op + 1) ;
00723     float *succLevel = vl_scalespace_get_level(self, op + 1, self->geom.octaveFirstSubdivision) ;
00724     level = vl_scalespace_get_level(self, op, self->geom.octaveFirstSubdivision) ;
00725     copy_and_upsample(level, succLevel, ogeom.width, ogeom.height) ;
00726   }
00727 
00728   /*
00729    * Adjust the smoothing of the first level just initialised, accounting
00730    * for the fact that the input image is assumed to be a nominal scale
00731    * level.
00732    */
00733 
00734   sigma = vl_scalespace_get_level_sigma(self, o, self->geom.octaveFirstSubdivision) ;
00735   imageSigma = self->geom.nominalScale ;
00736 
00737   if (sigma > imageSigma) {
00738     VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ;
00739     double deltaSigma = sqrt (sigma*sigma - imageSigma*imageSigma) ;
00740     level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ;
00741     vl_imsmooth_f (level, ogeom.width,
00742                    level, ogeom.width, ogeom.height, ogeom.width,
00743                    deltaSigma / ogeom.step, deltaSigma / ogeom.step) ;
00744   }
00745 }
00746 
00755 static void
00756 _vl_scalespace_start_octave_from_previous_octave (VlScaleSpace *self, vl_index o)
00757 {
00758   double sigma, prevSigma ;
00759   float *level, *prevLevel ;
00760   vl_index prevLevelIndex ;
00761   VlScaleSpaceOctaveGeometry ogeom ;
00762 
00763   assert(self) ;
00764   assert(o > self->geom.firstOctave) ; /* must not be the first octave */
00765   assert(o <= self->geom.lastOctave) ;
00766 
00767   /*
00768    * From the previous octave pick the level which is closer to
00769    * self->geom.octaveFirstSubdivision in this octave.
00770    * The is self->geom.octaveFirstSubdivision + self->numLevels since there are
00771    * self->geom.octaveResolution levels in an octave, provided that
00772    * this value does not exceed self->geom.octaveLastSubdivision.
00773    */
00774 
00775   prevLevelIndex = VL_MIN(self->geom.octaveFirstSubdivision
00776                           + (signed)self->geom.octaveResolution,
00777                           self->geom.octaveLastSubdivision) ;
00778   prevLevel = vl_scalespace_get_level (self, o - 1, prevLevelIndex) ;
00779   level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ;
00780   ogeom = vl_scalespace_get_octave_geometry(self, o - 1) ;
00781 
00782   copy_and_downsample (level, prevLevel, ogeom.width, ogeom.height, 1) ;
00783 
00784   /*
00785    * Add remaining smoothing, if any.
00786    */
00787 
00788   sigma = vl_scalespace_get_level_sigma(self, o, self->geom.octaveFirstSubdivision) ;
00789   prevSigma = vl_scalespace_get_level_sigma(self, o - 1, prevLevelIndex) ;
00790 
00791   if (sigma > prevSigma) {
00792     VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ;
00793     double deltaSigma = sqrt (sigma*sigma - prevSigma*prevSigma) ;
00794     level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ;
00795 
00796     /* todo: this may fail due to an out-of-memory condition */
00797     vl_imsmooth_f (level, ogeom.width,
00798                    level, ogeom.width, ogeom.height, ogeom.width,
00799                    deltaSigma / ogeom.step, deltaSigma / ogeom.step) ;
00800   }
00801 }
00802 
00811 void
00812 vl_scalespace_put_image (VlScaleSpace *self, float const *image)
00813 {
00814   vl_index o ;
00815   _vl_scalespace_start_octave_from_image(self, image, self->geom.firstOctave) ;
00816   _vl_scalespace_fill_octave(self, self->geom.firstOctave) ;
00817   for (o = self->geom.firstOctave + 1 ; o <= self->geom.lastOctave ; ++o) {
00818     _vl_scalespace_start_octave_from_previous_octave(self, o) ;
00819     _vl_scalespace_fill_octave(self, o) ;
00820   }
00821 }


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