auto import from //depot/cupcake/@135843
diff --git a/Embedded/common/src/b_BitFeatureEm/LocalScanDetector.c b/Embedded/common/src/b_BitFeatureEm/LocalScanDetector.c
new file mode 100644
index 0000000..880dba3
--- /dev/null
+++ b/Embedded/common/src/b_BitFeatureEm/LocalScanDetector.c
@@ -0,0 +1,745 @@
+/*
+ * 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;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* ========================================================================= */
+