1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* ---- includes ----------------------------------------------------------- */ 18 19#include "b_BasicEm/Functions.h" 20#include "b_BasicEm/Math.h" 21#include "b_ImageEm/Functions.h" 22#include "b_BitFeatureEm/LocalScanDetector.h" 23 24/* ------------------------------------------------------------------------- */ 25 26/* ========================================================================= */ 27/* */ 28/* ---- \ghd{ auxiliary functions } ---------------------------------------- */ 29/* */ 30/* ========================================================================= */ 31 32/* ------------------------------------------------------------------------- */ 33 34/** applies PCA mapping 35 * Input and output clusters may be identical 36 */ 37void bbf_LocalScanDetector_pcaMap( struct bbs_Context* cpA, 38 const struct bbf_LocalScanDetector* ptrA, 39 const struct bts_IdCluster2D* inClusterPtrA, 40 struct bts_IdCluster2D* outClusterPtrA ) 41{ 42 bbs_DEF_fNameL( "bbf_LocalScanDetector_pcaMap" ) 43 44 struct bts_Cluster2D* tmpCl1PtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E; 45 struct bts_Cluster2D* tmpCl2PtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E; 46 struct bts_RBFMap2D* rbfPtrL = ( struct bts_RBFMap2D* )&ptrA->rbfMapE; 47 struct bts_Flt16Alt2D altL; 48 uint32 outBbpL = inClusterPtrA->clusterE.bbpE; 49 uint32 iL, jL; 50 51 /* setup two equivalent clusters holding the essential (alt-free) moves to be handled by PCA */ 52 bts_IdCluster2D_convertToEqivalentClusters( cpA, 53 inClusterPtrA, 54 &ptrA->pcaClusterE, 55 tmpCl1PtrL, 56 tmpCl2PtrL ); 57 58 altL = bts_Cluster2D_alt( cpA, tmpCl1PtrL, tmpCl2PtrL, bts_ALT_RIGID ); 59 bts_Cluster2D_transform( cpA, tmpCl1PtrL, altL ); 60 bts_RBFMap2D_compute( cpA, rbfPtrL, tmpCl2PtrL, tmpCl1PtrL ); 61 bts_RBFMap2D_mapCluster( cpA, rbfPtrL, &ptrA->pcaClusterE.clusterE, tmpCl1PtrL, 6/* ! */ ); 62 63 /* PCA projection: cluster1 -> cluster1 */ 64 { 65 /* mat elements: 8.8 */ 66 const int16* matPtrL = ptrA->pcaMatE.arrPtrE; 67 68 /* same bbp as pca cluster */ 69 const int16* avgPtrL = ptrA->pcaAvgE.arrPtrE; 70 71 struct bts_Int16Vec2D* vecArrL = tmpCl1PtrL->vecArrE; 72 73 /* projected vector */ 74 int32 prjVecL[ bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM ]; 75 76 /* width of matrix */ 77 uint16 matWidthL = tmpCl1PtrL->sizeE * 2; 78 79 if( ptrA->pcaDimSubSpaceE > bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM ) 80 { 81 bbs_ERROR1( "%s:\nbpi_RF_LANDMARKER_MAX_PCA_DIM exceeded", fNameL ); 82 return; 83 } 84 85 /* forward trafo */ 86 for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) 87 { 88 int32 sumL = 0; 89 avgPtrL = ptrA->pcaAvgE.arrPtrE; 90 for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ ) 91 { 92 sumL += matPtrL[ 0 ] * ( vecArrL[ jL ].xE - avgPtrL[ 0 ] ); 93 sumL += matPtrL[ 1 ] * ( vecArrL[ jL ].yE - avgPtrL[ 1 ] ); 94 avgPtrL += 2; 95 matPtrL += 2; 96 } 97 prjVecL[ iL ] = ( sumL + 128 ) >> 8; 98 } 99 100 matPtrL = ptrA->pcaMatE.arrPtrE; 101 avgPtrL = ptrA->pcaAvgE.arrPtrE; 102 vecArrL = tmpCl1PtrL->vecArrE; 103 104 /* backward trafo */ 105 for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ ) 106 { 107 int32 sumL = 0; 108 for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) 109 { 110 sumL += matPtrL[ iL * matWidthL + 0 ] * prjVecL[ iL ]; 111 } 112 113 vecArrL[ jL ].xE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 0 ]; 114 115 sumL = 0; 116 for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) 117 { 118 sumL += matPtrL[ iL * matWidthL + 1 ] * prjVecL[ iL ]; 119 } 120 121 vecArrL[ jL ].yE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 1 ]; 122 123 matPtrL += 2; 124 avgPtrL += 2; 125 } 126 } 127 128 /* ALT backtransformation */ 129 bts_IdCluster2D_copy( cpA, outClusterPtrA, &ptrA->pcaClusterE ); 130 bts_Cluster2D_copyTransform( cpA, &outClusterPtrA->clusterE, tmpCl1PtrL, bts_Flt16Alt2D_inverted( &altL ), outBbpL ); 131} 132 133/* ------------------------------------------------------------------------- */ 134 135/* ========================================================================= */ 136/* */ 137/* ---- \ghd{ constructor / destructor } ----------------------------------- */ 138/* */ 139/* ========================================================================= */ 140 141/* ------------------------------------------------------------------------- */ 142 143void bbf_LocalScanDetector_init( struct bbs_Context* cpA, 144 struct bbf_LocalScanDetector* ptrA ) 145{ 146 bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) ); 147 bts_RBFMap2D_init( cpA, &ptrA->rbfMapE ); 148 bts_Cluster2D_init( cpA, &ptrA->tmpCluster1E ); 149 bts_Cluster2D_init( cpA, &ptrA->tmpCluster2E ); 150 bts_Cluster2D_init( cpA, &ptrA->tmpCluster3E ); 151 bts_Cluster2D_init( cpA, &ptrA->tmpCluster4E ); 152 bbf_LocalScanner_init( cpA, &ptrA->scannerE ); 153 bbs_Int32Arr_init( cpA, &ptrA->actArrE ); 154 bbs_Int16Arr_init( cpA, &ptrA->idxArrE ); 155 bbs_UInt8Arr_init( cpA, &ptrA->workImageBufE ); 156 ptrA->maxImageWidthE = 0; 157 ptrA->maxImageHeightE = 0; 158 159 ptrA->patchWidthE = 0; 160 ptrA->patchHeightE = 0; 161 ptrA->scanWidthE = 0; 162 ptrA->scanHeightE = 0; 163 ptrA->scaleExpE = 0; 164 ptrA->interpolatedWarpingE = TRUE; 165 ptrA->warpScaleThresholdE = 0; 166 bts_IdCluster2D_init( cpA, &ptrA->refClusterE ); 167 bts_Cluster2D_init( cpA, &ptrA->scanClusterE ); 168 bbs_UInt16Arr_init( cpA, &ptrA->ftrDataArrE ); 169 bbf_BitParam_init( cpA, &ptrA->bitParamE ); 170 ptrA->outlierDistanceE = 0; 171 bts_IdCluster2D_init( cpA, &ptrA->pcaClusterE ); 172 bbs_Int16Arr_init( cpA, &ptrA->pcaAvgE ); 173 bbs_Int16Arr_init( cpA, &ptrA->pcaMatE ); 174 ptrA->pcaDimSubSpaceE = 0; 175 ptrA->maxImageWidthE = 0; 176 ptrA->maxImageHeightE = 0; 177} 178 179/* ------------------------------------------------------------------------- */ 180 181void bbf_LocalScanDetector_exit( struct bbs_Context* cpA, 182 struct bbf_LocalScanDetector* ptrA ) 183{ 184 uint16 iL; 185 for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) bbf_featureExit( cpA, ptrA->ftrPtrArrE[ iL ] ); 186 bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) ); 187 188 bts_RBFMap2D_exit( cpA, &ptrA->rbfMapE ); 189 bts_Cluster2D_exit( cpA, &ptrA->tmpCluster1E ); 190 bts_Cluster2D_exit( cpA, &ptrA->tmpCluster2E ); 191 bts_Cluster2D_exit( cpA, &ptrA->tmpCluster3E ); 192 bts_Cluster2D_exit( cpA, &ptrA->tmpCluster4E ); 193 bbf_LocalScanner_exit( cpA, &ptrA->scannerE ); 194 bbs_Int32Arr_exit( cpA, &ptrA->actArrE ); 195 bbs_Int16Arr_exit( cpA, &ptrA->idxArrE ); 196 bbs_UInt8Arr_exit( cpA, &ptrA->workImageBufE ); 197 ptrA->maxImageWidthE = 0; 198 ptrA->maxImageHeightE = 0; 199 200 ptrA->patchWidthE = 0; 201 ptrA->patchHeightE = 0; 202 ptrA->scanWidthE = 0; 203 ptrA->scanHeightE = 0; 204 ptrA->scaleExpE = 0; 205 ptrA->interpolatedWarpingE = TRUE; 206 ptrA->warpScaleThresholdE = 0; 207 bts_IdCluster2D_exit( cpA, &ptrA->refClusterE ); 208 bts_Cluster2D_exit( cpA, &ptrA->scanClusterE ); 209 bbs_UInt16Arr_exit( cpA, &ptrA->ftrDataArrE ); 210 bbf_BitParam_exit( cpA, &ptrA->bitParamE ); 211 ptrA->outlierDistanceE = 0; 212 bts_IdCluster2D_exit( cpA, &ptrA->pcaClusterE ); 213 bbs_Int16Arr_exit( cpA, &ptrA->pcaAvgE ); 214 bbs_Int16Arr_exit( cpA, &ptrA->pcaMatE ); 215 ptrA->pcaDimSubSpaceE = 0; 216 ptrA->maxImageWidthE = 0; 217 ptrA->maxImageHeightE = 0; 218} 219 220/* ------------------------------------------------------------------------- */ 221 222/* ========================================================================= */ 223/* */ 224/* ---- \ghd{ operators } -------------------------------------------------- */ 225/* */ 226/* ========================================================================= */ 227 228/* ------------------------------------------------------------------------- */ 229 230void bbf_LocalScanDetector_copy( struct bbs_Context* cpA, 231 struct bbf_LocalScanDetector* ptrA, 232 const struct bbf_LocalScanDetector* srcPtrA ) 233{ 234 bbs_ERROR0( "bbf_LocalScanDetector_copy:\n Function is not available" ); 235} 236 237/* ------------------------------------------------------------------------- */ 238 239flag bbf_LocalScanDetector_equal( struct bbs_Context* cpA, 240 const struct bbf_LocalScanDetector* ptrA, 241 const struct bbf_LocalScanDetector* srcPtrA ) 242{ 243 bbs_ERROR0( "bbf_LocalScanDetector_equal:\n Function is not available" ); 244 return TRUE; 245} 246 247/* ------------------------------------------------------------------------- */ 248 249/* ========================================================================= */ 250/* */ 251/* ---- \ghd{ query functions } -------------------------------------------- */ 252/* */ 253/* ========================================================================= */ 254 255/* ------------------------------------------------------------------------- */ 256 257/* ========================================================================= */ 258/* */ 259/* ---- \ghd{ modify functions } ------------------------------------------- */ 260/* */ 261/* ========================================================================= */ 262 263/* ------------------------------------------------------------------------- */ 264 265/* ========================================================================= */ 266/* */ 267/* ---- \ghd{ I/O } -------------------------------------------------------- */ 268/* */ 269/* ========================================================================= */ 270 271/* ------------------------------------------------------------------------- */ 272 273uint32 bbf_LocalScanDetector_memSize( struct bbs_Context* cpA, 274 const struct bbf_LocalScanDetector* ptrA ) 275{ 276 uint32 iL; 277 uint32 memSizeL = bbs_SIZEOF16( uint32 ) + 278 bbs_SIZEOF16( uint32 ); /* version */ 279 280 memSizeL += bbs_SIZEOF16( ptrA->patchWidthE ); 281 memSizeL += bbs_SIZEOF16( ptrA->patchHeightE ); 282 memSizeL += bbs_SIZEOF16( ptrA->scanWidthE ); 283 memSizeL += bbs_SIZEOF16( ptrA->scanHeightE ); 284 memSizeL += bbs_SIZEOF16( ptrA->scaleExpE ); 285 memSizeL += bbs_SIZEOF16( ptrA->interpolatedWarpingE ); 286 memSizeL += bbs_SIZEOF16( ptrA->warpScaleThresholdE ); 287 memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->refClusterE ); 288 memSizeL += bts_Cluster2D_memSize( cpA, &ptrA->scanClusterE ); 289 memSizeL += bbf_BitParam_memSize( cpA, &ptrA->bitParamE ); 290 memSizeL += bbs_SIZEOF16( ptrA->outlierDistanceE ); 291 memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->pcaClusterE ); 292 memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaAvgE ); 293 memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaMatE ); 294 memSizeL += bbs_SIZEOF16( ptrA->pcaDimSubSpaceE ); 295 memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE ); 296 memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE ); 297 for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memSizeL += bbf_featureMemSize( cpA, ptrA->ftrPtrArrE[ iL ] ); 298 299 return memSizeL; 300} 301 302/* ------------------------------------------------------------------------- */ 303 304uint32 bbf_LocalScanDetector_memWrite( struct bbs_Context* cpA, 305 const struct bbf_LocalScanDetector* ptrA, 306 uint16* memPtrA ) 307{ 308 uint32 iL; 309 uint32 memSizeL = bbf_LocalScanDetector_memSize( cpA, ptrA ); 310 memPtrA += bbs_memWrite32( &memSizeL, memPtrA ); 311 memPtrA += bbs_memWriteUInt32( bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA ); 312 313 memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA ); 314 memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA ); 315 memPtrA += bbs_memWrite32( &ptrA->scanWidthE, memPtrA ); 316 memPtrA += bbs_memWrite32( &ptrA->scanHeightE, memPtrA ); 317 memPtrA += bbs_memWrite32( &ptrA->scaleExpE, memPtrA ); 318 memPtrA += bbs_memWrite32( &ptrA->interpolatedWarpingE, memPtrA ); 319 memPtrA += bbs_memWrite32( &ptrA->warpScaleThresholdE, memPtrA ); 320 memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->refClusterE, memPtrA ); 321 memPtrA += bts_Cluster2D_memWrite( cpA, &ptrA->scanClusterE, memPtrA ); 322 memPtrA += bbf_BitParam_memWrite( cpA, &ptrA->bitParamE, memPtrA ); 323 memPtrA += bbs_memWrite32( &ptrA->outlierDistanceE, memPtrA ); 324 memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->pcaClusterE, memPtrA ); 325 memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaAvgE, memPtrA ); 326 memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaMatE, memPtrA ); 327 memPtrA += bbs_memWrite32( &ptrA->pcaDimSubSpaceE, memPtrA ); 328 memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA ); 329 memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA ); 330 331 for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memPtrA += bbf_featureMemWrite( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA ); 332 333 return memSizeL; 334} 335 336/* ------------------------------------------------------------------------- */ 337 338uint32 bbf_LocalScanDetector_memRead( struct bbs_Context* cpA, 339 struct bbf_LocalScanDetector* ptrA, 340 const uint16* memPtrA, 341 struct bbs_MemTbl* mtpA ) 342{ 343 uint32 iL; 344 uint32 memSizeL, versionL; 345 struct bbs_MemTbl memTblL = *mtpA; 346 struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 ); 347 struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 ); 348 if( bbs_Context_error( cpA ) ) return 0; 349 350 memPtrA += bbs_memRead32( &memSizeL, memPtrA ); 351 memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA ); 352 353 354 memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA ); 355 memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA ); 356 memPtrA += bbs_memRead32( &ptrA->scanWidthE, memPtrA ); 357 memPtrA += bbs_memRead32( &ptrA->scanHeightE, memPtrA ); 358 memPtrA += bbs_memRead32( &ptrA->scaleExpE, memPtrA ); 359 memPtrA += bbs_memRead32( &ptrA->interpolatedWarpingE, memPtrA ); 360 memPtrA += bbs_memRead32( &ptrA->warpScaleThresholdE, memPtrA ); 361 memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->refClusterE, memPtrA, espL ); 362 memPtrA += bts_Cluster2D_memRead( cpA, &ptrA->scanClusterE, memPtrA, espL ); 363 memPtrA += bbf_BitParam_memRead( cpA, &ptrA->bitParamE, memPtrA ); 364 memPtrA += bbs_memRead32( &ptrA->outlierDistanceE, memPtrA ); 365 memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->pcaClusterE, memPtrA, espL ); 366 memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaAvgE, memPtrA, espL ); 367 memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaMatE, memPtrA, espL ); 368 memPtrA += bbs_memRead32( &ptrA->pcaDimSubSpaceE, memPtrA ); 369 memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA ); 370 memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA ); 371 372 /* check features & allocate data buffer */ 373 { 374 const uint16* memPtrL = memPtrA; 375 uint32 dataSizeL = 0; 376 for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) 377 { 378 enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrL + 4 ); 379 dataSizeL += bbf_featureSizeOf16( cpA, typeL ); 380 memPtrL += bbs_memPeek32( memPtrL ); 381 } 382 bbs_UInt16Arr_create( cpA, &ptrA->ftrDataArrE, dataSizeL, espL ); 383 } 384 385 /* load features & initialize pointers */ 386 { 387 uint16* dataPtrL = ptrA->ftrDataArrE.arrPtrE; 388 for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) 389 { 390 enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrA + 4 ); 391 ptrA->ftrPtrArrE[ iL ] = ( struct bbf_Feature* )dataPtrL; 392 bbf_featureInit( cpA, ptrA->ftrPtrArrE[ iL ], typeL ); 393 memPtrA += bbf_featureMemRead( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA, &memTblL ); 394 dataPtrL += bbf_featureSizeOf16( cpA, typeL ); 395 } 396 } 397 398 if( memSizeL != bbf_LocalScanDetector_memSize( cpA, ptrA ) ) 399 { 400 bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n" 401 "size mismatch" ); 402 return 0; 403 } 404 405 if( ptrA->maxImageWidthE * ptrA->maxImageHeightE == 0 ) 406 { 407 bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n" 408 "maximum image width/height not set" ); 409 return 0; 410 } 411 412 /* initialize internal data */ 413 414 /* ought to be placed on shared memory later */ 415 bts_RBFMap2D_create( cpA, &ptrA->rbfMapE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 416 ptrA->rbfMapE.RBFTypeE = bts_RBF_LINEAR; 417 ptrA->rbfMapE.altTypeE = bts_ALT_RIGID; 418 419 bts_Cluster2D_create( cpA, &ptrA->tmpCluster1E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 420 bts_Cluster2D_create( cpA, &ptrA->tmpCluster2E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 421 bts_Cluster2D_create( cpA, &ptrA->tmpCluster3E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 422 bts_Cluster2D_create( cpA, &ptrA->tmpCluster4E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 423 424 bbs_Int32Arr_create( cpA, &ptrA->actArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 425 bbs_Int16Arr_create( cpA, &ptrA->idxArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); 426 427 /* working image memory */ 428 /* ought to be placed on shared memory later */ 429 bbs_UInt8Arr_create( cpA, &ptrA->workImageBufE, ptrA->maxImageWidthE * ptrA->maxImageHeightE, sspL ); 430 431 /* initialize local scanner (be aware of shared memory usage when moving this create function) */ 432 bbf_LocalScanner_create( cpA, &ptrA->scannerE, 433 ptrA->patchWidthE, 434 ptrA->patchHeightE, 435 ptrA->scaleExpE, 436 ptrA->maxImageWidthE, 437 ptrA->maxImageHeightE, 438 ptrA->scaleExpE, 439 ptrA->bitParamE.outerRadiusE, 440 &memTblL ); 441 442 return memSizeL; 443} 444 445/* ------------------------------------------------------------------------- */ 446 447/* ========================================================================= */ 448/* */ 449/* ---- \ghd{ exec functions } --------------------------------------------- */ 450/* */ 451/* ========================================================================= */ 452 453/* ------------------------------------------------------------------------- */ 454 455int32 bbf_LocalScanDetector_process( struct bbs_Context* cpA, 456 const struct bbf_LocalScanDetector* ptrA, 457 uint8* imagePtrA, 458 uint32 imageWidthA, 459 uint32 imageHeightA, 460 const struct bts_Int16Vec2D* offsPtrA, 461 const struct bts_IdCluster2D* inClusterPtrA, 462 struct bts_IdCluster2D* outClusterPtrA ) 463{ 464 bbs_DEF_fNameL( "bbf_LocalScanDetector_process" ) 465 466 int32 pw0L = ptrA->patchWidthE; 467 int32 ph0L = ptrA->patchHeightE; 468 int32 pw1L = pw0L << ptrA->scaleExpE; 469 int32 ph1L = ph0L << ptrA->scaleExpE; 470 471 struct bts_Cluster2D* wrkClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E; 472 struct bts_Cluster2D* refClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E; 473 struct bts_Cluster2D* dstClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster3E; 474 struct bts_Cluster2D* tmpClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster4E; 475 struct bts_RBFMap2D* rbfPtrL = ( struct bts_RBFMap2D* )&ptrA->rbfMapE; 476 struct bbf_LocalScanner* scnPtrL = ( struct bbf_LocalScanner* )&ptrA->scannerE; 477 478 int32* actArrL = ( int32* )ptrA->actArrE.arrPtrE; 479 int16* idxArrL = ( int16* )ptrA->idxArrE.arrPtrE; 480 481 uint32 workImageWidthL, workImageHeightL; 482 483 struct bts_Flt16Alt2D altL; 484 485 int32 confidenceL; 486 uint32 iL; 487 uint32 sizeL = ptrA->scanClusterE.sizeE; 488 489 if( sizeL > bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE ) 490 { 491 bbs_ERROR1( "%s:\nScan cluster size exceeds bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE", fNameL ); 492 return 0; 493 } 494 495 /* compute equivalent clusters (matching ids) from input and reference cluster */ 496 bts_IdCluster2D_convertToEqivalentClusters( cpA, inClusterPtrA, &ptrA->refClusterE, wrkClPtrL, refClPtrL ); 497 498 /* altL: orig image -> normalized image */ 499 altL = bts_Cluster2D_alt( cpA, wrkClPtrL, refClPtrL, bts_ALT_RIGID ); 500 501 /* transorm work cluster to normalized image */ 502 bts_Cluster2D_transformBbp( cpA, wrkClPtrL, altL, 6 ); 503 504 /* map: ref cluster -> work cluster */ 505 bts_RBFMap2D_compute( cpA, rbfPtrL, refClPtrL, wrkClPtrL ); 506 507 /* copy: scanClusterE -> work cluster */ 508 bts_Cluster2D_copy( cpA, wrkClPtrL, &ptrA->scanClusterE ); 509 510 /* copy: refClusterE -> ref cluster */ 511 bts_Cluster2D_copy( cpA, refClPtrL, &ptrA->refClusterE.clusterE ); 512 513 /* apply map to work cluster */ 514 bts_Cluster2D_rbfTransform( cpA, wrkClPtrL, rbfPtrL ); 515 516 /* apply map to ref cluster */ 517 bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL ); 518 519 { 520 /* analyze boundaries; get exact dimensions of working image */ 521 int32 workBorderWL = ( ( ptrA->scanWidthE + pw1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */ 522 int32 workBorderHL = ( ( ptrA->scanHeightE + ph1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */ 523 struct bts_Int16Rect workAreaL = bts_Cluster2D_boundingBox( cpA, wrkClPtrL ); 524 workAreaL.x1E = workAreaL.x1E >> wrkClPtrL->bbpE; 525 workAreaL.y1E = workAreaL.y1E >> wrkClPtrL->bbpE; 526 workAreaL.x2E = workAreaL.x2E >> wrkClPtrL->bbpE; 527 workAreaL.y2E = workAreaL.y2E >> wrkClPtrL->bbpE; 528 workAreaL.x1E -= workBorderWL; 529 workAreaL.y1E -= workBorderHL; 530 workAreaL.x2E += workBorderWL; 531 workAreaL.y2E += workBorderHL; 532 533 workImageWidthL = workAreaL.x2E - workAreaL.x1E; 534 workImageHeightL = workAreaL.y2E - workAreaL.y1E; 535 536 /* truncate if necessary (should not occur in normal operation) */ 537 workImageWidthL = workImageWidthL > ptrA->maxImageWidthE ? ptrA->maxImageWidthE : workImageWidthL; 538 workImageHeightL = workImageHeightL > ptrA->maxImageHeightE ? ptrA->maxImageHeightE : workImageHeightL; 539 540 /* adjust ALT */ 541 altL.vecE.xE -= workAreaL.x1E << altL.vecE.bbpE; 542 altL.vecE.yE -= workAreaL.y1E << altL.vecE.bbpE; 543 544 /* adjust work cluster */ 545 for( iL = 0; iL < wrkClPtrL->sizeE; iL++ ) 546 { 547 wrkClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << wrkClPtrL->bbpE; 548 wrkClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << wrkClPtrL->bbpE; 549 } 550 551 /* adjust ref cluster */ 552 for( iL = 0; iL < wrkClPtrL->sizeE; iL++ ) 553 { 554 refClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << refClPtrL->bbpE; 555 refClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << refClPtrL->bbpE; 556 } 557 558 /* transform image */ 559 bim_filterWarp( cpA, 560 ptrA->workImageBufE.arrPtrE, 561 imagePtrA, imageWidthA, imageHeightA, 562 offsPtrA, 563 &altL, 564 workImageWidthL, workImageHeightL, 565 NULL, 566 ptrA->warpScaleThresholdE, 567 ptrA->interpolatedWarpingE ); 568 569 } 570 571 /* scan over all positions of work cluster; target positions are stored in *dstClPtrL*/ 572 { 573 int32 regionWHL = ( ptrA->scanWidthE + pw1L + 1 ) >> 1; 574 int32 regionHHL = ( ptrA->scanHeightE + ph1L + 1 ) >> 1; 575 struct bts_Int16Vec2D* srcVecArrL = wrkClPtrL->vecArrE; 576 struct bts_Int16Vec2D* dstVecArrL = dstClPtrL->vecArrE; 577 int32 vecBbpL = wrkClPtrL->bbpE; 578 bts_Cluster2D_size( cpA, dstClPtrL, sizeL ); 579 dstClPtrL->bbpE = vecBbpL; 580 581 /* initialize scanner */ 582 scnPtrL->patchWidthE = ptrA->patchWidthE; 583 scnPtrL->patchHeightE = ptrA->patchWidthE; 584 scnPtrL->scaleExpE = ptrA->scaleExpE; 585 586 bbf_LocalScanner_assign( cpA, scnPtrL, ptrA->workImageBufE.arrPtrE, workImageWidthL, workImageHeightL, &ptrA->bitParamE ); 587 588 bbs_memset32( actArrL, 0x80000000, sizeL ); 589 590 do 591 { 592 for( iL = 0; iL < sizeL; iL++ ) 593 { 594 int32 bestActL = 0x80000000; 595 uint32 bestIdxL = 0; 596 struct bbf_Feature* ftrPtrL = ptrA->ftrPtrArrE[ iL ]; 597 598 /* set scan region */ 599 { 600 int32 x0L = ( ( wrkClPtrL->vecArrE[ iL ].xE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1; 601 int32 y0L = ( ( wrkClPtrL->vecArrE[ iL ].yE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1; 602 struct bts_Int16Rect scanRegionL = bts_Int16Rect_create( x0L - regionWHL, y0L - regionHHL, x0L + regionWHL, y0L + regionHHL ); 603 bbf_LocalScanner_origScanRegion( cpA, scnPtrL, &scanRegionL ); 604 } 605 606 do 607 { 608 int32 actL = ftrPtrL->vpActivityE( ftrPtrL, bbf_LocalScanner_getPatch( scnPtrL ) ); 609 610 if( actL > bestActL ) 611 { 612 bestActL = actL; 613 bestIdxL = bbf_LocalScanner_scanIndex( scnPtrL ); 614 } 615 } 616 while( bbf_LocalScanner_next( cpA, scnPtrL ) ); 617 618 { 619 int32 xL, yL; /* 16.16 */ 620 bbf_LocalScanner_idxPos( scnPtrL, bestIdxL, &xL, &yL ); 621 xL += pw1L << 15; 622 yL += ph1L << 15; 623 if( bestActL > actArrL[ iL ] ) 624 { 625 dstVecArrL[ iL ].xE = ( ( xL >> ( 15 - vecBbpL ) ) + 1 ) >> 1; 626 dstVecArrL[ iL ].yE = ( ( yL >> ( 15 - vecBbpL ) ) + 1 ) >> 1; 627 actArrL[ iL ] = bestActL; 628 } 629 } 630 } 631 } 632 while( bbf_LocalScanner_nextOffset( cpA, scnPtrL ) ); 633 634 /* outlier analysis: outliers are disabled by setting their similarity to -1 */ 635 if( ptrA->outlierDistanceE > 0 ) 636 { 637 /* altL: work cluster -> ref cluster */ 638 struct bts_Flt16Alt2D localAltL = bts_Cluster2D_alt( cpA, wrkClPtrL, dstClPtrL, bts_ALT_RIGID ); 639 640 /* squared distance 16.16 */ 641 uint32 dist2L = ( ptrA->outlierDistanceE >> 8 ) * ( ptrA->outlierDistanceE >> 8 ); 642 643 /* analyze deviations */ 644 for( iL = 0; iL < sizeL; iL++ ) 645 { 646 struct bts_Flt16Vec2D vecL = bts_Flt16Vec2D_create32( srcVecArrL[ iL ].xE, srcVecArrL[ iL ].yE, vecBbpL ); 647 uint32 dev2L; /* squared deviation 16.16 */ 648 vecL = bts_Flt16Alt2D_mapFlt( &localAltL, &vecL ); 649 vecL = bts_Flt16Vec2D_sub( vecL, bts_Flt16Vec2D_create32( dstVecArrL[ iL ].xE, dstVecArrL[ iL ].yE, vecBbpL ) ); 650 dev2L = bbs_convertU32( bts_Flt16Vec2D_norm2( &vecL ), vecL.bbpE << 1, 16 ); 651 if( dev2L > dist2L ) actArrL[ iL ] = 0xF0000000; 652 } 653 } 654 655 /* remove undetected positions but keep at least 1/2 best positions */ 656 { 657 flag sortedL; 658 659 /* bubble sort (no speed issue in this case) */ 660 for( iL = 0; iL < sizeL; iL++ ) idxArrL[ iL ] = iL; 661 662 do 663 { 664 sortedL = TRUE; 665 for( iL = 1; iL < sizeL; iL++ ) 666 { 667 if( actArrL[ idxArrL[ iL - 1 ] ] < actArrL[ idxArrL[ iL ] ] ) 668 { 669 int16 tmpL = idxArrL[ iL - 1 ]; 670 idxArrL[ iL - 1 ] = idxArrL[ iL ]; 671 idxArrL[ iL ] = tmpL; 672 sortedL = FALSE; 673 } 674 } 675 } 676 while( !sortedL ); 677 678 for( iL = ( sizeL >> 1 ); iL < sizeL && actArrL[ idxArrL[ iL ] ] >= 0; iL++ ); 679 680 { 681 uint32 subSizeL = iL; 682 683 /* reorder clusters */ 684 bts_Cluster2D_size( cpA, tmpClPtrL, subSizeL ); 685 { 686 struct bts_Int16Vec2D* tmpVecArrL = tmpClPtrL->vecArrE; 687 for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = srcVecArrL[ idxArrL[ iL ] ]; 688 for( iL = 0; iL < subSizeL; iL++ ) srcVecArrL[ iL ] = tmpVecArrL[ iL ]; 689 for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = dstVecArrL[ idxArrL[ iL ] ]; 690 for( iL = 0; iL < subSizeL; iL++ ) dstVecArrL[ iL ] = tmpVecArrL[ iL ]; 691 } 692 bts_Cluster2D_size( cpA, wrkClPtrL, subSizeL ); 693 bts_Cluster2D_size( cpA, dstClPtrL, subSizeL ); 694 } 695 } 696 697 /* compute confidence */ 698 { 699 int16* idxArrL = ptrA->idxArrE.arrPtrE; 700 int32* actArrL = ptrA->actArrE.arrPtrE; 701 int32 actSumL = 0; /* .20 */ 702 for( iL = 0; iL < sizeL; iL++ ) 703 { 704 float actL = ( actArrL[ idxArrL[ iL ] ] + 128 ) >> 8; 705 if( actL < 0 ) break; 706 actSumL += actL; 707 } 708 709 /* actSumL = average positive activity */ 710 actSumL = ( iL > 0 ) ? actSumL / iL : 0; 711 712 confidenceL = ( ( ( int32 )iL << 20 ) - ( ( ( int32 )1 << 20 ) - actSumL ) ) / sizeL; 713 714 /* adjust to 4.28 */ 715 confidenceL <<= 8; 716 } 717 718 } 719 720 /* map: wrkCluster -> dstCluster */ 721 bts_RBFMap2D_compute( cpA, rbfPtrL, wrkClPtrL, dstClPtrL ); 722 723 /* apply map to ref cluster */ 724 bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL ); 725 726 /* copy ref cluster to outCluster */ 727 bts_Cluster2D_copy( cpA, &outClusterPtrA->clusterE, refClPtrL ); 728 bbs_Int16Arr_copy( cpA, &outClusterPtrA->idArrE, &ptrA->refClusterE.idArrE ); 729 730 /* PCA Mapping */ 731 if( ptrA->pcaDimSubSpaceE > 0 ) 732 { 733 bbf_LocalScanDetector_pcaMap( cpA, ptrA, outClusterPtrA, outClusterPtrA ); 734 } 735 736 /* backtransform out cluster to original image */ 737 bts_Cluster2D_transformBbp( cpA, &outClusterPtrA->clusterE, bts_Flt16Alt2D_inverted( &altL ), inClusterPtrA->clusterE.bbpE ); 738 739 return confidenceL; 740} 741 742/* ------------------------------------------------------------------------- */ 743 744/* ========================================================================= */ 745 746