00001
00008
00009
00010
00011
00012
00013
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 ;
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
00715
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
00730
00731
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) ;
00765 assert(o <= self->geom.lastOctave) ;
00766
00767
00768
00769
00770
00771
00772
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
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
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 }