text: /*
   * 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_BitFeatureEm/ScanDetector.h"
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ auxiliary functions } ---------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ constructor / destructor } ----------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  
  void bbf_ScanDetector_init( struct bbs_Context* cpA,
  						    struct bbf_ScanDetector* ptrA )
  {
  	uint32 iL;
  
  	ptrA->minScaleE = 0;
  	ptrA->maxScaleE = 0;
  	ptrA->maxImageWidthE = 0;
  	ptrA->maxImageHeightE = 0;
  	bbf_Scanner_init( cpA, &ptrA->scannerE );
  
  	ptrA->patchWidthE = 0;
  	ptrA->patchHeightE = 0;
  	ptrA->minDefScaleE = 0;
  	ptrA->maxDefScaleE = 0;
  	ptrA->scaleStepE = 0;
  	ptrA->overlapThrE = 0;
  	ptrA->borderWidthE = 0;
  	ptrA->borderHeightE = 0;
  	ptrA->featuresE = 0;
  	for( iL = 0; iL < bbf_SCAN_DETECTOR_MAX_FEATURES; iL++ ) bbf_BitParam_init( cpA, &ptrA->bitParamArrE[ iL ] );
  	for( iL = 0; iL < bbf_SCAN_DETECTOR_MAX_FEATURES; iL++ ) bbf_Sequence_init( cpA, &ptrA->featureArrE[ iL ] );
  	bts_IdCluster2D_init( cpA, &ptrA->refClusterE );
  	ptrA->refDistanceE = 10;
  }
  
  /* ------------------------------------------------------------------------- */
  
  void bbf_ScanDetector_exit( struct bbs_Context* cpA,
  						    struct bbf_ScanDetector* ptrA )
  {
  	uint32 iL;
  
  	ptrA->minScaleE = 0;
  	ptrA->maxScaleE = 0;
  	ptrA->maxImageWidthE = 0;
  	ptrA->maxImageHeightE = 0;
  	bbf_Scanner_exit( cpA, &ptrA->scannerE );
  
  	ptrA->patchWidthE = 0;
  	ptrA->patchHeightE = 0;
  	ptrA->minDefScaleE = 0;
  	ptrA->maxDefScaleE = 0;
  	ptrA->scaleStepE = 0;
  	ptrA->overlapThrE = 0;
  	ptrA->borderWidthE = 0;
  	ptrA->borderHeightE = 0;
  	ptrA->featuresE = 0;
  	for( iL = 0; iL < bbf_SCAN_DETECTOR_MAX_FEATURES; iL++ ) bbf_BitParam_exit( cpA, &ptrA->bitParamArrE[ iL ] );
  	for( iL = 0; iL < bbf_SCAN_DETECTOR_MAX_FEATURES; iL++ ) bbf_Sequence_exit( cpA, &ptrA->featureArrE[ iL ] );
  	bts_IdCluster2D_exit( cpA, &ptrA->refClusterE );
  	ptrA->refDistanceE = 0;
  }
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ operators } -------------------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  
  void bbf_ScanDetector_copy( struct bbs_Context* cpA,
  						    struct bbf_ScanDetector* ptrA, 
  						    const struct bbf_ScanDetector* srcPtrA )
  {
  	bbs_ERROR0( "bbf_ScanDetector_copy:\n Function is not available" );
  }
  
  /* ------------------------------------------------------------------------- */
  
  flag bbf_ScanDetector_equal( struct bbs_Context* cpA,
  						     const struct bbf_ScanDetector* ptrA, 
  						     const struct bbf_ScanDetector* srcPtrA )
  {
  	bbs_ERROR0( "bbf_ScanDetector_equal:\n Function is not available" );
  	return TRUE;
  }
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ query functions } -------------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ modify functions } ------------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  	
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ I/O } -------------------------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  
  /* ------------------------------------------------------------------------- */
  	
  uint32 bbf_ScanDetector_memSize( struct bbs_Context* cpA,
  							     const struct bbf_ScanDetector* 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->minDefScaleE );
  	memSizeL += bbs_SIZEOF16( ptrA->maxDefScaleE );
  	memSizeL += bbs_SIZEOF16( ptrA->scaleStepE );
  	memSizeL += bbs_SIZEOF16( ptrA->overlapThrE );
  	memSizeL += bbs_SIZEOF16( ptrA->borderWidthE );
  	memSizeL += bbs_SIZEOF16( ptrA->borderHeightE );
  	memSizeL += bbs_SIZEOF16( ptrA->featuresE );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memSizeL += bbf_BitParam_memSize( cpA, &ptrA->bitParamArrE[ iL ] );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memSizeL += bbf_Sequence_memSize( cpA, &ptrA->featureArrE[ iL ] );
  	memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->refClusterE );
  	memSizeL += bbs_SIZEOF16( ptrA->refDistanceE );
  
  	return memSizeL; 
  }
  
  /* ------------------------------------------------------------------------- */
  	
  uint32 bbf_ScanDetector_memWrite( struct bbs_Context* cpA,
  							      const struct bbf_ScanDetector* ptrA, 
  								  uint16* memPtrA )
  {
  	uint32 iL;
  	uint32 memSizeL = bbf_ScanDetector_memSize( cpA, ptrA );
  	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
  	memPtrA += bbs_memWriteUInt32( bbf_SCAN_DETECTOR_VERSION, memPtrA );
  
  	memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->minDefScaleE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->maxDefScaleE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->scaleStepE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->overlapThrE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->borderWidthE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->borderHeightE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->featuresE, memPtrA );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memPtrA += bbf_BitParam_memWrite( cpA, &ptrA->bitParamArrE[ iL ], memPtrA );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memPtrA += bbf_Sequence_memWrite( cpA, &ptrA->featureArrE[ iL ], memPtrA );
  	memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->refClusterE, memPtrA );
  	memPtrA += bbs_memWrite32( &ptrA->refDistanceE, memPtrA );
  
  	return memSizeL;
  }
  
  /* ------------------------------------------------------------------------- */
  
  uint32 bbf_ScanDetector_memRead( struct bbs_Context* cpA,
  							     struct bbf_ScanDetector* ptrA, 
  							     const uint16* memPtrA, 
  							     struct bbs_MemTbl* mtpA )
  {
  	bbs_DEF_fNameL( "bbf_ScanDetector_memRead" )
  
  	/* debugging hint: set this flag to FALSE when you suspect a shared memory conflict */
  	const flag maximizeSharedMemoryL = TRUE;
  
  	uint32 iL;
  	uint32 memSizeL, versionL;
  	struct bbs_MemTbl memTblL = *mtpA;
  	struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 );
  	if( bbs_Context_error( cpA ) ) return 0;
  
  	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
  	memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_SCAN_DETECTOR_VERSION, memPtrA );
  
  	memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->minDefScaleE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->maxDefScaleE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->scaleStepE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->overlapThrE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->borderWidthE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->borderHeightE, memPtrA );
  	memPtrA += bbs_memRead32( &ptrA->featuresE, memPtrA );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memPtrA += bbf_BitParam_memRead( cpA, &ptrA->bitParamArrE[ iL ], memPtrA );
  	for( iL = 0; iL < ptrA->featuresE; iL++ ) memPtrA += bbf_Sequence_memRead( cpA, &ptrA->featureArrE[ iL ], memPtrA, &memTblL );
  	memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->refClusterE, memPtrA, espL );
  	memPtrA += bbs_memRead32( &ptrA->refDistanceE, memPtrA );
  /*
  	if( memSizeL != bbf_ScanDetector_memSize( cpA, ptrA ) )
  	{
  		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_ScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
  			        "size mismatch" );
  		return 0;
  	}
  */
  
  	ptrA->minScaleE = ptrA->minDefScaleE;
  	ptrA->maxScaleE = ptrA->maxDefScaleE;
  
  	/* initialize scanner; be aware of shared memory settings(!) */
  	{
  		uint32 maxImageSizeL = ptrA->maxImageWidthE * ptrA->maxImageHeightE;
  
  		/* estimate of maximal possible faces in image */
  		uint32 maxFacesL = maxImageSizeL / ( 768 << 1 );
  
  		uint32 maxRadiusL = 0;
  
  		if( maxImageSizeL == 0 ) 
  		{
  			bbs_ERROR1( "%s:\nMaximum image size was not defined (size variables must be set before calling _memRead)", fNameL );
  			return memSizeL; 
  		}
  
  		for( iL = 0; iL < ptrA->featuresE; iL++ ) 
  		{
  			maxRadiusL = maxRadiusL > ptrA->bitParamArrE[ iL ].outerRadiusE ? maxRadiusL : ptrA->bitParamArrE[ iL ].outerRadiusE;
  		}
  
  		if( maxFacesL < 1 ) maxFacesL = 1;
  
  		bbf_Scanner_create( cpA, &ptrA->scannerE, 
  							maximizeSharedMemoryL,
  							ptrA->maxImageWidthE,
  							ptrA->maxImageHeightE,
  							maxRadiusL, 
  							ptrA->patchWidthE,
  							ptrA->patchHeightE,
  							ptrA->minScaleE,
  							ptrA->maxScaleE,
  							ptrA->scaleStepE,
  							ptrA->borderWidthE,
  							ptrA->borderHeightE,
  							maxFacesL * 20,  /* bufferSizeA */
  							&memTblL );
  	}
  
  	return memSizeL;
  }
  
  /* ------------------------------------------------------------------------- */
  	
  /* ========================================================================= */
  /*                                                                           */
  /* ---- \ghd{ exec functions } --------------------------------------------- */
  /*                                                                           */
  /* ========================================================================= */
  	
  /* ------------------------------------------------------------------------- */
  
  uint32 bbf_ScanDetector_process( struct bbs_Context* cpA, 
  							     struct bbf_ScanDetector* ptrA,
  							     const void* imagePtrA,
  								 uint32 imageWidthA,
  								 uint32 imageHeightA,
  								 const struct bts_Int16Rect* roiPtrA,
  								 int32** outArrPtrPtrA )
  {
  	/* best global values (used when no positives could be found) */
  	int32 bestGlobalActL = ( int32 )0x80000000;
  	int32 bestGlobalXL = 0;
  	int32 bestGlobalYL = 0;
  	uint32 bestGlobalScaleL = 0;
  
  	struct bbf_Scanner* scannerPtrL = &ptrA->scannerE;
  
  	scannerPtrL->minScaleE = ptrA->minScaleE;
  	scannerPtrL->maxScaleE = ptrA->maxScaleE;
  
  	*outArrPtrPtrA = NULL;
  
  	if( bbs_Context_error( cpA ) ) return 0;
  	if( ptrA->featuresE == 0 )
  	{
  		bbs_ERROR0( "bbf_ScanDetector_process: detector has no features" );
  		return 0;
  	}
  
  	if( imageWidthA > ptrA->maxImageWidthE || imageHeightA > ptrA->maxImageHeightE )
  	{
  		bbs_ERROR0( "bbf_ScanDetector_process: images size exceeds preallocated size" );
  		return 0;
  	}
  
  	/* resets output positions */
  	bbf_Scanner_resetOutPos( cpA, scannerPtrL ); 
  
  	/* assign image to scanner - reset scanner */
  	bbf_Scanner_assign( cpA, scannerPtrL, imagePtrA, imageWidthA, imageHeightA, roiPtrA, &ptrA->bitParamArrE[ 0 ] );
  
  	while( bbf_Scanner_positions( scannerPtrL ) > 0 )
  	{
  		int32 bestActL = ( int32 )0x80000000;
  		uint32 bestIdxL = 0;
  		uint32 bestLvlL = 0;
  		uint32 iL;
  
  		const struct bbf_Feature* featurePtrL = ( const struct bbf_Feature* )&ptrA->featureArrE[ 0 ];
  		const struct bbf_BitParam* paramPtrL = &ptrA->bitParamArrE[ 0 ];
  		bbf_Scanner_bitParam( cpA, scannerPtrL, paramPtrL );
  
  		/* resets internal positions */
  		bbf_Scanner_resetIntPos( cpA, scannerPtrL );
  
  		do
  		{
  			int32 actL = featurePtrL->vpActivityE( featurePtrL, bbf_Scanner_getPatch( scannerPtrL ) );
  			if( actL > 0 ) 
  			{
  				bbf_Scanner_addIntPos( cpA, scannerPtrL, bbf_Scanner_scanIndex( scannerPtrL ), actL );
  			}
  			
  			if( actL > bestActL )
  			{
  				bestActL = actL;
  				bestIdxL = bbf_Scanner_scanIndex( scannerPtrL );
  			}
  		}
  		while( bbf_Scanner_next( cpA, scannerPtrL ) );
  
  		for( iL = 1; iL < ptrA->featuresE; iL++ )
  		{
  			const struct bbf_Feature* featurePtrL = ( const struct bbf_Feature* )&ptrA->featureArrE[ iL ];
  			const struct bbf_BitParam* paramPtrL = &ptrA->bitParamArrE[ iL ];
  			uint32* idxArrL = scannerPtrL->idxArrE.arrPtrE;
  			int32* actArrL = scannerPtrL->actArrE.arrPtrE;
  
  			uint32 kL = 0;
  			uint32 jL;
  
  			if( scannerPtrL->intCountE == 0 ) break;
  			bestActL = ( int32 )0x80000000;
  			bbf_Scanner_bitParam( cpA, scannerPtrL, paramPtrL );
  
  			for( jL = 0; jL < scannerPtrL->intCountE; jL++ )
  			{
  				int32 actL;
  				bbf_Scanner_goToIndex( cpA, scannerPtrL, idxArrL[ jL ] );
  				actL = featurePtrL->vpActivityE( featurePtrL, bbf_Scanner_getPatch( scannerPtrL ) );
  				if( actL > 0 )
  				{
  					idxArrL[ kL ] = idxArrL[ jL ];
  					actArrL[ kL ] = ( actArrL[ jL ] + actL ) >> 1;
  					kL++;
  				}
  
  				if( actL > bestActL )
  				{
  					bestActL = actL;
  					bestIdxL = idxArrL[ jL ];
  					bestLvlL = iL;
  				}
  			}
  
  			scannerPtrL->intCountE = kL;
  		}
  
  		if( scannerPtrL->intCountE == 0 )
  		{
  			int32 xL, yL;
  			uint32 scaleL;
  
  			/* 8.24 */
  			int32 actL = ( bestActL >> 4 ) + ( ( ( int32 )( bestLvlL + 1 - ptrA->featuresE ) << 24 ) / ( int32 )ptrA->featuresE );
  
  			/* 4.28 */
  			actL <<= 4;
  
  			bbf_Scanner_idxPos( scannerPtrL, bestIdxL, &xL, &yL, &scaleL );
  
  			if( actL > bestGlobalActL )
  			{
              	bestGlobalActL = actL;
  				bestGlobalXL = xL;
  				bestGlobalYL = yL;
  				bestGlobalScaleL = scaleL;
  			}
  		}
  		else
  		{
  			/* remove overlaps for current scale */
  			bbf_Scanner_removeIntOverlaps( cpA, scannerPtrL, ptrA->overlapThrE );
  
  			for( iL = 0; iL < scannerPtrL->intCountE; iL++ )
  			{
  				int32 xL, yL;
  				uint32 scaleL;
  				uint32* idxArrL = scannerPtrL->idxArrE.arrPtrE;
  				int32* actArrL = scannerPtrL->actArrE.arrPtrE;
  
  				int32 actL = actArrL[ iL ];
  				bbf_Scanner_idxPos( scannerPtrL, idxArrL[ iL ], &xL, &yL, &scaleL );
  
  				/* add external position */
  				bbf_Scanner_addOutPos( cpA, scannerPtrL, xL, yL, scaleL, actL ); 
  			}
  
  			/* remove overlapping positions */
  			bbf_Scanner_removeOutOverlaps( cpA, scannerPtrL, ptrA->overlapThrE ); 
  
  		}
  
  		if( !bbf_Scanner_nextScale( cpA, scannerPtrL ) ) break;
  	}
  /*
  	{
  		uint32 iL;
  		printf( "\n-----------------------------------------------" );
  		for( iL = 0; iL < scannerPtrL->outCountE; iL++ )
  		{
  			printf( "\n%02i: %6.1f %6.1f %6.2f %6.3f", 
  					iL,
  					( float )scannerPtrL->outArrE.arrPtrE[ iL * 4 + 0 ] / ( 1L << 16 ),
  					( float )scannerPtrL->outArrE.arrPtrE[ iL * 4 + 1 ] / ( 1L << 16 ),
  					( float )scannerPtrL->outArrE.arrPtrE[ iL * 4 + 2 ] / ( 1L << 20 ),
  					( float )scannerPtrL->outArrE.arrPtrE[ iL * 4 + 3 ] / ( 1L << 28 ) );
  
  		}
  	}
  */
  
  	*outArrPtrPtrA = scannerPtrL->outArrE.arrPtrE;
  	if( scannerPtrL->outCountE == 0 )
  	{
  		/* no positive activities found: store best negative activity */
  		bbf_Scanner_addOutPos( cpA, scannerPtrL, bestGlobalXL, bestGlobalYL, bestGlobalScaleL, bestGlobalActL );
  		return 0;
  	}
  	else
  	{
  		return scannerPtrL->outCountE;
  	}
  }
  
  /* ------------------------------------------------------------------------- */
  
  /* ========================================================================= */
  
  