/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* ---- includes ----------------------------------------------------------- */ #include "b_BasicEm/Functions.h" #include "b_BasicEm/Math.h" #include "b_ImageEm/Functions.h" #include "b_BitFeatureEm/LocalScanDetector.h" /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ auxiliary functions } ---------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /** applies PCA mapping * Input and output clusters may be identical */ void bbf_LocalScanDetector_pcaMap( struct bbs_Context* cpA, const struct bbf_LocalScanDetector* ptrA, const struct bts_IdCluster2D* inClusterPtrA, struct bts_IdCluster2D* outClusterPtrA ) { bbs_DEF_fNameL( "bbf_LocalScanDetector_pcaMap" ) struct bts_Cluster2D* tmpCl1PtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E; struct bts_Cluster2D* tmpCl2PtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E; struct bts_RBFMap2D* rbfPtrL = ( struct bts_RBFMap2D* )&ptrA->rbfMapE; struct bts_Flt16Alt2D altL; uint32 outBbpL = inClusterPtrA->clusterE.bbpE; uint32 iL, jL; /* setup two equivalent clusters holding the essential (alt-free) moves to be handled by PCA */ bts_IdCluster2D_convertToEqivalentClusters( cpA, inClusterPtrA, &ptrA->pcaClusterE, tmpCl1PtrL, tmpCl2PtrL ); altL = bts_Cluster2D_alt( cpA, tmpCl1PtrL, tmpCl2PtrL, bts_ALT_RIGID ); bts_Cluster2D_transform( cpA, tmpCl1PtrL, altL ); bts_RBFMap2D_compute( cpA, rbfPtrL, tmpCl2PtrL, tmpCl1PtrL ); bts_RBFMap2D_mapCluster( cpA, rbfPtrL, &ptrA->pcaClusterE.clusterE, tmpCl1PtrL, 6/* ! */ ); /* PCA projection: cluster1 -> cluster1 */ { /* mat elements: 8.8 */ const int16* matPtrL = ptrA->pcaMatE.arrPtrE; /* same bbp as pca cluster */ const int16* avgPtrL = ptrA->pcaAvgE.arrPtrE; struct bts_Int16Vec2D* vecArrL = tmpCl1PtrL->vecArrE; /* projected vector */ int32 prjVecL[ bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM ]; /* width of matrix */ uint16 matWidthL = tmpCl1PtrL->sizeE * 2; if( ptrA->pcaDimSubSpaceE > bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM ) { bbs_ERROR1( "%s:\nbpi_RF_LANDMARKER_MAX_PCA_DIM exceeded", fNameL ); return; } /* forward trafo */ for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) { int32 sumL = 0; avgPtrL = ptrA->pcaAvgE.arrPtrE; for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ ) { sumL += matPtrL[ 0 ] * ( vecArrL[ jL ].xE - avgPtrL[ 0 ] ); sumL += matPtrL[ 1 ] * ( vecArrL[ jL ].yE - avgPtrL[ 1 ] ); avgPtrL += 2; matPtrL += 2; } prjVecL[ iL ] = ( sumL + 128 ) >> 8; } matPtrL = ptrA->pcaMatE.arrPtrE; avgPtrL = ptrA->pcaAvgE.arrPtrE; vecArrL = tmpCl1PtrL->vecArrE; /* backward trafo */ for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ ) { int32 sumL = 0; for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) { sumL += matPtrL[ iL * matWidthL + 0 ] * prjVecL[ iL ]; } vecArrL[ jL ].xE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 0 ]; sumL = 0; for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ ) { sumL += matPtrL[ iL * matWidthL + 1 ] * prjVecL[ iL ]; } vecArrL[ jL ].yE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 1 ]; matPtrL += 2; avgPtrL += 2; } } /* ALT backtransformation */ bts_IdCluster2D_copy( cpA, outClusterPtrA, &ptrA->pcaClusterE ); bts_Cluster2D_copyTransform( cpA, &outClusterPtrA->clusterE, tmpCl1PtrL, bts_Flt16Alt2D_inverted( &altL ), outBbpL ); } /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ constructor / destructor } ----------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ void bbf_LocalScanDetector_init( struct bbs_Context* cpA, struct bbf_LocalScanDetector* ptrA ) { bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) ); bts_RBFMap2D_init( cpA, &ptrA->rbfMapE ); bts_Cluster2D_init( cpA, &ptrA->tmpCluster1E ); bts_Cluster2D_init( cpA, &ptrA->tmpCluster2E ); bts_Cluster2D_init( cpA, &ptrA->tmpCluster3E ); bts_Cluster2D_init( cpA, &ptrA->tmpCluster4E ); bbf_LocalScanner_init( cpA, &ptrA->scannerE ); bbs_Int32Arr_init( cpA, &ptrA->actArrE ); bbs_Int16Arr_init( cpA, &ptrA->idxArrE ); bbs_UInt8Arr_init( cpA, &ptrA->workImageBufE ); ptrA->maxImageWidthE = 0; ptrA->maxImageHeightE = 0; ptrA->patchWidthE = 0; ptrA->patchHeightE = 0; ptrA->scanWidthE = 0; ptrA->scanHeightE = 0; ptrA->scaleExpE = 0; ptrA->interpolatedWarpingE = TRUE; ptrA->warpScaleThresholdE = 0; bts_IdCluster2D_init( cpA, &ptrA->refClusterE ); bts_Cluster2D_init( cpA, &ptrA->scanClusterE ); bbs_UInt16Arr_init( cpA, &ptrA->ftrDataArrE ); bbf_BitParam_init( cpA, &ptrA->bitParamE ); ptrA->outlierDistanceE = 0; bts_IdCluster2D_init( cpA, &ptrA->pcaClusterE ); bbs_Int16Arr_init( cpA, &ptrA->pcaAvgE ); bbs_Int16Arr_init( cpA, &ptrA->pcaMatE ); ptrA->pcaDimSubSpaceE = 0; ptrA->maxImageWidthE = 0; ptrA->maxImageHeightE = 0; } /* ------------------------------------------------------------------------- */ void bbf_LocalScanDetector_exit( struct bbs_Context* cpA, struct bbf_LocalScanDetector* ptrA ) { uint16 iL; for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) bbf_featureExit( cpA, ptrA->ftrPtrArrE[ iL ] ); bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) ); bts_RBFMap2D_exit( cpA, &ptrA->rbfMapE ); bts_Cluster2D_exit( cpA, &ptrA->tmpCluster1E ); bts_Cluster2D_exit( cpA, &ptrA->tmpCluster2E ); bts_Cluster2D_exit( cpA, &ptrA->tmpCluster3E ); bts_Cluster2D_exit( cpA, &ptrA->tmpCluster4E ); bbf_LocalScanner_exit( cpA, &ptrA->scannerE ); bbs_Int32Arr_exit( cpA, &ptrA->actArrE ); bbs_Int16Arr_exit( cpA, &ptrA->idxArrE ); bbs_UInt8Arr_exit( cpA, &ptrA->workImageBufE ); ptrA->maxImageWidthE = 0; ptrA->maxImageHeightE = 0; ptrA->patchWidthE = 0; ptrA->patchHeightE = 0; ptrA->scanWidthE = 0; ptrA->scanHeightE = 0; ptrA->scaleExpE = 0; ptrA->interpolatedWarpingE = TRUE; ptrA->warpScaleThresholdE = 0; bts_IdCluster2D_exit( cpA, &ptrA->refClusterE ); bts_Cluster2D_exit( cpA, &ptrA->scanClusterE ); bbs_UInt16Arr_exit( cpA, &ptrA->ftrDataArrE ); bbf_BitParam_exit( cpA, &ptrA->bitParamE ); ptrA->outlierDistanceE = 0; bts_IdCluster2D_exit( cpA, &ptrA->pcaClusterE ); bbs_Int16Arr_exit( cpA, &ptrA->pcaAvgE ); bbs_Int16Arr_exit( cpA, &ptrA->pcaMatE ); ptrA->pcaDimSubSpaceE = 0; ptrA->maxImageWidthE = 0; ptrA->maxImageHeightE = 0; } /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ operators } -------------------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ void bbf_LocalScanDetector_copy( struct bbs_Context* cpA, struct bbf_LocalScanDetector* ptrA, const struct bbf_LocalScanDetector* srcPtrA ) { bbs_ERROR0( "bbf_LocalScanDetector_copy:\n Function is not available" ); } /* ------------------------------------------------------------------------- */ flag bbf_LocalScanDetector_equal( struct bbs_Context* cpA, const struct bbf_LocalScanDetector* ptrA, const struct bbf_LocalScanDetector* srcPtrA ) { bbs_ERROR0( "bbf_LocalScanDetector_equal:\n Function is not available" ); return TRUE; } /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ query functions } -------------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ modify functions } ------------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ I/O } -------------------------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ uint32 bbf_LocalScanDetector_memSize( struct bbs_Context* cpA, const struct bbf_LocalScanDetector* ptrA ) { uint32 iL; uint32 memSizeL = bbs_SIZEOF16( uint32 ) + bbs_SIZEOF16( uint32 ); /* version */ memSizeL += bbs_SIZEOF16( ptrA->patchWidthE ); memSizeL += bbs_SIZEOF16( ptrA->patchHeightE ); memSizeL += bbs_SIZEOF16( ptrA->scanWidthE ); memSizeL += bbs_SIZEOF16( ptrA->scanHeightE ); memSizeL += bbs_SIZEOF16( ptrA->scaleExpE ); memSizeL += bbs_SIZEOF16( ptrA->interpolatedWarpingE ); memSizeL += bbs_SIZEOF16( ptrA->warpScaleThresholdE ); memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->refClusterE ); memSizeL += bts_Cluster2D_memSize( cpA, &ptrA->scanClusterE ); memSizeL += bbf_BitParam_memSize( cpA, &ptrA->bitParamE ); memSizeL += bbs_SIZEOF16( ptrA->outlierDistanceE ); memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->pcaClusterE ); memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaAvgE ); memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaMatE ); memSizeL += bbs_SIZEOF16( ptrA->pcaDimSubSpaceE ); memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE ); memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE ); for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memSizeL += bbf_featureMemSize( cpA, ptrA->ftrPtrArrE[ iL ] ); return memSizeL; } /* ------------------------------------------------------------------------- */ uint32 bbf_LocalScanDetector_memWrite( struct bbs_Context* cpA, const struct bbf_LocalScanDetector* ptrA, uint16* memPtrA ) { uint32 iL; uint32 memSizeL = bbf_LocalScanDetector_memSize( cpA, ptrA ); memPtrA += bbs_memWrite32( &memSizeL, memPtrA ); memPtrA += bbs_memWriteUInt32( bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->scanWidthE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->scanHeightE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->scaleExpE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->interpolatedWarpingE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->warpScaleThresholdE, memPtrA ); memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->refClusterE, memPtrA ); memPtrA += bts_Cluster2D_memWrite( cpA, &ptrA->scanClusterE, memPtrA ); memPtrA += bbf_BitParam_memWrite( cpA, &ptrA->bitParamE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->outlierDistanceE, memPtrA ); memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->pcaClusterE, memPtrA ); memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaAvgE, memPtrA ); memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaMatE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->pcaDimSubSpaceE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA ); memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA ); for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memPtrA += bbf_featureMemWrite( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA ); return memSizeL; } /* ------------------------------------------------------------------------- */ uint32 bbf_LocalScanDetector_memRead( struct bbs_Context* cpA, struct bbf_LocalScanDetector* ptrA, const uint16* memPtrA, struct bbs_MemTbl* mtpA ) { uint32 iL; uint32 memSizeL, versionL; struct bbs_MemTbl memTblL = *mtpA; struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 ); struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 ); if( bbs_Context_error( cpA ) ) return 0; memPtrA += bbs_memRead32( &memSizeL, memPtrA ); memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA ); memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->scanWidthE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->scanHeightE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->scaleExpE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->interpolatedWarpingE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->warpScaleThresholdE, memPtrA ); memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->refClusterE, memPtrA, espL ); memPtrA += bts_Cluster2D_memRead( cpA, &ptrA->scanClusterE, memPtrA, espL ); memPtrA += bbf_BitParam_memRead( cpA, &ptrA->bitParamE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->outlierDistanceE, memPtrA ); memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->pcaClusterE, memPtrA, espL ); memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaAvgE, memPtrA, espL ); memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaMatE, memPtrA, espL ); memPtrA += bbs_memRead32( &ptrA->pcaDimSubSpaceE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA ); memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA ); /* check features & allocate data buffer */ { const uint16* memPtrL = memPtrA; uint32 dataSizeL = 0; for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) { enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrL + 4 ); dataSizeL += bbf_featureSizeOf16( cpA, typeL ); memPtrL += bbs_memPeek32( memPtrL ); } bbs_UInt16Arr_create( cpA, &ptrA->ftrDataArrE, dataSizeL, espL ); } /* load features & initialize pointers */ { uint16* dataPtrL = ptrA->ftrDataArrE.arrPtrE; for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) { enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrA + 4 ); ptrA->ftrPtrArrE[ iL ] = ( struct bbf_Feature* )dataPtrL; bbf_featureInit( cpA, ptrA->ftrPtrArrE[ iL ], typeL ); memPtrA += bbf_featureMemRead( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA, &memTblL ); dataPtrL += bbf_featureSizeOf16( cpA, typeL ); } } if( memSizeL != bbf_LocalScanDetector_memSize( cpA, ptrA ) ) { bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n" "size mismatch" ); return 0; } if( ptrA->maxImageWidthE * ptrA->maxImageHeightE == 0 ) { bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n" "maximum image width/height not set" ); return 0; } /* initialize internal data */ /* ought to be placed on shared memory later */ bts_RBFMap2D_create( cpA, &ptrA->rbfMapE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); ptrA->rbfMapE.RBFTypeE = bts_RBF_LINEAR; ptrA->rbfMapE.altTypeE = bts_ALT_RIGID; bts_Cluster2D_create( cpA, &ptrA->tmpCluster1E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); bts_Cluster2D_create( cpA, &ptrA->tmpCluster2E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); bts_Cluster2D_create( cpA, &ptrA->tmpCluster3E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); bts_Cluster2D_create( cpA, &ptrA->tmpCluster4E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); bbs_Int32Arr_create( cpA, &ptrA->actArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); bbs_Int16Arr_create( cpA, &ptrA->idxArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL ); /* working image memory */ /* ought to be placed on shared memory later */ bbs_UInt8Arr_create( cpA, &ptrA->workImageBufE, ptrA->maxImageWidthE * ptrA->maxImageHeightE, sspL ); /* initialize local scanner (be aware of shared memory usage when moving this create function) */ bbf_LocalScanner_create( cpA, &ptrA->scannerE, ptrA->patchWidthE, ptrA->patchHeightE, ptrA->scaleExpE, ptrA->maxImageWidthE, ptrA->maxImageHeightE, ptrA->scaleExpE, ptrA->bitParamE.outerRadiusE, &memTblL ); return memSizeL; } /* ------------------------------------------------------------------------- */ /* ========================================================================= */ /* */ /* ---- \ghd{ exec functions } --------------------------------------------- */ /* */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ int32 bbf_LocalScanDetector_process( struct bbs_Context* cpA, const struct bbf_LocalScanDetector* ptrA, uint8* imagePtrA, uint32 imageWidthA, uint32 imageHeightA, const struct bts_Int16Vec2D* offsPtrA, const struct bts_IdCluster2D* inClusterPtrA, struct bts_IdCluster2D* outClusterPtrA ) { bbs_DEF_fNameL( "bbf_LocalScanDetector_process" ) int32 pw0L = ptrA->patchWidthE; int32 ph0L = ptrA->patchHeightE; int32 pw1L = pw0L << ptrA->scaleExpE; int32 ph1L = ph0L << ptrA->scaleExpE; struct bts_Cluster2D* wrkClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E; struct bts_Cluster2D* refClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E; struct bts_Cluster2D* dstClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster3E; struct bts_Cluster2D* tmpClPtrL = ( struct bts_Cluster2D* )&ptrA->tmpCluster4E; struct bts_RBFMap2D* rbfPtrL = ( struct bts_RBFMap2D* )&ptrA->rbfMapE; struct bbf_LocalScanner* scnPtrL = ( struct bbf_LocalScanner* )&ptrA->scannerE; int32* actArrL = ( int32* )ptrA->actArrE.arrPtrE; int16* idxArrL = ( int16* )ptrA->idxArrE.arrPtrE; uint32 workImageWidthL, workImageHeightL; struct bts_Flt16Alt2D altL; int32 confidenceL; uint32 iL; uint32 sizeL = ptrA->scanClusterE.sizeE; if( sizeL > bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE ) { bbs_ERROR1( "%s:\nScan cluster size exceeds bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE", fNameL ); return 0; } /* compute equivalent clusters (matching ids) from input and reference cluster */ bts_IdCluster2D_convertToEqivalentClusters( cpA, inClusterPtrA, &ptrA->refClusterE, wrkClPtrL, refClPtrL ); /* altL: orig image -> normalized image */ altL = bts_Cluster2D_alt( cpA, wrkClPtrL, refClPtrL, bts_ALT_RIGID ); /* transorm work cluster to normalized image */ bts_Cluster2D_transformBbp( cpA, wrkClPtrL, altL, 6 ); /* map: ref cluster -> work cluster */ bts_RBFMap2D_compute( cpA, rbfPtrL, refClPtrL, wrkClPtrL ); /* copy: scanClusterE -> work cluster */ bts_Cluster2D_copy( cpA, wrkClPtrL, &ptrA->scanClusterE ); /* copy: refClusterE -> ref cluster */ bts_Cluster2D_copy( cpA, refClPtrL, &ptrA->refClusterE.clusterE ); /* apply map to work cluster */ bts_Cluster2D_rbfTransform( cpA, wrkClPtrL, rbfPtrL ); /* apply map to ref cluster */ bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL ); { /* analyze boundaries; get exact dimensions of working image */ int32 workBorderWL = ( ( ptrA->scanWidthE + pw1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */ int32 workBorderHL = ( ( ptrA->scanHeightE + ph1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */ struct bts_Int16Rect workAreaL = bts_Cluster2D_boundingBox( cpA, wrkClPtrL ); workAreaL.x1E = workAreaL.x1E >> wrkClPtrL->bbpE; workAreaL.y1E = workAreaL.y1E >> wrkClPtrL->bbpE; workAreaL.x2E = workAreaL.x2E >> wrkClPtrL->bbpE; workAreaL.y2E = workAreaL.y2E >> wrkClPtrL->bbpE; workAreaL.x1E -= workBorderWL; workAreaL.y1E -= workBorderHL; workAreaL.x2E += workBorderWL; workAreaL.y2E += workBorderHL; workImageWidthL = workAreaL.x2E - workAreaL.x1E; workImageHeightL = workAreaL.y2E - workAreaL.y1E; /* truncate if necessary (should not occur in normal operation) */ workImageWidthL = workImageWidthL > ptrA->maxImageWidthE ? ptrA->maxImageWidthE : workImageWidthL; workImageHeightL = workImageHeightL > ptrA->maxImageHeightE ? ptrA->maxImageHeightE : workImageHeightL; /* adjust ALT */ altL.vecE.xE -= workAreaL.x1E << altL.vecE.bbpE; altL.vecE.yE -= workAreaL.y1E << altL.vecE.bbpE; /* adjust work cluster */ for( iL = 0; iL < wrkClPtrL->sizeE; iL++ ) { wrkClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << wrkClPtrL->bbpE; wrkClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << wrkClPtrL->bbpE; } /* adjust ref cluster */ for( iL = 0; iL < wrkClPtrL->sizeE; iL++ ) { refClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << refClPtrL->bbpE; refClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << refClPtrL->bbpE; } /* transform image */ bim_filterWarp( cpA, ptrA->workImageBufE.arrPtrE, imagePtrA, imageWidthA, imageHeightA, offsPtrA, &altL, workImageWidthL, workImageHeightL, NULL, ptrA->warpScaleThresholdE, ptrA->interpolatedWarpingE ); } /* scan over all positions of work cluster; target positions are stored in *dstClPtrL*/ { int32 regionWHL = ( ptrA->scanWidthE + pw1L + 1 ) >> 1; int32 regionHHL = ( ptrA->scanHeightE + ph1L + 1 ) >> 1; struct bts_Int16Vec2D* srcVecArrL = wrkClPtrL->vecArrE; struct bts_Int16Vec2D* dstVecArrL = dstClPtrL->vecArrE; int32 vecBbpL = wrkClPtrL->bbpE; bts_Cluster2D_size( cpA, dstClPtrL, sizeL ); dstClPtrL->bbpE = vecBbpL; /* initialize scanner */ scnPtrL->patchWidthE = ptrA->patchWidthE; scnPtrL->patchHeightE = ptrA->patchWidthE; scnPtrL->scaleExpE = ptrA->scaleExpE; bbf_LocalScanner_assign( cpA, scnPtrL, ptrA->workImageBufE.arrPtrE, workImageWidthL, workImageHeightL, &ptrA->bitParamE ); bbs_memset32( actArrL, 0x80000000, sizeL ); do { for( iL = 0; iL < sizeL; iL++ ) { int32 bestActL = 0x80000000; uint32 bestIdxL = 0; struct bbf_Feature* ftrPtrL = ptrA->ftrPtrArrE[ iL ]; /* set scan region */ { int32 x0L = ( ( wrkClPtrL->vecArrE[ iL ].xE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1; int32 y0L = ( ( wrkClPtrL->vecArrE[ iL ].yE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1; struct bts_Int16Rect scanRegionL = bts_Int16Rect_create( x0L - regionWHL, y0L - regionHHL, x0L + regionWHL, y0L + regionHHL ); bbf_LocalScanner_origScanRegion( cpA, scnPtrL, &scanRegionL ); } do { int32 actL = ftrPtrL->vpActivityE( ftrPtrL, bbf_LocalScanner_getPatch( scnPtrL ) ); if( actL > bestActL ) { bestActL = actL; bestIdxL = bbf_LocalScanner_scanIndex( scnPtrL ); } } while( bbf_LocalScanner_next( cpA, scnPtrL ) ); { int32 xL, yL; /* 16.16 */ bbf_LocalScanner_idxPos( scnPtrL, bestIdxL, &xL, &yL ); xL += pw1L << 15; yL += ph1L << 15; if( bestActL > actArrL[ iL ] ) { dstVecArrL[ iL ].xE = ( ( xL >> ( 15 - vecBbpL ) ) + 1 ) >> 1; dstVecArrL[ iL ].yE = ( ( yL >> ( 15 - vecBbpL ) ) + 1 ) >> 1; actArrL[ iL ] = bestActL; } } } } while( bbf_LocalScanner_nextOffset( cpA, scnPtrL ) ); /* outlier analysis: outliers are disabled by setting their similarity to -1 */ if( ptrA->outlierDistanceE > 0 ) { /* altL: work cluster -> ref cluster */ struct bts_Flt16Alt2D localAltL = bts_Cluster2D_alt( cpA, wrkClPtrL, dstClPtrL, bts_ALT_RIGID ); /* squared distance 16.16 */ uint32 dist2L = ( ptrA->outlierDistanceE >> 8 ) * ( ptrA->outlierDistanceE >> 8 ); /* analyze deviations */ for( iL = 0; iL < sizeL; iL++ ) { struct bts_Flt16Vec2D vecL = bts_Flt16Vec2D_create32( srcVecArrL[ iL ].xE, srcVecArrL[ iL ].yE, vecBbpL ); uint32 dev2L; /* squared deviation 16.16 */ vecL = bts_Flt16Alt2D_mapFlt( &localAltL, &vecL ); vecL = bts_Flt16Vec2D_sub( vecL, bts_Flt16Vec2D_create32( dstVecArrL[ iL ].xE, dstVecArrL[ iL ].yE, vecBbpL ) ); dev2L = bbs_convertU32( bts_Flt16Vec2D_norm2( &vecL ), vecL.bbpE << 1, 16 ); if( dev2L > dist2L ) actArrL[ iL ] = 0xF0000000; } } /* remove undetected positions but keep at least 1/2 best positions */ { flag sortedL; /* bubble sort (no speed issue in this case) */ for( iL = 0; iL < sizeL; iL++ ) idxArrL[ iL ] = iL; do { sortedL = TRUE; for( iL = 1; iL < sizeL; iL++ ) { if( actArrL[ idxArrL[ iL - 1 ] ] < actArrL[ idxArrL[ iL ] ] ) { int16 tmpL = idxArrL[ iL - 1 ]; idxArrL[ iL - 1 ] = idxArrL[ iL ]; idxArrL[ iL ] = tmpL; sortedL = FALSE; } } } while( !sortedL ); for( iL = ( sizeL >> 1 ); iL < sizeL && actArrL[ idxArrL[ iL ] ] >= 0; iL++ ) ; { uint32 subSizeL = iL; /* reorder clusters */ bts_Cluster2D_size( cpA, tmpClPtrL, subSizeL ); { struct bts_Int16Vec2D* tmpVecArrL = tmpClPtrL->vecArrE; for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = srcVecArrL[ idxArrL[ iL ] ]; for( iL = 0; iL < subSizeL; iL++ ) srcVecArrL[ iL ] = tmpVecArrL[ iL ]; for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = dstVecArrL[ idxArrL[ iL ] ]; for( iL = 0; iL < subSizeL; iL++ ) dstVecArrL[ iL ] = tmpVecArrL[ iL ]; } bts_Cluster2D_size( cpA, wrkClPtrL, subSizeL ); bts_Cluster2D_size( cpA, dstClPtrL, subSizeL ); } } /* compute confidence */ { int16* idxArrL = ptrA->idxArrE.arrPtrE; int32* actArrL = ptrA->actArrE.arrPtrE; int32 actSumL = 0; /* .20 */ for( iL = 0; iL < sizeL; iL++ ) { float actL = ( actArrL[ idxArrL[ iL ] ] + 128 ) >> 8; if( actL < 0 ) break; actSumL += actL; } /* actSumL = average positive activity */ actSumL = ( iL > 0 ) ? actSumL / iL : 0; confidenceL = ( ( ( int32 )iL << 20 ) - ( ( ( int32 )1 << 20 ) - actSumL ) ) / sizeL; /* adjust to 4.28 */ confidenceL <<= 8; } } /* map: wrkCluster -> dstCluster */ bts_RBFMap2D_compute( cpA, rbfPtrL, wrkClPtrL, dstClPtrL ); /* apply map to ref cluster */ bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL ); /* copy ref cluster to outCluster */ bts_Cluster2D_copy( cpA, &outClusterPtrA->clusterE, refClPtrL ); bbs_Int16Arr_copy( cpA, &outClusterPtrA->idArrE, &ptrA->refClusterE.idArrE ); /* PCA Mapping */ if( ptrA->pcaDimSubSpaceE > 0 ) { bbf_LocalScanDetector_pcaMap( cpA, ptrA, outClusterPtrA, outClusterPtrA ); } /* backtransform out cluster to original image */ bts_Cluster2D_transformBbp( cpA, &outClusterPtrA->clusterE, bts_Flt16Alt2D_inverted( &altL ), inClusterPtrA->clusterE.bbpE ); return confidenceL; } /* ------------------------------------------------------------------------- */ /* ========================================================================= */