00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00945 #include "covdet.h"
00946 #include <string.h>
00947
00955 static int
00956 _vl_resize_buffer (void ** buffer, vl_size * bufferSize, vl_size targetSize) {
00957 void * newBuffer ;
00958 if (*buffer == NULL) {
00959 *buffer = vl_malloc(targetSize) ;
00960 if (*buffer) {
00961 *bufferSize = targetSize ;
00962 return VL_ERR_OK ;
00963 } else {
00964 *bufferSize = 0 ;
00965 return VL_ERR_ALLOC ;
00966 }
00967 }
00968 newBuffer = vl_realloc(*buffer, targetSize) ;
00969 if (newBuffer) {
00970 *buffer = newBuffer ;
00971 *bufferSize = targetSize ;
00972 return VL_ERR_OK ;
00973 } else {
00974 return VL_ERR_ALLOC ;
00975 }
00976 }
00977
00985 static int
00986 _vl_enlarge_buffer (void ** buffer, vl_size * bufferSize, vl_size targetSize) {
00987 if (*bufferSize >= targetSize) return VL_ERR_OK ;
00988 return _vl_resize_buffer(buffer,bufferSize,targetSize) ;
00989 }
00990
00991
00992
00993
00994
00995
00996
00997 typedef struct _VlCovDetExtremum2
00998 {
00999 vl_index xi ;
01000 vl_index yi ;
01001 float x ;
01002 float y ;
01003 float peakScore ;
01004 float edgeScore ;
01005 } VlCovDetExtremum2 ;
01006
01007 typedef struct _VlCovDetExtremum3
01008 {
01009 vl_index xi ;
01010 vl_index yi ;
01011 vl_index zi ;
01012 float x ;
01013 float y ;
01014 float z ;
01015 float peakScore ;
01016 float edgeScore ;
01017 } VlCovDetExtremum3 ;
01018
01019 VL_EXPORT vl_size
01020 vl_find_local_extrema_3 (vl_index ** extrema, vl_size * bufferSize,
01021 float const * map,
01022 vl_size width, vl_size height, vl_size depth,
01023 double threshold) ;
01024
01025 VL_EXPORT vl_size
01026 vl_find_local_extrema_2 (vl_index ** extrema, vl_size * bufferSize,
01027 float const * map,
01028 vl_size width, vl_size height,
01029 double threshold) ;
01030
01031 VL_EXPORT vl_bool
01032 vl_refine_local_extreum_3 (VlCovDetExtremum3 * refined,
01033 float const * map,
01034 vl_size width, vl_size height, vl_size depth,
01035 vl_index x, vl_index y, vl_index z) ;
01036
01037 VL_EXPORT vl_bool
01038 vl_refine_local_extreum_2 (VlCovDetExtremum2 * refined,
01039 float const * map,
01040 vl_size width, vl_size height,
01041 vl_index x, vl_index y) ;
01042
01056 vl_size
01057 vl_find_local_extrema_3 (vl_index ** extrema, vl_size * bufferSize,
01058 float const * map,
01059 vl_size width, vl_size height, vl_size depth,
01060 double threshold)
01061 {
01062 vl_index x, y, z ;
01063 vl_size const xo = 1 ;
01064 vl_size const yo = width ;
01065 vl_size const zo = width * height ;
01066 float const *pt = map + xo + yo + zo ;
01067
01068 vl_size numExtrema = 0 ;
01069 vl_size requiredSize = 0 ;
01070
01071 #define CHECK_NEIGHBORS_3(v,CMP,SGN) (\
01072 v CMP ## = SGN threshold && \
01073 v CMP *(pt + xo) && \
01074 v CMP *(pt - xo) && \
01075 v CMP *(pt + zo) && \
01076 v CMP *(pt - zo) && \
01077 v CMP *(pt + yo) && \
01078 v CMP *(pt - yo) && \
01079 \
01080 v CMP *(pt + yo + xo) && \
01081 v CMP *(pt + yo - xo) && \
01082 v CMP *(pt - yo + xo) && \
01083 v CMP *(pt - yo - xo) && \
01084 \
01085 v CMP *(pt + xo + zo) && \
01086 v CMP *(pt - xo + zo) && \
01087 v CMP *(pt + yo + zo) && \
01088 v CMP *(pt - yo + zo) && \
01089 v CMP *(pt + yo + xo + zo) && \
01090 v CMP *(pt + yo - xo + zo) && \
01091 v CMP *(pt - yo + xo + zo) && \
01092 v CMP *(pt - yo - xo + zo) && \
01093 \
01094 v CMP *(pt + xo - zo) && \
01095 v CMP *(pt - xo - zo) && \
01096 v CMP *(pt + yo - zo) && \
01097 v CMP *(pt - yo - zo) && \
01098 v CMP *(pt + yo + xo - zo) && \
01099 v CMP *(pt + yo - xo - zo) && \
01100 v CMP *(pt - yo + xo - zo) && \
01101 v CMP *(pt - yo - xo - zo) )
01102
01103 for (z = 1 ; z < (signed)depth - 1 ; ++z) {
01104 for (y = 1 ; y < (signed)height - 1 ; ++y) {
01105 for (x = 1 ; x < (signed)width - 1 ; ++x) {
01106 float value = *pt ;
01107 if (CHECK_NEIGHBORS_3(value,>,+) || CHECK_NEIGHBORS_3(value,<,-)) {
01108 numExtrema ++ ;
01109 requiredSize += sizeof(vl_index) * 3 ;
01110 if (*bufferSize < requiredSize) {
01111 int err = _vl_resize_buffer((void**)extrema, bufferSize,
01112 requiredSize + 2000 * 3 * sizeof(vl_index)) ;
01113 if (err != VL_ERR_OK) abort() ;
01114 }
01115 (*extrema) [3 * (numExtrema - 1) + 0] = x ;
01116 (*extrema) [3 * (numExtrema - 1) + 1] = y ;
01117 (*extrema) [3 * (numExtrema - 1) + 2] = z ;
01118 }
01119 pt += xo ;
01120 }
01121 pt += 2*xo ;
01122 }
01123 pt += 2*yo ;
01124 }
01125 return numExtrema ;
01126 }
01127
01146 vl_size
01147 vl_find_local_extrema_2 (vl_index ** extrema, vl_size * bufferSize,
01148 float const* map,
01149 vl_size width, vl_size height,
01150 double threshold)
01151 {
01152 vl_index x, y ;
01153 vl_size const xo = 1 ;
01154 vl_size const yo = width ;
01155 float const *pt = map + xo + yo ;
01156
01157 vl_size numExtrema = 0 ;
01158 vl_size requiredSize = 0 ;
01159 #define CHECK_NEIGHBORS_2(v,CMP,SGN) (\
01160 v CMP ## = SGN threshold && \
01161 v CMP *(pt + xo) && \
01162 v CMP *(pt - xo) && \
01163 v CMP *(pt + yo) && \
01164 v CMP *(pt - yo) && \
01165 \
01166 v CMP *(pt + yo + xo) && \
01167 v CMP *(pt + yo - xo) && \
01168 v CMP *(pt - yo + xo) && \
01169 v CMP *(pt - yo - xo) )
01170
01171 for (y = 1 ; y < (signed)height - 1 ; ++y) {
01172 for (x = 1 ; x < (signed)width - 1 ; ++x) {
01173 float value = *pt ;
01174 if (CHECK_NEIGHBORS_2(value,>,+) || CHECK_NEIGHBORS_2(value,<,-)) {
01175 numExtrema ++ ;
01176 requiredSize += sizeof(vl_index) * 2 ;
01177 if (*bufferSize < requiredSize) {
01178 int err = _vl_resize_buffer((void**)extrema, bufferSize,
01179 requiredSize + 2000 * 2 * sizeof(vl_index)) ;
01180 if (err != VL_ERR_OK) abort() ;
01181 }
01182 (*extrema) [2 * (numExtrema - 1) + 0] = x ;
01183 (*extrema) [2 * (numExtrema - 1) + 1] = y ;
01184 }
01185 pt += xo ;
01186 }
01187 pt += 2*xo ;
01188 }
01189 return numExtrema ;
01190 }
01191
01205 VL_EXPORT vl_bool
01206 vl_refine_local_extreum_3 (VlCovDetExtremum3 * refined,
01207 float const * map,
01208 vl_size width, vl_size height, vl_size depth,
01209 vl_index x, vl_index y, vl_index z)
01210 {
01211 vl_size const xo = 1 ;
01212 vl_size const yo = width ;
01213 vl_size const zo = width * height ;
01214
01215 double Dx=0,Dy=0,Dz=0,Dxx=0,Dyy=0,Dzz=0,Dxy=0,Dxz=0,Dyz=0 ;
01216 double A [3*3], b [3] ;
01217
01218 #define at(dx,dy,dz) (*(pt + (dx)*xo + (dy)*yo + (dz)*zo))
01219 #define Aat(i,j) (A[(i)+(j)*3])
01220
01221 float const * pt ;
01222 vl_index dx = 0 ;
01223 vl_index dy = 0 ;
01224
01225 vl_index iter ;
01226 int err ;
01227
01228 assert (map) ;
01229 assert (1 <= x && x <= (signed)width - 2) ;
01230 assert (1 <= y && y <= (signed)height - 2) ;
01231 assert (1 <= z && z <= (signed)depth - 2) ;
01232
01233 for (iter = 0 ; iter < 5 ; ++iter) {
01234 x += dx ;
01235 y += dy ;
01236 pt = map + x*xo + y*yo + z*zo ;
01237
01238
01239 Dx = 0.5 * (at(+1,0,0) - at(-1,0,0)) ;
01240 Dy = 0.5 * (at(0,+1,0) - at(0,-1,0));
01241 Dz = 0.5 * (at(0,0,+1) - at(0,0,-1)) ;
01242
01243
01244 Dxx = (at(+1,0,0) + at(-1,0,0) - 2.0 * at(0,0,0)) ;
01245 Dyy = (at(0,+1,0) + at(0,-1,0) - 2.0 * at(0,0,0)) ;
01246 Dzz = (at(0,0,+1) + at(0,0,-1) - 2.0 * at(0,0,0)) ;
01247
01248 Dxy = 0.25 * (at(+1,+1,0) + at(-1,-1,0) - at(-1,+1,0) - at(+1,-1,0)) ;
01249 Dxz = 0.25 * (at(+1,0,+1) + at(-1,0,-1) - at(-1,0,+1) - at(+1,0,-1)) ;
01250 Dyz = 0.25 * (at(0,+1,+1) + at(0,-1,-1) - at(0,-1,+1) - at(0,+1,-1)) ;
01251
01252
01253 Aat(0,0) = Dxx ;
01254 Aat(1,1) = Dyy ;
01255 Aat(2,2) = Dzz ;
01256 Aat(0,1) = Aat(1,0) = Dxy ;
01257 Aat(0,2) = Aat(2,0) = Dxz ;
01258 Aat(1,2) = Aat(2,1) = Dyz ;
01259
01260 b[0] = - Dx ;
01261 b[1] = - Dy ;
01262 b[2] = - Dz ;
01263
01264 err = vl_solve_linear_system_3(b, A, b) ;
01265
01266 if (err != VL_ERR_OK) {
01267 b[0] = 0 ;
01268 b[1] = 0 ;
01269 b[2] = 0 ;
01270 break ;
01271 }
01272
01273
01274
01275 dx = (b[0] > 0.6 && x < (signed)width - 2 ? 1 : 0)
01276 + (b[0] < -0.6 && x > 1 ? -1 : 0) ;
01277
01278 dy = (b[1] > 0.6 && y < (signed)height - 2 ? 1 : 0)
01279 + (b[1] < -0.6 && y > 1 ? -1 : 0) ;
01280
01281 if (dx == 0 && dy == 0) break ;
01282 }
01283
01284
01285 {
01286 double peakScore = at(0,0,0)
01287 + 0.5 * (Dx * b[0] + Dy * b[1] + Dz * b[2]) ;
01288 double alpha = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ;
01289 double edgeScore ;
01290
01291 if (alpha < 0) {
01292
01293 edgeScore = VL_INFINITY_D ;
01294 } else {
01295 edgeScore = (0.5*alpha - 1) + sqrt(VL_MAX(0.25*alpha - 1,0)*alpha) ;
01296 }
01297
01298 refined->xi = x ;
01299 refined->yi = y ;
01300 refined->zi = z ;
01301 refined->x = x + b[0] ;
01302 refined->y = y + b[1] ;
01303 refined->z = z + b[2] ;
01304 refined->peakScore = peakScore ;
01305 refined->edgeScore = edgeScore ;
01306
01307 return
01308 err == VL_ERR_OK &&
01309 vl_abs_d(b[0]) < 1.5 &&
01310 vl_abs_d(b[1]) < 1.5 &&
01311 vl_abs_d(b[2]) < 1.5 &&
01312 0 <= refined->x && refined->x <= (signed)width - 1 &&
01313 0 <= refined->y && refined->y <= (signed)height - 1 &&
01314 0 <= refined->z && refined->z <= (signed)depth - 1 ;
01315 }
01316 #undef Aat
01317 #undef at
01318 }
01319
01331 VL_EXPORT vl_bool
01332 vl_refine_local_extreum_2 (VlCovDetExtremum2 * refined,
01333 float const * map,
01334 vl_size width, vl_size height,
01335 vl_index x, vl_index y)
01336 {
01337 vl_size const xo = 1 ;
01338 vl_size const yo = width ;
01339
01340 double Dx=0,Dy=0,Dxx=0,Dyy=0,Dxy=0;
01341 double A [2*2], b [2] ;
01342
01343 #define at(dx,dy) (*(pt + (dx)*xo + (dy)*yo ))
01344 #define Aat(i,j) (A[(i)+(j)*2])
01345
01346 float const * pt ;
01347 vl_index dx = 0 ;
01348 vl_index dy = 0 ;
01349 vl_index iter ;
01350 int err ;
01351
01352 assert (map) ;
01353 assert (1 <= x && x <= (signed)width - 2) ;
01354 assert (1 <= y && y <= (signed)height - 2) ;
01355
01356 for (iter = 0 ; iter < 5 ; ++iter) {
01357 x += dx ;
01358 y += dy ;
01359 pt = map + x*xo + y*yo ;
01360
01361
01362 Dx = 0.5 * (at(+1,0) - at(-1,0)) ;
01363 Dy = 0.5 * (at(0,+1) - at(0,-1));
01364
01365
01366 Dxx = (at(+1,0) + at(-1,0) - 2.0 * at(0,0)) ;
01367 Dyy = (at(0,+1) + at(0,-1) - 2.0 * at(0,0)) ;
01368 Dxy = 0.25 * (at(+1,+1) + at(-1,-1) - at(-1,+1) - at(+1,-1)) ;
01369
01370
01371 Aat(0,0) = Dxx ;
01372 Aat(1,1) = Dyy ;
01373 Aat(0,1) = Aat(1,0) = Dxy ;
01374
01375 b[0] = - Dx ;
01376 b[1] = - Dy ;
01377
01378 err = vl_solve_linear_system_2(b, A, b) ;
01379
01380 if (err != VL_ERR_OK) {
01381 b[0] = 0 ;
01382 b[1] = 0 ;
01383 break ;
01384 }
01385
01386
01387
01388 dx = (b[0] > 0.6 && x < (signed)width - 2 ? 1 : 0)
01389 + (b[0] < -0.6 && x > 1 ? -1 : 0) ;
01390
01391 dy = (b[1] > 0.6 && y < (signed)height - 2 ? 1 : 0)
01392 + (b[1] < -0.6 && y > 1 ? -1 : 0) ;
01393
01394 if (dx == 0 && dy == 0) break ;
01395 }
01396
01397
01398 {
01399 double peakScore = at(0,0) + 0.5 * (Dx * b[0] + Dy * b[1]) ;
01400 double alpha = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ;
01401 double edgeScore ;
01402
01403 if (alpha < 0) {
01404
01405 edgeScore = VL_INFINITY_D ;
01406 } else {
01407 edgeScore = (0.5*alpha - 1) + sqrt(VL_MAX(0.25*alpha - 1,0)*alpha) ;
01408 }
01409
01410 refined->xi = x ;
01411 refined->yi = y ;
01412 refined->x = x + b[0] ;
01413 refined->y = y + b[1] ;
01414 refined->peakScore = peakScore ;
01415 refined->edgeScore = edgeScore ;
01416
01417 return
01418 err == VL_ERR_OK &&
01419 vl_abs_d(b[0]) < 1.5 &&
01420 vl_abs_d(b[1]) < 1.5 &&
01421 0 <= refined->x && refined->x <= (signed)width - 1 &&
01422 0 <= refined->y && refined->y <= (signed)height - 1 ;
01423 }
01424 #undef Aat
01425 #undef at
01426 }
01427
01428
01429
01430
01431
01432 #define VL_COVDET_MAX_NUM_ORIENTATIONS 4
01433 #define VL_COVDET_MAX_NUM_LAPLACIAN_SCALES 4
01434 #define VL_COVDET_AA_PATCH_RESOLUTION 20
01435 #define VL_COVDET_AA_MAX_NUM_ITERATIONS 15
01436 #define VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS 36
01437 #define VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA 3
01438 #define VL_COVDET_AA_RELATIVE_DERIVATIVE_SIGMA 1
01439 #define VL_COVDET_AA_MAX_ANISOTROPY 5
01440 #define VL_COVDET_AA_CONVERGENCE_THRESHOLD 1.001
01441 #define VL_COVDET_AA_ACCURATE_SMOOTHING VL_FALSE
01442 #define VL_COVDET_AA_PATCH_EXTENT (3*VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA)
01443 #define VL_COVDET_OR_ADDITIONAL_PEAKS_RELATIVE_SIZE 0.8
01444 #define VL_COVDET_LAP_NUM_LEVELS 10
01445 #define VL_COVDET_LAP_PATCH_RESOLUTION 16
01446 #define VL_COVDET_LAP_DEF_PEAK_THRESHOLD 0.01
01447 #define VL_COVDET_DOG_DEF_PEAK_THRESHOLD VL_COVDET_LAP_DEF_PEAK_THRESHOLD
01448 #define VL_COVDET_DOG_DEF_EDGE_THRESHOLD 10.0
01449 #define VL_COVDET_HARRIS_DEF_PEAK_THRESHOLD 0.000002
01450 #define VL_COVDET_HARRIS_DEF_EDGE_THRESHOLD 10.0
01451 #define VL_COVDET_HESSIAN_DEF_PEAK_THRESHOLD 0.003
01452 #define VL_COVDET_HESSIAN_DEF_EDGE_THRESHOLD 10.0
01453
01455 struct _VlCovDet
01456 {
01457 VlScaleSpace *gss ;
01458 VlScaleSpace *css ;
01459 VlCovDetMethod method ;
01460 double peakThreshold ;
01461 double edgeThreshold ;
01462 double lapPeakThreshold;
01463 vl_size octaveResolution ;
01464 vl_index firstOctave ;
01466 double nonExtremaSuppression ;
01467 vl_size numNonExtremaSuppressed ;
01468
01469 VlCovDetFeature *features ;
01470 vl_size numFeatures ;
01471 vl_size numFeatureBufferSize ;
01472
01473 float * patch ;
01474 vl_size patchBufferSize ;
01475
01476 vl_bool transposed ;
01477 VlCovDetFeatureOrientation orientations [VL_COVDET_MAX_NUM_ORIENTATIONS] ;
01478 VlCovDetFeatureLaplacianScale scales [VL_COVDET_MAX_NUM_LAPLACIAN_SCALES] ;
01479
01480 vl_bool aaAccurateSmoothing ;
01481 float aaPatch [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ;
01482 float aaPatchX [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ;
01483 float aaPatchY [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ;
01484 float aaMask [(2*VL_COVDET_AA_PATCH_RESOLUTION+1)*(2*VL_COVDET_AA_PATCH_RESOLUTION+1)] ;
01485
01486 float lapPatch [(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)] ;
01487 float laplacians [(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*(2*VL_COVDET_LAP_PATCH_RESOLUTION+1)*VL_COVDET_LAP_NUM_LEVELS] ;
01488 vl_size numFeaturesWithNumScales [VL_COVDET_MAX_NUM_LAPLACIAN_SCALES + 1] ;
01489 } ;
01490
01491 VlEnumerator vlCovdetMethods [VL_COVDET_METHOD_NUM] = {
01492 {"DoG" , (vl_index)VL_COVDET_METHOD_DOG },
01493 {"Hessian", (vl_index)VL_COVDET_METHOD_HESSIAN },
01494 {"HessianLaplace", (vl_index)VL_COVDET_METHOD_HESSIAN_LAPLACE },
01495 {"HarrisLaplace", (vl_index)VL_COVDET_METHOD_HARRIS_LAPLACE },
01496 {"MultiscaleHessian", (vl_index)VL_COVDET_METHOD_MULTISCALE_HESSIAN},
01497 {"MultiscaleHarris", (vl_index)VL_COVDET_METHOD_MULTISCALE_HARRIS },
01498 {0, 0 }
01499 } ;
01500
01506 VlCovDet *
01507 vl_covdet_new (VlCovDetMethod method)
01508 {
01509 VlCovDet * self = vl_calloc(sizeof(VlCovDet),1) ;
01510 self->method = method ;
01511 self->octaveResolution = 3 ;
01512 self->firstOctave = -1 ;
01513 switch (self->method) {
01514 case VL_COVDET_METHOD_DOG :
01515 self->peakThreshold = VL_COVDET_DOG_DEF_PEAK_THRESHOLD ;
01516 self->edgeThreshold = VL_COVDET_DOG_DEF_EDGE_THRESHOLD ;
01517 self->lapPeakThreshold = 0 ;
01518 break ;
01519 case VL_COVDET_METHOD_HARRIS_LAPLACE:
01520 case VL_COVDET_METHOD_MULTISCALE_HARRIS:
01521 self->peakThreshold = VL_COVDET_HARRIS_DEF_PEAK_THRESHOLD ;
01522 self->edgeThreshold = VL_COVDET_HARRIS_DEF_EDGE_THRESHOLD ;
01523 self->lapPeakThreshold = VL_COVDET_LAP_DEF_PEAK_THRESHOLD ;
01524 break ;
01525 case VL_COVDET_METHOD_HESSIAN :
01526 case VL_COVDET_METHOD_HESSIAN_LAPLACE:
01527 case VL_COVDET_METHOD_MULTISCALE_HESSIAN:
01528 self->peakThreshold = VL_COVDET_HESSIAN_DEF_PEAK_THRESHOLD ;
01529 self->edgeThreshold = VL_COVDET_HESSIAN_DEF_EDGE_THRESHOLD ;
01530 self->lapPeakThreshold = VL_COVDET_LAP_DEF_PEAK_THRESHOLD ;
01531 break;
01532 default:
01533 assert(0) ;
01534 }
01535
01536 self->nonExtremaSuppression = 0.5 ;
01537 self->features = NULL ;
01538 self->numFeatures = 0 ;
01539 self->numFeatureBufferSize = 0 ;
01540 self->patch = NULL ;
01541 self->patchBufferSize = 0 ;
01542 self->transposed = VL_FALSE ;
01543 self->aaAccurateSmoothing = VL_COVDET_AA_ACCURATE_SMOOTHING ;
01544
01545 {
01546 vl_index const w = VL_COVDET_AA_PATCH_RESOLUTION ;
01547 vl_index i,j ;
01548 double step = (2.0 * VL_COVDET_AA_PATCH_EXTENT) / (2*w+1) ;
01549 double sigma = VL_COVDET_AA_RELATIVE_INTEGRATION_SIGMA ;
01550 for (j = -w ; j <= w ; ++j) {
01551 for (i = -w ; i <= w ; ++i) {
01552 double dx = i*step/sigma ;
01553 double dy = j*step/sigma ;
01554 self->aaMask[(i+w) + (2*w+1)*(j+w)] = exp(-0.5*(dx*dx+dy*dy)) ;
01555 }
01556 }
01557 }
01558
01559 {
01560
01561
01562
01563
01564 vl_index s ;
01565 for (s = 0 ; s < VL_COVDET_LAP_NUM_LEVELS ; ++s) {
01566 double sigmaLap = pow(2.0, -0.5 +
01567 (double)s / (VL_COVDET_LAP_NUM_LEVELS - 1)) ;
01568 double const sigmaImage = 1.0 / sqrt(2.0) ;
01569 double const step = 0.5 * sigmaImage ;
01570 double const sigmaDelta = sqrt(sigmaLap*sigmaLap - sigmaImage*sigmaImage) ;
01571 vl_size const w = VL_COVDET_LAP_PATCH_RESOLUTION ;
01572 vl_size const num = 2 * w + 1 ;
01573 float * pt = self->laplacians + s * (num * num) ;
01574
01575 memset(pt, 0, num * num * sizeof(float)) ;
01576
01577 #define at(x,y) pt[(x+w)+(y+w)*(2*w+1)]
01578 at(0,0) = - 4.0 ;
01579 at(-1,0) = 1.0 ;
01580 at(+1,0) = 1.0 ;
01581 at(0,1) = 1.0 ;
01582 at(0,-1) = 1.0 ;
01583 #undef at
01584
01585 vl_imsmooth_f(pt, num,
01586 pt, num, num, num,
01587 sigmaDelta / step, sigmaDelta / step) ;
01588
01589 #if 0
01590 {
01591 char name [200] ;
01592 snprintf(name, 200, "/tmp/%f-lap.pgm", sigmaDelta) ;
01593 vl_pgm_write_f(name, pt, num, num) ;
01594 }
01595 #endif
01596
01597 }
01598 }
01599 return self ;
01600 }
01601
01609 void
01610 vl_covdet_reset (VlCovDet * self)
01611 {
01612 if (self->features) {
01613 vl_free(self->features) ;
01614 self->features = NULL ;
01615 }
01616 if (self->css) {
01617 vl_scalespace_delete(self->css) ;
01618 self->css = NULL ;
01619 }
01620 if (self->gss) {
01621 vl_scalespace_delete(self->gss) ;
01622 self->gss = NULL ;
01623 }
01624 }
01625
01630 void
01631 vl_covdet_delete (VlCovDet * self)
01632 {
01633 vl_covdet_reset(self) ;
01634 if (self->patch) vl_free (self->patch) ;
01635 vl_free(self) ;
01636 }
01637
01647 int
01648 vl_covdet_append_feature (VlCovDet * self, VlCovDetFeature const * feature)
01649 {
01650 vl_size requiredSize ;
01651 assert(self) ;
01652 assert(feature) ;
01653 self->numFeatures ++ ;
01654 requiredSize = self->numFeatures * sizeof(VlCovDetFeature) ;
01655 if (requiredSize > self->numFeatureBufferSize) {
01656 int err = _vl_resize_buffer((void**)&self->features, &self->numFeatureBufferSize,
01657 (self->numFeatures + 1000) * sizeof(VlCovDetFeature)) ;
01658 if (err) {
01659 self->numFeatures -- ;
01660 return err ;
01661 }
01662 }
01663 self->features[self->numFeatures - 1] = *feature ;
01664 return VL_ERR_OK ;
01665 }
01666
01667
01668
01669
01670
01682 int
01683 vl_covdet_put_image (VlCovDet * self,
01684 float const * image,
01685 vl_size width, vl_size height)
01686 {
01687 vl_size const minOctaveSize = 16 ;
01688 vl_index lastOctave ;
01689 vl_index octaveFirstSubdivision ;
01690 vl_index octaveLastSubdivision ;
01691 VlScaleSpaceGeometry geom = vl_scalespace_get_default_geometry(width,height) ;
01692
01693 assert (self) ;
01694 assert (image) ;
01695 assert (width >= 1) ;
01696 assert (height >= 1) ;
01697
01698
01699 lastOctave = vl_floor_d(vl_log2_d(VL_MIN((double)width-1,(double)height-1) / (minOctaveSize - 1))) ;
01700
01701 if (self->method == VL_COVDET_METHOD_DOG) {
01702 octaveFirstSubdivision = -1 ;
01703 octaveLastSubdivision = self->octaveResolution + 1 ;
01704 } else if (self->method == VL_COVDET_METHOD_HESSIAN) {
01705 octaveFirstSubdivision = -1 ;
01706 octaveLastSubdivision = self->octaveResolution ;
01707 } else {
01708 octaveFirstSubdivision = 0 ;
01709 octaveLastSubdivision = self->octaveResolution - 1 ;
01710 }
01711
01712 geom.width = width ;
01713 geom.height = height ;
01714 geom.firstOctave = self->firstOctave ;
01715 geom.lastOctave = lastOctave ;
01716 geom.octaveResolution = self->octaveResolution ;
01717 geom.octaveFirstSubdivision = octaveFirstSubdivision ;
01718 geom.octaveLastSubdivision = octaveLastSubdivision ;
01719
01720 if (self->gss == NULL ||
01721 ! vl_scalespacegeometry_is_equal (geom,
01722 vl_scalespace_get_geometry(self->gss)))
01723 {
01724 if (self->gss) vl_scalespace_delete(self->gss) ;
01725 self->gss = vl_scalespace_new_with_geometry(geom) ;
01726 if (self->gss == NULL) return VL_ERR_ALLOC ;
01727 }
01728 vl_scalespace_put_image(self->gss, image) ;
01729 return VL_ERR_OK ;
01730 }
01731
01732
01733
01734
01735
01745 static void
01746 _vl_det_hessian_response (float * hessian,
01747 float const * image,
01748 vl_size width, vl_size height,
01749 double step, double sigma)
01750 {
01751 float factor = (float) pow(sigma/step, 4.0) ;
01752 vl_index const xo = 1 ;
01753 vl_index const yo = width;
01754 vl_size r, c;
01755
01756 float p11, p12, p13, p21, p22, p23, p31, p32, p33;
01757
01758
01759 float const *in = image + yo ;
01760
01761
01762 float *out = hessian + xo + yo;
01763
01764
01765 for (r = 1; r < height - 1; ++r)
01766 {
01767
01768 p11 = in[-yo]; p12 = in[xo - yo];
01769 p21 = in[ 0]; p22 = in[xo ];
01770 p31 = in[+yo]; p32 = in[xo + yo];
01771
01772 in += 2;
01773 for (c = 1; c < width - 1; ++c)
01774 {
01775 float Lxx, Lyy, Lxy;
01776
01777 p13 = in[-yo]; p23 = *in; p33 = in[+yo];
01778
01779
01780 Lxx = (-p21 + 2*p22 - p23);
01781 Lyy = (-p12 + 2*p22 - p32);
01782 Lxy = ((p11 - p31 - p13 + p33)/4.0f);
01783
01784
01785 *out = (Lxx * Lyy - Lxy * Lxy) * factor ;
01786
01787
01788 p11=p12; p12=p13;
01789 p21=p22; p22=p23;
01790 p31=p32; p32=p33;
01791
01792
01793 in++; out++;
01794 }
01795 out += 2;
01796 }
01797
01798
01799 in = hessian + yo + xo ;
01800 out = hessian + xo ;
01801
01802
01803 memcpy(out, in, (width - 2)*sizeof(float));
01804 out--;
01805 in -= yo;
01806
01807
01808 for (r = 0; r < height - 1; r++){
01809 *out = *in;
01810 *(out + yo - 1) = *(in + yo - 3);
01811 in += yo;
01812 out += yo;
01813 }
01814
01815
01816 in -= yo;
01817 *out = *in;
01818 *(out + yo - 1) = *(in + yo - 3);
01819
01820
01821 out++;
01822 memcpy(out, in, (width - 2)*sizeof(float));
01823 }
01824
01836 static void
01837 _vl_harris_response (float * harris,
01838 float const * image,
01839 vl_size width, vl_size height,
01840 double step, double sigma,
01841 double sigmaI, double alpha)
01842 {
01843 float factor = (float) pow(sigma/step, 4.0) ;
01844 vl_index k ;
01845
01846 float * LxLx ;
01847 float * LyLy ;
01848 float * LxLy ;
01849
01850 LxLx = vl_malloc(sizeof(float) * width * height) ;
01851 LyLy = vl_malloc(sizeof(float) * width * height) ;
01852 LxLy = vl_malloc(sizeof(float) * width * height) ;
01853
01854 vl_imgradient_f (LxLx, LyLy, 1, width, image, width, height, width) ;
01855
01856 for (k = 0 ; k < (signed)(width * height) ; ++k) {
01857 float dx = LxLx[k] ;
01858 float dy = LyLy[k] ;
01859 LxLx[k] = dx*dx ;
01860 LyLy[k] = dy*dy ;
01861 LxLy[k] = dx*dy ;
01862 }
01863
01864 vl_imsmooth_f(LxLx, width, LxLx, width, height, width,
01865 sigmaI / step, sigmaI / step) ;
01866
01867 vl_imsmooth_f(LyLy, width, LyLy, width, height, width,
01868 sigmaI / step, sigmaI / step) ;
01869
01870 vl_imsmooth_f(LxLy, width, LxLy, width, height, width,
01871 sigmaI / step, sigmaI / step) ;
01872
01873 for (k = 0 ; k < (signed)(width * height) ; ++k) {
01874 float a = LxLx[k] ;
01875 float b = LyLy[k] ;
01876 float c = LxLy[k] ;
01877
01878 float determinant = a * b - c * c ;
01879 float trace = a + b ;
01880
01881 harris[k] = factor * (determinant - alpha * (trace * trace)) ;
01882 }
01883
01884 vl_free(LxLy) ;
01885 vl_free(LyLy) ;
01886 vl_free(LxLx) ;
01887 }
01888
01897 static void
01898 _vl_dog_response (float * dog,
01899 float const * level1,
01900 float const * level2,
01901 vl_size width, vl_size height)
01902 {
01903 vl_index k ;
01904 for (k = 0 ; k < (signed)(width*height) ; ++k) {
01905 dog[k] = level2[k] - level1[k] ;
01906 }
01907 }
01908
01909
01910
01911
01912
01920 void
01921 vl_covdet_detect (VlCovDet * self)
01922 {
01923 VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ;
01924 VlScaleSpaceGeometry cgeom ;
01925 float * levelxx = NULL ;
01926 float * levelyy = NULL ;
01927 float * levelxy = NULL ;
01928 vl_index o, s ;
01929
01930 assert (self) ;
01931 assert (self->gss) ;
01932
01933
01934 self->numFeatures = 0 ;
01935
01936
01937 cgeom = geom ;
01938 if (self->method == VL_COVDET_METHOD_DOG) {
01939 cgeom.octaveLastSubdivision -= 1 ;
01940 }
01941 if (!self->css ||
01942 !vl_scalespacegeometry_is_equal(cgeom,
01943 vl_scalespace_get_geometry(self->css)))
01944 {
01945 if (self->css) vl_scalespace_delete(self->css) ;
01946 self->css = vl_scalespace_new_with_geometry(cgeom) ;
01947 }
01948 if (self->method == VL_COVDET_METHOD_HARRIS_LAPLACE ||
01949 self->method == VL_COVDET_METHOD_MULTISCALE_HARRIS) {
01950 VlScaleSpaceOctaveGeometry oct = vl_scalespace_get_octave_geometry(self->gss, geom.firstOctave) ;
01951 levelxx = vl_malloc(oct.width * oct.height * sizeof(float)) ;
01952 levelyy = vl_malloc(oct.width * oct.height * sizeof(float)) ;
01953 levelxy = vl_malloc(oct.width * oct.height * sizeof(float)) ;
01954 }
01955
01956
01957 for (o = cgeom.firstOctave ; o <= cgeom.lastOctave ; ++o) {
01958 VlScaleSpaceOctaveGeometry oct = vl_scalespace_get_octave_geometry(self->css, o) ;
01959
01960 for (s = cgeom.octaveFirstSubdivision ; s <= cgeom.octaveLastSubdivision ; ++s) {
01961 float * level = vl_scalespace_get_level(self->gss, o, s) ;
01962 float * clevel = vl_scalespace_get_level(self->css, o, s) ;
01963 double sigma = vl_scalespace_get_level_sigma(self->css, o, s) ;
01964 switch (self->method) {
01965 case VL_COVDET_METHOD_DOG:
01966 _vl_dog_response(clevel,
01967 vl_scalespace_get_level(self->gss, o, s + 1),
01968 level,
01969 oct.width, oct.height) ;
01970 break ;
01971
01972 case VL_COVDET_METHOD_HARRIS_LAPLACE:
01973 case VL_COVDET_METHOD_MULTISCALE_HARRIS:
01974 _vl_harris_response(clevel,
01975 level, oct.width, oct.height, oct.step,
01976 sigma, 1.4 * sigma, 0.05) ;
01977 break ;
01978
01979 case VL_COVDET_METHOD_HESSIAN:
01980 case VL_COVDET_METHOD_HESSIAN_LAPLACE:
01981 case VL_COVDET_METHOD_MULTISCALE_HESSIAN:
01982 _vl_det_hessian_response(clevel, level, oct.width, oct.height, oct.step, sigma) ;
01983 break ;
01984
01985 default:
01986 assert(0) ;
01987 }
01988 }
01989 }
01990
01991
01992 {
01993 vl_index * extrema = NULL ;
01994 vl_size extremaBufferSize = 0 ;
01995 vl_size numExtrema ;
01996 vl_size index ;
01997 for (o = cgeom.firstOctave ; o <= cgeom.lastOctave ; ++o) {
01998 VlScaleSpaceOctaveGeometry octgeom = vl_scalespace_get_octave_geometry(self->css, o) ;
01999 double step = octgeom.step ;
02000 vl_size width = octgeom.width ;
02001 vl_size height = octgeom.height ;
02002 vl_size depth = cgeom.octaveLastSubdivision - cgeom.octaveFirstSubdivision + 1 ;
02003
02004 switch (self->method) {
02005 case VL_COVDET_METHOD_DOG:
02006 case VL_COVDET_METHOD_HESSIAN:
02007 {
02008
02009 float const * octave =
02010 vl_scalespace_get_level(self->css, o, cgeom.octaveFirstSubdivision) ;
02011 numExtrema = vl_find_local_extrema_3(&extrema, &extremaBufferSize,
02012 octave, width, height, depth,
02013 0.8 * self->peakThreshold);
02014 for (index = 0 ; index < numExtrema ; ++index) {
02015 VlCovDetExtremum3 refined ;
02016 VlCovDetFeature feature ;
02017 vl_bool ok ;
02018 memset(&feature, 0, sizeof(feature)) ;
02019 ok = vl_refine_local_extreum_3(&refined,
02020 octave, width, height, depth,
02021 extrema[3*index+0],
02022 extrema[3*index+1],
02023 extrema[3*index+2]) ;
02024 ok &= fabs(refined.peakScore) > self->peakThreshold ;
02025 ok &= refined.edgeScore < self->edgeThreshold ;
02026 if (ok) {
02027 double sigma = cgeom.baseScale *
02028 pow(2.0, o + (refined.z + cgeom.octaveFirstSubdivision)
02029 / cgeom.octaveResolution) ;
02030 feature.frame.x = refined.x * step ;
02031 feature.frame.y = refined.y * step ;
02032 feature.frame.a11 = sigma ;
02033 feature.frame.a12 = 0.0 ;
02034 feature.frame.a21 = 0.0 ;
02035 feature.frame.a22 = sigma ;
02036 feature.peakScore = refined.peakScore ;
02037 feature.edgeScore = refined.edgeScore ;
02038 vl_covdet_append_feature(self, &feature) ;
02039 }
02040 }
02041 break ;
02042 }
02043
02044 default:
02045 {
02046 for (s = cgeom.octaveFirstSubdivision ; s < cgeom.octaveLastSubdivision ; ++s) {
02047
02048 float const * level = vl_scalespace_get_level(self->css,o,s) ;
02049 numExtrema = vl_find_local_extrema_2(&extrema, &extremaBufferSize,
02050 level,
02051 width, height,
02052 0.8 * self->peakThreshold);
02053 for (index = 0 ; index < numExtrema ; ++index) {
02054 VlCovDetExtremum2 refined ;
02055 VlCovDetFeature feature ;
02056 vl_bool ok ;
02057 memset(&feature, 0, sizeof(feature)) ;
02058 ok = vl_refine_local_extreum_2(&refined,
02059 level, width, height,
02060 extrema[2*index+0],
02061 extrema[2*index+1]);
02062 ok &= fabs(refined.peakScore) > self->peakThreshold ;
02063 ok &= refined.edgeScore < self->edgeThreshold ;
02064 if (ok) {
02065 double sigma = cgeom.baseScale *
02066 pow(2.0, o + (double)s / cgeom.octaveResolution) ;
02067 feature.frame.x = refined.x * step ;
02068 feature.frame.y = refined.y * step ;
02069 feature.frame.a11 = sigma ;
02070 feature.frame.a12 = 0.0 ;
02071 feature.frame.a21 = 0.0 ;
02072 feature.frame.a22 = sigma ;
02073 feature.peakScore = refined.peakScore ;
02074 feature.edgeScore = refined.edgeScore ;
02075 vl_covdet_append_feature(self, &feature) ;
02076 }
02077 }
02078 }
02079 break ;
02080 }
02081 }
02082 }
02083
02084 if (extrema) { vl_free(extrema) ; extrema = 0 ; }
02085 }
02086
02087
02088 switch (self->method) {
02089 case VL_COVDET_METHOD_HARRIS_LAPLACE :
02090 case VL_COVDET_METHOD_HESSIAN_LAPLACE :
02091 vl_covdet_extract_laplacian_scales (self) ;
02092 break ;
02093 default:
02094 break ;
02095 }
02096
02097 if (self->nonExtremaSuppression) {
02098 vl_index i, j ;
02099 double tol = self->nonExtremaSuppression ;
02100 self->numNonExtremaSuppressed = 0 ;
02101 for (i = 0 ; i < (signed)self->numFeatures ; ++i) {
02102 double x = self->features[i].frame.x ;
02103 double y = self->features[i].frame.y ;
02104 double sigma = self->features[i].frame.a11 ;
02105 double score = self->features[i].peakScore ;
02106
02107 for (j = 0 ; j < (signed)self->numFeatures ; ++j) {
02108 double dx_ = self->features[j].frame.x - x ;
02109 double dy_ = self->features[j].frame.y - y ;
02110 double sigma_ = self->features[j].frame.a11 ;
02111 double score_ = self->features[j].peakScore ;
02112 if (score_ == 0) continue ;
02113 if (sigma < (1+tol) * sigma_ &&
02114 sigma_ < (1+tol) * sigma &&
02115 vl_abs_d(dx_) < tol * sigma &&
02116 vl_abs_d(dy_) < tol * sigma &&
02117 vl_abs_d(score) > vl_abs_d(score_)) {
02118 self->features[j].peakScore = 0 ;
02119 self->numNonExtremaSuppressed ++ ;
02120 }
02121 }
02122 }
02123 j = 0 ;
02124 for (i = 0 ; i < (signed)self->numFeatures ; ++i) {
02125 VlCovDetFeature feature = self->features[i] ;
02126 if (self->features[i].peakScore != 0) {
02127 self->features[j++] = feature ;
02128 }
02129 }
02130 self->numFeatures = j ;
02131 }
02132
02133 if (levelxx) vl_free(levelxx) ;
02134 if (levelyy) vl_free(levelyy) ;
02135 if (levelxy) vl_free(levelxy) ;
02136 }
02137
02138
02139
02140
02141
02157 vl_bool
02158 vl_covdet_extract_patch_helper (VlCovDet * self,
02159 double * sigma1,
02160 double * sigma2,
02161 float * patch,
02162 vl_size resolution,
02163 double extent,
02164 double sigma,
02165 double A_ [4],
02166 double T_ [2],
02167 double d1, double d2)
02168 {
02169 vl_index o, s ;
02170 double factor ;
02171 double sigma_ ;
02172 float const * level ;
02173 vl_size width, height ;
02174 double step ;
02175
02176 double A [4] = {A_[0], A_[1], A_[2], A_[3]} ;
02177 double T [2] = {T_[0], T_[1]} ;
02178
02179 VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ;
02180 VlScaleSpaceOctaveGeometry oct ;
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214 factor = 1.0 / VL_MIN(d1, d2) ;
02215
02216 for (o = geom.firstOctave + 1 ; o <= geom.lastOctave ; ++o) {
02217 s = vl_floor_d(vl_log2_d(sigma / (factor * geom.baseScale)) - o) ;
02218 s = VL_MAX(s, geom.octaveFirstSubdivision) ;
02219 s = VL_MIN(s, geom.octaveLastSubdivision) ;
02220 sigma_ = geom.baseScale * pow(2.0, o + (double)s / geom.octaveResolution) ;
02221
02222 if (factor * sigma_ > sigma) {
02223 o -- ;
02224 break ;
02225 }
02226 }
02227 o = VL_MIN(o, geom.lastOctave) ;
02228 s = vl_floor_d(vl_log2_d(sigma / (factor * geom.baseScale)) - o) ;
02229 s = VL_MAX(s, geom.octaveFirstSubdivision) ;
02230 s = VL_MIN(s, geom.octaveLastSubdivision) ;
02231 sigma_ = geom.baseScale * pow(2.0, o + (double)s / geom.octaveResolution) ;
02232 if (sigma1) *sigma1 = sigma_ / d1 ;
02233 if (sigma2) *sigma2 = sigma_ / d2 ;
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245 level = vl_scalespace_get_level(self->gss, o, s) ;
02246 oct = vl_scalespace_get_octave_geometry(self->gss, o) ;
02247 width = oct.width ;
02248 height = oct.height ;
02249 step = oct.step ;
02250
02251 A[0] /= step ;
02252 A[1] /= step ;
02253 A[2] /= step ;
02254 A[3] /= step ;
02255 T[0] /= step ;
02256 T[1] /= step ;
02257
02258 {
02259
02260
02261
02262
02263
02264
02265
02266 vl_index x0i, y0i, x1i, y1i ;
02267 double x0 = +VL_INFINITY_D ;
02268 double x1 = -VL_INFINITY_D ;
02269 double y0 = +VL_INFINITY_D ;
02270 double y1 = -VL_INFINITY_D ;
02271 double boxx [4] = {extent, extent, -extent, -extent} ;
02272 double boxy [4] = {-extent, extent, extent, -extent} ;
02273 int i ;
02274 for (i = 0 ; i < 4 ; ++i) {
02275 double x = A[0] * boxx[i] + A[2] * boxy[i] + T[0] ;
02276 double y = A[1] * boxx[i] + A[3] * boxy[i] + T[1] ;
02277 x0 = VL_MIN(x0, x) ;
02278 x1 = VL_MAX(x1, x) ;
02279 y0 = VL_MIN(y0, y) ;
02280 y1 = VL_MAX(y1, y) ;
02281 }
02282
02283
02284 x0i = floor(x0) - 1 ;
02285 y0i = floor(y0) - 1 ;
02286 x1i = ceil(x1) + 1 ;
02287 y1i = ceil(y1) + 1 ;
02288
02289
02290
02291
02292
02293
02294
02295 if (x0i < 0 || x1i > (signed)width-1 ||
02296 y0i < 0 || y1i > (signed)height-1) {
02297 vl_index xi, yi ;
02298
02299
02300 vl_index padx0 = VL_MAX(0, - x0i) ;
02301 vl_index pady0 = VL_MAX(0, - y0i) ;
02302 vl_index padx1 = VL_MAX(0, x1i - ((signed)width - 1)) ;
02303 vl_index pady1 = VL_MAX(0, y1i - ((signed)height - 1)) ;
02304
02305
02306 vl_index patchWidth = x1i - x0i + 1 ;
02307 vl_index patchHeight = y1i - y0i + 1 ;
02308 vl_size patchBufferSize = patchWidth * patchHeight * sizeof(float) ;
02309 if (patchBufferSize > self->patchBufferSize) {
02310 int err = _vl_resize_buffer((void**)&self->patch, &self->patchBufferSize, patchBufferSize) ;
02311 if (err) return vl_set_last_error(VL_ERR_ALLOC, NULL) ;
02312 }
02313
02314 if (pady0 < patchHeight - pady1) {
02315
02316 for (yi = y0i + pady0 ; yi < y0i + patchHeight - pady1 ; ++ yi) {
02317 float *dst = self->patch + (yi - y0i) * patchWidth ;
02318 float const *src = level + yi * width + VL_MIN(VL_MAX(0, x0i),(signed)width-1) ;
02319 for (xi = x0i ; xi < x0i + padx0 ; ++xi) *dst++ = *src ;
02320 for ( ; xi < x0i + patchWidth - padx1 - 2 ; ++xi) *dst++ = *src++ ;
02321 for ( ; xi < x0i + patchWidth ; ++xi) *dst++ = *src ;
02322 }
02323
02324 for (yi = 0 ; yi < pady0 ; ++yi) {
02325 memcpy(self->patch + yi * patchWidth,
02326 self->patch + pady0 * patchWidth,
02327 patchWidth * sizeof(float)) ;
02328 }
02329 for (yi = patchHeight - pady1 ; yi < patchHeight ; ++yi) {
02330 memcpy(self->patch + yi * patchWidth,
02331 self->patch + (patchHeight - pady1 - 1) * patchWidth,
02332 patchWidth * sizeof(float)) ;
02333 }
02334 } else {
02335
02336 memset(self->patch, 0, self->patchBufferSize) ;
02337 }
02338 #if 0
02339 {
02340 char name [200] ;
02341 snprintf(name, 200, "/tmp/%20.0f-ext.pgm", 1e10*vl_get_cpu_time()) ;
02342 vl_pgm_write_f(name, patch, patchWidth, patchWidth) ;
02343 }
02344 #endif
02345
02346 level = self->patch ;
02347 width = patchWidth ;
02348 height = patchHeight ;
02349 T[0] -= x0i ;
02350 T[1] -= y0i ;
02351 }
02352 }
02353
02354
02355
02356
02357 {
02358 float * pt = patch ;
02359 double yhat = -extent ;
02360 vl_index xxi ;
02361 vl_index yyi ;
02362 double stephat = extent / resolution ;
02363
02364 for (yyi = 0 ; yyi < 2 * (signed)resolution + 1 ; ++yyi) {
02365 double xhat = -extent ;
02366 double rx = A[2] * yhat + T[0] ;
02367 double ry = A[3] * yhat + T[1] ;
02368 for (xxi = 0 ; xxi < 2 * (signed)resolution + 1 ; ++xxi) {
02369 double x = A[0] * xhat + rx ;
02370 double y = A[1] * xhat + ry ;
02371 vl_index xi = vl_floor_d(x) ;
02372 vl_index yi = vl_floor_d(y) ;
02373 double i00 = level[yi * width + xi] ;
02374 double i10 = level[yi * width + xi + 1] ;
02375 double i01 = level[(yi + 1) * width + xi] ;
02376 double i11 = level[(yi + 1) * width + xi + 1] ;
02377 double wx = x - xi ;
02378 double wy = y - yi ;
02379
02380 assert(xi >= 0 && xi <= (signed)width - 1) ;
02381 assert(yi >= 0 && yi <= (signed)height - 1) ;
02382
02383 *pt++ =
02384 (1.0 - wy) * ((1.0 - wx) * i00 + wx * i10) +
02385 wy * ((1.0 - wx) * i01 + wx * i11) ;
02386
02387 xhat += stephat ;
02388 }
02389 yhat += stephat ;
02390 }
02391 }
02392 #if 0
02393 {
02394 char name [200] ;
02395 snprintf(name, 200, "/tmp/%20.0f.pgm", 1e10*vl_get_cpu_time()) ;
02396 vl_pgm_write_f(name, patch, 2*resolution+1, 2*resolution+1) ;
02397 }
02398 #endif
02399 return VL_ERR_OK ;
02400 }
02401
02422 vl_bool
02423 vl_covdet_extract_patch_for_frame (VlCovDet * self,
02424 float * patch,
02425 vl_size resolution,
02426 double extent,
02427 double sigma,
02428 VlFrameOrientedEllipse frame)
02429 {
02430 double A[2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
02431 double T[2] = {frame.x, frame.y} ;
02432 double D[4], U[4], V[4] ;
02433
02434 vl_svd2(D, U, V, A) ;
02435
02436 return vl_covdet_extract_patch_helper
02437 (self, NULL, NULL, patch, resolution, extent, sigma, A, T, D[0], D[3]) ;
02438 }
02439
02440
02441
02442
02443
02454 int
02455 vl_covdet_extract_affine_shape_for_frame (VlCovDet * self,
02456 VlFrameOrientedEllipse * adapted,
02457 VlFrameOrientedEllipse frame)
02458 {
02459 vl_index iter = 0 ;
02460
02461 double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
02462 double T [2] = {frame.x, frame.y} ;
02463 double U [2*2] ;
02464 double V [2*2] ;
02465 double D [2*2] ;
02466 double M [2*2] ;
02467 double P [2*2] ;
02468 double P_ [2*2] ;
02469 double Q [2*2] ;
02470 double sigma1, sigma2 ;
02471 double sigmaD = VL_COVDET_AA_RELATIVE_DERIVATIVE_SIGMA ;
02472 double factor ;
02473 double anisotropy ;
02474 double referenceScale ;
02475 vl_size const resolution = VL_COVDET_AA_PATCH_RESOLUTION ;
02476 vl_size const side = 2*VL_COVDET_AA_PATCH_RESOLUTION + 1 ;
02477 double const extent = VL_COVDET_AA_PATCH_EXTENT ;
02478
02479
02480 *adapted = frame ;
02481
02482 while (1) {
02483 double lxx = 0, lxy = 0, lyy = 0 ;
02484 vl_index k ;
02485 int err ;
02486
02487
02488 vl_svd2(D, U, V, A) ;
02489 anisotropy = VL_MAX(D[0]/D[3], D[3]/D[0]) ;
02490
02491
02492
02493 if (anisotropy > VL_COVDET_AA_MAX_ANISOTROPY) {
02494
02495 break ;
02496 }
02497
02498
02499
02500 if (iter == 0) {
02501 referenceScale = VL_MIN(D[0], D[3]) ;
02502 factor = 1.0 ;
02503 } else {
02504 factor = referenceScale / VL_MIN(D[0],D[3]) ;
02505 }
02506
02507 D[0] *= factor ;
02508 D[3] *= factor ;
02509
02510 A[0] = U[0] * D[0] ;
02511 A[1] = U[1] * D[0] ;
02512 A[2] = U[2] * D[3] ;
02513 A[3] = U[3] * D[3] ;
02514
02515 adapted->a11 = A[0] ;
02516 adapted->a21 = A[1] ;
02517 adapted->a12 = A[2] ;
02518 adapted->a22 = A[3] ;
02519
02520 if (++iter >= VL_COVDET_AA_MAX_NUM_ITERATIONS) break ;
02521
02522 err = vl_covdet_extract_patch_helper(self,
02523 &sigma1, &sigma2,
02524 self->aaPatch,
02525 resolution,
02526 extent,
02527 sigmaD,
02528 A, T, D[0], D[3]) ;
02529 if (err) return err ;
02530
02531 if (self->aaAccurateSmoothing ) {
02532 double deltaSigma1 = sqrt(VL_MAX(sigmaD*sigmaD - sigma1*sigma1,0)) ;
02533 double deltaSigma2 = sqrt(VL_MAX(sigmaD*sigmaD - sigma2*sigma2,0)) ;
02534 double stephat = extent / resolution ;
02535 vl_imsmooth_f(self->aaPatch, side,
02536 self->aaPatch, side, side, side,
02537 deltaSigma1 / stephat, deltaSigma2 / stephat) ;
02538 }
02539
02540
02541 vl_imgradient_f (self->aaPatchX, self->aaPatchY, 1, side,
02542 self->aaPatch, side, side, side) ;
02543
02544 for (k = 0 ; k < (signed)(side*side) ; ++k) {
02545 double lx = self->aaPatchX[k] ;
02546 double ly = self->aaPatchY[k] ;
02547 lxx += lx * lx * self->aaMask[k] ;
02548 lyy += ly * ly * self->aaMask[k] ;
02549 lxy += lx * ly * self->aaMask[k] ;
02550 }
02551 M[0] = lxx ;
02552 M[1] = lxy ;
02553 M[2] = lxy ;
02554 M[3] = lyy ;
02555
02556 if (lxx == 0 || lyy == 0) {
02557 *adapted = frame ;
02558 break ;
02559 }
02560
02561
02562 vl_svd2 (Q, P, P_, M) ;
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576 if (Q[3]/Q[0] < VL_COVDET_AA_CONVERGENCE_THRESHOLD &&
02577 Q[0]/Q[3] < VL_COVDET_AA_CONVERGENCE_THRESHOLD) {
02578 break ;
02579 }
02580
02581 {
02582 double Ap [4] ;
02583 double q0 = sqrt(Q[0]) ;
02584 double q1 = sqrt(Q[3]) ;
02585 Ap[0] = (A[0] * P[0] + A[2] * P[1]) / q0 ;
02586 Ap[1] = (A[1] * P[0] + A[3] * P[1]) / q0 ;
02587 Ap[2] = (A[0] * P[2] + A[2] * P[3]) / q1 ;
02588 Ap[3] = (A[1] * P[2] + A[3] * P[3]) / q1 ;
02589 memcpy(A,Ap,4*sizeof(double)) ;
02590 }
02591
02592 }
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602 {
02603 double A [2*2] = {adapted->a11, adapted->a21, adapted->a12, adapted->a22} ;
02604 double ref [2] ;
02605 double ref_ [2] ;
02606 double angle ;
02607 double angle_ ;
02608 double dangle ;
02609 double r1, r2 ;
02610
02611 if (self->transposed) {
02612
02613 ref[0] = 1 ;
02614 ref[1] = 0 ;
02615 } else {
02616
02617 ref[0] = 0 ;
02618 ref[1] = 1 ;
02619 }
02620
02621 vl_solve_linear_system_2 (ref_, A, ref) ;
02622 angle = atan2(ref[1], ref[0]) ;
02623 angle_ = atan2(ref_[1], ref_[0]) ;
02624 dangle = angle_ - angle ;
02625 r1 = cos(dangle) ;
02626 r2 = sin(dangle) ;
02627 adapted->a11 = + A[0] * r1 + A[2] * r2 ;
02628 adapted->a21 = + A[1] * r1 + A[3] * r2 ;
02629 adapted->a12 = - A[0] * r2 + A[2] * r1 ;
02630 adapted->a22 = - A[1] * r2 + A[3] * r1 ;
02631 }
02632
02633 return VL_ERR_OK ;
02634 }
02635
02643 void
02644 vl_covdet_extract_affine_shape (VlCovDet * self)
02645 {
02646 vl_index i, j = 0 ;
02647 vl_size numFeatures = vl_covdet_get_num_features(self) ;
02648 VlCovDetFeature * feature = vl_covdet_get_features(self);
02649 for (i = 0 ; i < (signed)numFeatures ; ++i) {
02650 int status ;
02651 VlFrameOrientedEllipse adapted ;
02652 status = vl_covdet_extract_affine_shape_for_frame(self, &adapted, feature[i].frame) ;
02653 if (status == VL_ERR_OK) {
02654 feature[j] = feature[i] ;
02655 feature[j].frame = adapted ;
02656 ++ j ;
02657 }
02658 }
02659 self->numFeatures = j ;
02660 }
02661
02662
02663
02664
02665
02666 static int
02667 _vl_covdet_compare_orientations_descending (void const * a_,
02668 void const * b_)
02669 {
02670 VlCovDetFeatureOrientation const * a = a_ ;
02671 VlCovDetFeatureOrientation const * b = b_ ;
02672 if (a->score > b->score) return -1 ;
02673 if (a->score < b->score) return +1 ;
02674 return 0 ;
02675 }
02676
02689 VlCovDetFeatureOrientation *
02690 vl_covdet_extract_orientations_for_frame (VlCovDet * self,
02691 vl_size * numOrientations,
02692 VlFrameOrientedEllipse frame)
02693 {
02694 int err ;
02695 vl_index k, i ;
02696 vl_index iter ;
02697
02698 double extent = VL_COVDET_AA_PATCH_EXTENT ;
02699 vl_size resolution = VL_COVDET_AA_PATCH_RESOLUTION ;
02700 vl_size side = 2 * resolution + 1 ;
02701
02702 vl_size const numBins = VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ;
02703 double hist [VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS] ;
02704 double const binExtent = 2 * VL_PI / VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ;
02705 double const peakRelativeSize = VL_COVDET_OR_ADDITIONAL_PEAKS_RELATIVE_SIZE ;
02706 double maxPeakValue ;
02707
02708 double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
02709 double T [2] = {frame.x, frame.y} ;
02710 double U [2*2] ;
02711 double V [2*2] ;
02712 double D [2*2] ;
02713 double sigma1, sigma2 ;
02714 double sigmaD = 1.0 ;
02715 double theta0 ;
02716
02717 assert(self);
02718 assert(numOrientations) ;
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737 vl_svd2(D, U, V, A) ;
02738
02739 A[0] = U[0] * D[0] ;
02740 A[1] = U[1] * D[0] ;
02741 A[2] = U[2] * D[3] ;
02742 A[3] = U[3] * D[3] ;
02743
02744 theta0 = atan2(V[1],V[0]) ;
02745
02746 err = vl_covdet_extract_patch_helper(self,
02747 &sigma1, &sigma2,
02748 self->aaPatch,
02749 resolution,
02750 extent,
02751 sigmaD,
02752 A, T, D[0], D[3]) ;
02753
02754 if (err) {
02755 *numOrientations = 0 ;
02756 return NULL ;
02757 }
02758
02759 if (1) {
02760 double deltaSigma1 = sqrt(VL_MAX(sigmaD*sigmaD - sigma1*sigma1,0)) ;
02761 double deltaSigma2 = sqrt(VL_MAX(sigmaD*sigmaD - sigma2*sigma2,0)) ;
02762 double stephat = extent / resolution ;
02763 vl_imsmooth_f(self->aaPatch, side,
02764 self->aaPatch, side, side, side,
02765 deltaSigma1 / stephat, deltaSigma2 / stephat) ;
02766 }
02767
02768
02769 vl_imgradient_polar_f (self->aaPatchX, self->aaPatchY, 1, side,
02770 self->aaPatch, side, side, side) ;
02771
02772 memset (hist, 0, sizeof(double) * numBins) ;
02773
02774 for (k = 0 ; k < (signed)(side*side) ; ++k) {
02775 double modulus = self->aaPatchX[k] ;
02776 double angle = self->aaPatchY[k] ;
02777 double weight = self->aaMask[k] ;
02778
02779 double x = angle / binExtent ;
02780 vl_index bin = vl_floor_d(x) ;
02781 double w2 = x - bin ;
02782 double w1 = 1.0 - w2 ;
02783
02784 hist[(bin + numBins) % numBins] += w1 * (modulus * weight) ;
02785 hist[(bin + numBins + 1) % numBins] += w2 * (modulus * weight) ;
02786 }
02787
02788
02789 for (iter = 0; iter < 6; iter ++) {
02790 double prev = hist [numBins - 1] ;
02791 double first = hist [0] ;
02792 vl_index i ;
02793 for (i = 0; i < (signed)numBins - 1; ++i) {
02794 double curr = (prev + hist[i] + hist[(i + 1) % numBins]) / 3.0 ;
02795 prev = hist[i] ;
02796 hist[i] = curr ;
02797 }
02798 hist[i] = (prev + hist[i] + first) / 3.0 ;
02799 }
02800
02801
02802 maxPeakValue = 0 ;
02803 for (i = 0 ; i < (signed)numBins ; ++i) {
02804 maxPeakValue = VL_MAX (maxPeakValue, hist[i]) ;
02805 }
02806
02807
02808 *numOrientations = 0 ;
02809 for(i = 0 ; i < (signed)numBins ; ++i) {
02810 double h0 = hist [i] ;
02811 double hm = hist [(i - 1 + numBins) % numBins] ;
02812 double hp = hist [(i + 1 + numBins) % numBins] ;
02813
02814
02815 if (h0 > peakRelativeSize * maxPeakValue && h0 > hm && h0 > hp) {
02816
02817 double di = - 0.5 * (hp - hm) / (hp + hm - 2 * h0) ;
02818 double th = binExtent * (i + di) + theta0 ;
02819 if (self->transposed) {
02820
02821 th = th - VL_PI/2 ;
02822 }
02823 self->orientations[*numOrientations].angle = th ;
02824 self->orientations[*numOrientations].score = h0 ;
02825 *numOrientations += 1 ;
02826
02827
02828 if (*numOrientations >= VL_COVDET_MAX_NUM_ORIENTATIONS) break ;
02829 }
02830 }
02831
02832
02833 qsort(self->orientations,
02834 *numOrientations,
02835 sizeof(VlCovDetFeatureOrientation),
02836 _vl_covdet_compare_orientations_descending) ;
02837
02838 return self->orientations ;
02839 }
02840
02849 void
02850 vl_covdet_extract_orientations (VlCovDet * self)
02851 {
02852 vl_index i, j ;
02853 vl_size numFeatures = vl_covdet_get_num_features(self) ;
02854 for (i = 0 ; i < (signed)numFeatures ; ++i) {
02855 vl_size numOrientations ;
02856 VlCovDetFeature feature = self->features[i] ;
02857 VlCovDetFeatureOrientation* orientations =
02858 vl_covdet_extract_orientations_for_frame(self, &numOrientations, feature.frame) ;
02859
02860 for (j = 0 ; j < (signed)numOrientations ; ++j) {
02861 double A [2*2] = {
02862 feature.frame.a11,
02863 feature.frame.a21,
02864 feature.frame.a12,
02865 feature.frame.a22} ;
02866 double r1 = cos(orientations[j].angle) ;
02867 double r2 = sin(orientations[j].angle) ;
02868 VlCovDetFeature * oriented ;
02869
02870 if (j == 0) {
02871 oriented = & self->features[i] ;
02872 } else {
02873 vl_covdet_append_feature(self, &feature) ;
02874 oriented = & self->features[self->numFeatures -1] ;
02875 }
02876
02877 oriented->orientationScore = orientations[j].score ;
02878 oriented->frame.a11 = + A[0] * r1 + A[2] * r2 ;
02879 oriented->frame.a21 = + A[1] * r1 + A[3] * r2 ;
02880 oriented->frame.a12 = - A[0] * r2 + A[2] * r1 ;
02881 oriented->frame.a22 = - A[1] * r2 + A[3] * r1 ;
02882 }
02883 }
02884 }
02885
02886
02887
02888
02889
02899 VlCovDetFeatureLaplacianScale *
02900 vl_covdet_extract_laplacian_scales_for_frame (VlCovDet * self,
02901 vl_size * numScales,
02902 VlFrameOrientedEllipse frame)
02903 {
02904
02905
02906
02907
02908
02909
02910
02911
02912
02913
02914
02915
02916
02917 int err ;
02918 double const sigmaImage = 1.0 / sqrt(2.0) ;
02919 double const step = 0.5 * sigmaImage ;
02920 double actualSigmaImage ;
02921 vl_size const resolution = VL_COVDET_LAP_PATCH_RESOLUTION ;
02922 vl_size const num = 2 * resolution + 1 ;
02923 double extent = step * resolution ;
02924 double scores [VL_COVDET_LAP_NUM_LEVELS] ;
02925 double factor = 1.0 ;
02926 float const * pt ;
02927 vl_index k ;
02928
02929 double A[2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
02930 double T[2] = {frame.x, frame.y} ;
02931 double D[4], U[4], V[4] ;
02932 double sigma1, sigma2 ;
02933
02934 assert(self) ;
02935 assert(numScales) ;
02936
02937 *numScales = 0 ;
02938
02939 vl_svd2(D, U, V, A) ;
02940
02941 err = vl_covdet_extract_patch_helper
02942 (self, &sigma1, &sigma2, self->lapPatch, resolution, extent, sigmaImage, A, T, D[0], D[3]) ;
02943 if (err) return NULL ;
02944
02945
02946 if (sigma1 == sigma2) {
02947 actualSigmaImage = sigma1 ;
02948 } else {
02949
02950 actualSigmaImage = sqrt(sigma1*sigma2) ;
02951 }
02952
02953
02954 pt = self->laplacians ;
02955 for (k = 0 ; k < VL_COVDET_LAP_NUM_LEVELS ; ++k) {
02956 vl_index q ;
02957 double score = 0 ;
02958 double sigmaLap = pow(2.0, -0.5 + (double)k / (VL_COVDET_LAP_NUM_LEVELS - 1)) ;
02959
02960
02961 sigmaLap = sqrt(sigmaLap*sigmaLap
02962 - sigmaImage*sigmaImage
02963 + actualSigmaImage*actualSigmaImage) ;
02964
02965 for (q = 0 ; q < (signed)(num * num) ; ++q) {
02966 score += (*pt++) * self->lapPatch[q] ;
02967 }
02968 scores[k] = score * sigmaLap * sigmaLap ;
02969 }
02970
02971
02972 for (k = 1 ; k < VL_COVDET_LAP_NUM_LEVELS - 1 ; ++k) {
02973 double a = scores[k-1] ;
02974 double b = scores[k] ;
02975 double c = scores[k+1] ;
02976 double t = self->lapPeakThreshold ;
02977
02978 if ((((b > a) && (b > c)) || ((b < a) && (b < c))) && (vl_abs_d(b) >= t)) {
02979 double dk = - 0.5 * (c - a) / (c + a - 2 * b) ;
02980 double s = k + dk ;
02981 double sigmaLap = pow(2.0, -0.5 + s / (VL_COVDET_LAP_NUM_LEVELS - 1)) ;
02982 double scale ;
02983 sigmaLap = sqrt(sigmaLap*sigmaLap
02984 - sigmaImage*sigmaImage
02985 + actualSigmaImage*actualSigmaImage) ;
02986 scale = sigmaLap / 1.0 ;
02987
02988
02989
02990
02991 if (*numScales < VL_COVDET_MAX_NUM_LAPLACIAN_SCALES) {
02992 self->scales[*numScales].scale = scale * factor ;
02993 self->scales[*numScales].score = b + 0.5 * (c - a) * dk ;
02994 *numScales += 1 ;
02995 }
02996 }
02997 }
02998 return self->scales ;
02999 }
03000
03008 void
03009 vl_covdet_extract_laplacian_scales (VlCovDet * self)
03010 {
03011 vl_index i, j ;
03012 vl_bool dropFeaturesWithoutScale = VL_TRUE ;
03013 vl_size numFeatures = vl_covdet_get_num_features(self) ;
03014 memset(self->numFeaturesWithNumScales, 0,
03015 sizeof(self->numFeaturesWithNumScales)) ;
03016
03017 for (i = 0 ; i < (signed)numFeatures ; ++i) {
03018 vl_size numScales ;
03019 VlCovDetFeature feature = self->features[i] ;
03020 VlCovDetFeatureLaplacianScale const * scales =
03021 vl_covdet_extract_laplacian_scales_for_frame(self, &numScales, feature.frame) ;
03022
03023 self->numFeaturesWithNumScales[numScales] ++ ;
03024
03025 if (numScales == 0 && dropFeaturesWithoutScale) {
03026 self->features[i].peakScore = 0 ;
03027 }
03028
03029 for (j = 0 ; j < (signed)numScales ; ++j) {
03030 VlCovDetFeature * scaled ;
03031
03032 if (j == 0) {
03033 scaled = & self->features[i] ;
03034 } else {
03035 vl_covdet_append_feature(self, &feature) ;
03036 scaled = & self->features[self->numFeatures -1] ;
03037 }
03038
03039 scaled->laplacianScaleScore = scales[j].score ;
03040 scaled->frame.a11 *= scales[j].scale ;
03041 scaled->frame.a21 *= scales[j].scale ;
03042 scaled->frame.a12 *= scales[j].scale ;
03043 scaled->frame.a22 *= scales[j].scale ;
03044 }
03045 }
03046 if (dropFeaturesWithoutScale) {
03047 j = 0 ;
03048 for (i = 0 ; i < (signed)self->numFeatures ; ++i) {
03049 VlCovDetFeature feature = self->features[i] ;
03050 if (feature.peakScore) {
03051 self->features[j++] = feature ;
03052 }
03053 }
03054 self->numFeatures = j ;
03055 }
03056
03057 }
03058
03059
03060
03061
03062
03063 vl_bool
03064 _vl_covdet_check_frame_inside (VlCovDet * self, VlFrameOrientedEllipse frame, double margin)
03065 {
03066 double extent = margin ;
03067 double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
03068 double T[2] = {frame.x, frame.y} ;
03069 double x0 = +VL_INFINITY_D ;
03070 double x1 = -VL_INFINITY_D ;
03071 double y0 = +VL_INFINITY_D ;
03072 double y1 = -VL_INFINITY_D ;
03073 double boxx [4] = {extent, extent, -extent, -extent} ;
03074 double boxy [4] = {-extent, extent, extent, -extent} ;
03075 VlScaleSpaceGeometry geom = vl_scalespace_get_geometry(self->gss) ;
03076 int i ;
03077 for (i = 0 ; i < 4 ; ++i) {
03078 double x = A[0] * boxx[i] + A[2] * boxy[i] + T[0] ;
03079 double y = A[1] * boxx[i] + A[3] * boxy[i] + T[1] ;
03080 x0 = VL_MIN(x0, x) ;
03081 x1 = VL_MAX(x1, x) ;
03082 y0 = VL_MIN(y0, y) ;
03083 y1 = VL_MAX(y1, y) ;
03084 }
03085
03086 return
03087 0 <= x0 && x1 <= geom.width-1 &&
03088 0 <= y0 && y1 <= geom.height-1 ;
03089 }
03090
03107 void
03108 vl_covdet_drop_features_outside (VlCovDet * self, double margin)
03109 {
03110 vl_index i, j = 0 ;
03111 vl_size numFeatures = vl_covdet_get_num_features(self) ;
03112 for (i = 0 ; i < (signed)numFeatures ; ++i) {
03113 vl_bool inside =
03114 _vl_covdet_check_frame_inside (self, self->features[i].frame, margin) ;
03115 if (inside) {
03116 self->features[j] = self->features[i] ;
03117 ++j ;
03118 }
03119 }
03120 self->numFeatures = j ;
03121 }
03122
03123
03124
03125
03126
03127
03132 vl_bool
03133 vl_covdet_get_transposed (VlCovDet const * self)
03134 {
03135 return self->transposed ;
03136 }
03137
03142 void
03143 vl_covdet_set_transposed (VlCovDet * self, vl_bool t)
03144 {
03145 self->transposed = t ;
03146 }
03147
03148
03153 double
03154 vl_covdet_get_edge_threshold (VlCovDet const * self)
03155 {
03156 return self->edgeThreshold ;
03157 }
03158
03165 void
03166 vl_covdet_set_edge_threshold (VlCovDet * self, double edgeThreshold)
03167 {
03168 assert(edgeThreshold >= 0) ;
03169 self->edgeThreshold = edgeThreshold ;
03170 }
03171
03172
03177 double
03178 vl_covdet_get_peak_threshold (VlCovDet const * self)
03179 {
03180 return self->peakThreshold ;
03181 }
03182
03189 void
03190 vl_covdet_set_peak_threshold (VlCovDet * self, double peakThreshold)
03191 {
03192 assert(peakThreshold >= 0) ;
03193 self->peakThreshold = peakThreshold ;
03194 }
03195
03196
03204 double
03205 vl_covdet_get_laplacian_peak_threshold (VlCovDet const * self)
03206 {
03207 return self->lapPeakThreshold ;
03208 }
03209
03216 void
03217 vl_covdet_set_laplacian_peak_threshold (VlCovDet * self, double peakThreshold)
03218 {
03219 assert(peakThreshold >= 0) ;
03220 self->lapPeakThreshold = peakThreshold ;
03221 }
03222
03223
03228 vl_index
03229 vl_covdet_get_first_octave (VlCovDet const * self)
03230 {
03231 return self->firstOctave ;
03232 }
03233
03240 void
03241 vl_covdet_set_first_octave (VlCovDet * self, vl_index o)
03242 {
03243 self->firstOctave = o ;
03244 vl_covdet_reset(self) ;
03245 }
03246
03247
03253 vl_size
03254 vl_covdet_get_octave_resolution (VlCovDet const * self)
03255 {
03256 return self->octaveResolution ;
03257 }
03258
03266 void
03267 vl_covdet_set_octave_resolution (VlCovDet * self, vl_size r)
03268 {
03269 self->octaveResolution = r ;
03270 vl_covdet_reset(self) ;
03271 }
03272
03273
03279 vl_bool
03280 vl_covdet_get_aa_accurate_smoothing (VlCovDet const * self)
03281 {
03282 return self->aaAccurateSmoothing ;
03283 }
03284
03290 void
03291 vl_covdet_set_aa_accurate_smoothing (VlCovDet * self, vl_bool x)
03292 {
03293 self->aaAccurateSmoothing = x ;
03294 }
03295
03296
03302 double
03303 vl_covdet_get_non_extrema_suppression_threshold (VlCovDet const * self)
03304 {
03305 return self->nonExtremaSuppression ;
03306 }
03307
03313 void
03314 vl_covdet_set_non_extrema_suppression_threshold (VlCovDet * self, double x)
03315 {
03316 self->nonExtremaSuppression = x ;
03317 }
03318
03324 vl_size
03325 vl_covdet_get_num_non_extrema_suppressed (VlCovDet const * self)
03326 {
03327 return self->numNonExtremaSuppressed ;
03328 }
03329
03330
03331
03335 vl_size
03336 vl_covdet_get_num_features (VlCovDet const * self)
03337 {
03338 return self->numFeatures ;
03339 }
03340
03344 void *
03345 vl_covdet_get_features (VlCovDet * self)
03346 {
03347 return self->features ;
03348 }
03349
03357 VlScaleSpace *
03358 vl_covdet_get_gss (VlCovDet const * self)
03359 {
03360 return self->gss ;
03361 }
03362
03370 VlScaleSpace *
03371 vl_covdet_get_css (VlCovDet const * self)
03372 {
03373 return self->css ;
03374 }
03375
03386 vl_size const *
03387 vl_covdet_get_laplacian_scales_statistics (VlCovDet const * self,
03388 vl_size * numScales)
03389 {
03390 *numScales = VL_COVDET_MAX_NUM_LAPLACIAN_SCALES ;
03391 return self->numFeaturesWithNumScales ;
03392 }