| /* |
| * 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_APIEm/BFFaceFinder.h" |
| #include "b_APIEm/Functions.h" |
| #include "b_APIEm/DCR.h" |
| #include "b_BasicEm/Functions.h" |
| #include "b_BasicEm/Math.h" |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ auxiliary functions } ---------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ constructor / destructor } ----------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_init( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA ) |
| { |
| bpi_FaceFinder_init( cpA, &ptrA->baseE ); |
| ptrA->baseE.typeE = ( uint32 )bpi_FF_BF_FACE_FINDER; |
| ptrA->baseE.vpSetParamsE = bpi_BFFaceFinder_setParams; |
| ptrA->baseE.vpSetRangeE = bpi_BFFaceFinder_setRange; |
| ptrA->baseE.vpProcessE = bpi_BFFaceFinder_processDcr; |
| ptrA->baseE.vpPutDcrE = bpi_BFFaceFinder_putDcr; |
| ptrA->baseE.vpGetDcrE = bpi_BFFaceFinder_getDcr; |
| |
| ptrA->detectedFacesE = 0; |
| ptrA->availableFacesE = 0; |
| ptrA->faceDataBufferE = NULL; |
| bbf_ScanDetector_init( cpA, &ptrA->detectorE ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_exit( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA ) |
| { |
| ptrA->detectedFacesE = 0; |
| ptrA->availableFacesE = 0; |
| ptrA->faceDataBufferE = NULL; |
| bbf_ScanDetector_exit( cpA, &ptrA->detectorE ); |
| |
| bpi_FaceFinder_exit( cpA, &ptrA->baseE ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ operators } -------------------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_copy( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA, |
| const struct bpi_BFFaceFinder* srcPtrA ) |
| { |
| bpi_FaceFinder_copy( cpA, &ptrA->baseE, &srcPtrA->baseE ); |
| bbf_ScanDetector_copy( cpA, &ptrA->detectorE, &srcPtrA->detectorE ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| flag bpi_BFFaceFinder_equal( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| const struct bpi_BFFaceFinder* srcPtrA ) |
| { |
| if( !bpi_FaceFinder_equal( cpA, &ptrA->baseE, &srcPtrA->baseE ) ) return FALSE; |
| if( !bbf_ScanDetector_equal( cpA, &ptrA->detectorE, &srcPtrA->detectorE ) ) return FALSE; |
| return TRUE; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ query functions } -------------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_getMinEyeDistance( const struct bpi_BFFaceFinder* ptrA ) |
| { |
| return ( ( ptrA->detectorE.refDistanceE >> 8 ) * ( ptrA->detectorE.minScaleE >> 12 ) ) >> 16; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_getMaxEyeDistance( const struct bpi_BFFaceFinder* ptrA ) |
| { |
| return ( ( ptrA->detectorE.refDistanceE >> 8 ) * ( ptrA->detectorE.maxScaleE >> 12 ) ) >> 16; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ modify functions } ------------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_setMinEyeDistance( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA, |
| uint32 distA ) |
| { |
| ptrA->detectorE.minScaleE = ( ( distA << 16 ) / ( ptrA->detectorE.refDistanceE >> 8 ) ) << 12; |
| if( ptrA->detectorE.minScaleE < 0x100000 /* 1.0 */ ) ptrA->detectorE.minScaleE = 0x100000; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_setMaxEyeDistance( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA, |
| uint32 distA ) |
| { |
| if( distA > 0x0FFFF ) |
| { |
| ptrA->detectorE.maxScaleE = 0; /* unlimited */ |
| } |
| else |
| { |
| ptrA->detectorE.maxScaleE = ( ( distA << 16 ) / ( ptrA->detectorE.refDistanceE >> 8 ) ) << 12; |
| } |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ I/O } -------------------------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_memSize( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder *ptrA ) |
| { |
| uint32 memSizeL = 0; |
| memSizeL += bbs_SIZEOF16( uint32 ); |
| memSizeL += bbs_SIZEOF16( uint32 ); /* version */ |
| memSizeL += bpi_FaceFinder_memSize( cpA, &ptrA->baseE ); |
| memSizeL += bbf_ScanDetector_memSize( cpA, &ptrA->detectorE ); |
| memSizeL += bbs_SIZEOF16( uint16 ); /* csa */ |
| return memSizeL; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_memWrite( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| uint16* memPtrA ) |
| { |
| uint32 memSizeL = bpi_BFFaceFinder_memSize( cpA, ptrA ); |
| memPtrA += bbs_memWrite32( &memSizeL, memPtrA ); |
| memPtrA += bbs_memWriteUInt32( bpi_BF_FACE_FINDER_VERSION, memPtrA ); |
| memPtrA += bpi_FaceFinder_memWrite( cpA, &ptrA->baseE, memPtrA ); |
| memPtrA += bbf_ScanDetector_memWrite( cpA, &ptrA->detectorE, memPtrA ); |
| memPtrA += bpi_memWriteCsa16( memPtrA, memSizeL, 0xFFFF ); |
| return memSizeL; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_memRead( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA, |
| const uint16* memPtrA, |
| struct bbs_MemTbl* mtpA ) |
| { |
| uint32 memSizeL, versionL; |
| if( bbs_Context_error( cpA ) ) return 0; |
| memPtrA += bbs_memRead32( &memSizeL, memPtrA ); |
| memPtrA += bbs_memReadVersion32( cpA, &versionL, bpi_BF_FACE_FINDER_VERSION, memPtrA ); |
| memPtrA += bpi_FaceFinder_memRead( cpA, &ptrA->baseE, memPtrA ); |
| if( bbs_Context_error( cpA ) ) return 0; |
| |
| memPtrA += bbf_ScanDetector_memRead( cpA, &ptrA->detectorE, memPtrA, mtpA ); |
| if( bbs_Context_error( cpA ) ) return 0; |
| memPtrA += bpi_memReadCsa16( memPtrA ); |
| |
| /* if( memSizeL != bpi_BFFaceFinder_memSize( cpA, ptrA ) ) |
| { |
| bbs_ERROR0( "uint32 bpi_BFFaceFinder_memRead( .... ):\n" |
| "Module file is corrupt or incorrect. Please check if the face finder module is still supported." ); |
| return 0; |
| } |
| */ |
| return memSizeL; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |
| /* */ |
| /* ---- \ghd{ exec functions } --------------------------------------------- */ |
| /* */ |
| /* ========================================================================= */ |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| int32 bpi_BFFaceFinder_process( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| void* imagePtrA, |
| uint32 imageWidthA, |
| uint32 imageHeightA, |
| const struct bts_Int16Rect* roiPtrA, |
| struct bts_Int16Vec2D* offsPtrA, |
| struct bts_IdCluster2D* idClusterPtrA ) |
| { |
| int32 xL = 0; /* 16.16 */ |
| int32 yL = 0; /* 16.16 */ |
| uint32 scaleL = 0; |
| int32 actL = 0; |
| int32* outArrL; |
| |
| struct bts_Flt16Alt2D altL; |
| struct bts_Flt16Vec2D centerL; |
| |
| struct bpi_BFFaceFinder* ptrL = ( struct bpi_BFFaceFinder* )ptrA; |
| |
| /* reset multi face imformation so they are not accidentally used */ |
| ptrL->detectedFacesE = 0; |
| ptrL->availableFacesE = 0; |
| ptrL->faceDataBufferE = NULL; |
| |
| bbf_ScanDetector_process( cpA, ( struct bbf_ScanDetector* )&ptrA->detectorE, imagePtrA, imageWidthA, imageHeightA, roiPtrA, &outArrL ); |
| |
| xL = outArrL[ 0 ]; /* 16.16 */ |
| yL = outArrL[ 1 ]; /* 16.16 */ |
| scaleL = outArrL[ 2 ]; /* 12.20 */ |
| actL = outArrL[ 3 ]; /* 4.28 */ |
| |
| if( bbs_Context_error( cpA ) ) return 0; |
| |
| offsPtrA->xE = xL >> 16; |
| offsPtrA->yE = yL >> 16; |
| xL -= ( ( int32 )offsPtrA->xE << 16 ); |
| yL -= ( ( int32 )offsPtrA->yE << 16 ); |
| |
| centerL = bts_Flt16Vec2D_create32( 0, 0, 0 ); |
| altL = bts_Flt16Alt2D_createScale( scaleL, 20, ¢erL ); |
| altL.vecE = bts_Flt16Vec2D_create32( xL, yL, 16 ); |
| |
| /* compute cluster */ |
| { |
| uint32 eyeDistL = ( ( ptrA->detectorE.refDistanceE >> 16 ) * scaleL ) >> 20; |
| uint32 logEyeDistL = bbs_intLog2( eyeDistL ); |
| int32 bbpL = 11 - logEyeDistL; |
| bbpL = bbpL < 0 ? 0 : bbpL; |
| bbpL = bbpL > 6 ? 6 : bbpL; |
| bts_IdCluster2D_copyTransform( cpA, idClusterPtrA, &ptrA->detectorE.refClusterE, altL, bbpL ); |
| } |
| |
| |
| return ( actL + 0x10000000 ) >> 5; /*output range 0...1 in 8.24*/ |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_multiProcess( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| void* imagePtrA, |
| uint32 imageWidthA, |
| uint32 imageHeightA, |
| const struct bts_Int16Rect* roiPtrA ) |
| { |
| struct bpi_BFFaceFinder* ptrL = ( struct bpi_BFFaceFinder* )ptrA; |
| ptrL->detectedFacesE = bbf_ScanDetector_process( cpA, ( struct bbf_ScanDetector* )&ptrA->detectorE, imagePtrA, imageWidthA, imageHeightA, roiPtrA, &ptrL->faceDataBufferE ); |
| ptrL->availableFacesE = ptrA->detectedFacesE > 0 ? ptrA->detectedFacesE : 1; |
| if( bbs_Context_error( cpA ) ) return 0; |
| return ptrL->detectedFacesE; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| uint32 bpi_BFFaceFinder_getFace( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| uint32 indexA, |
| struct bts_Int16Vec2D* offsPtrA, |
| struct bts_IdCluster2D* idClusterPtrA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_getFace" ) |
| int32 xL = 0; /* 16.16 */ |
| int32 yL = 0; /* 16.16 */ |
| uint32 scaleL = 0; |
| int32 actL = 0; |
| struct bts_Flt16Alt2D altL; |
| struct bts_Flt16Vec2D centerL; |
| |
| if( bbs_Context_error( cpA ) ) return 0; |
| |
| if( ptrA->availableFacesE == 0 || ptrA->faceDataBufferE == NULL ) |
| { |
| bbs_ERROR1( "%s:\nNo faces are availabe. This function was called before the face finder could detect multiple faces in an image", fNameL ); |
| return 0; |
| } |
| |
| if( indexA >= ptrA->availableFacesE ) |
| { |
| bbs_ERROR1( "%s:\nface index exceeds number of available faces", fNameL ); |
| return 0; |
| } |
| |
| xL = ptrA->faceDataBufferE[ indexA * 4 + 0 ]; /* 16.16 */ |
| yL = ptrA->faceDataBufferE[ indexA * 4 + 1 ]; /* 16.16 */ |
| scaleL = ptrA->faceDataBufferE[ indexA * 4 + 2 ]; /* 12.20 */ |
| actL = ptrA->faceDataBufferE[ indexA * 4 + 3 ]; /* 4.28 */ |
| |
| offsPtrA->xE = xL >> 16; |
| offsPtrA->yE = yL >> 16; |
| |
| xL -= ( ( int32 )offsPtrA->xE << 16 ); |
| yL -= ( ( int32 )offsPtrA->yE << 16 ); |
| |
| centerL = bts_Flt16Vec2D_create32( 0, 0, 0 ); |
| altL = bts_Flt16Alt2D_createScale( scaleL, 20, ¢erL ); |
| altL.vecE = bts_Flt16Vec2D_create32( xL, yL, 16 ); |
| |
| /* compute cluster */ |
| { |
| uint32 eyeDistL = ( ( ptrA->detectorE.refDistanceE >> 16 ) * scaleL ) >> 20; |
| uint32 logEyeDistL = bbs_intLog2( eyeDistL ); |
| int32 bbpL = 11 - logEyeDistL; |
| bbpL = bbpL < 0 ? 0 : bbpL; |
| bbpL = bbpL > 6 ? 6 : bbpL; |
| bts_IdCluster2D_copyTransform( cpA, idClusterPtrA, &ptrA->detectorE.refClusterE, altL, bbpL ); |
| } |
| |
| return ( actL + 0x10000000 ) >> 5; /*output range 0...1 in 8.24*/ |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_getFaceDCR( struct bbs_Context* cpA, |
| const struct bpi_BFFaceFinder* ptrA, |
| uint32 indexA, |
| struct bpi_DCR* dcrPtrA ) |
| { |
| int32 confL = bpi_BFFaceFinder_getFace( cpA, ptrA, indexA, &dcrPtrA->offsE, &dcrPtrA->mainClusterE ); |
| bts_IdCluster2D_copy( cpA, &dcrPtrA->sdkClusterE, &dcrPtrA->mainClusterE ); |
| dcrPtrA->confidenceE = confL; |
| dcrPtrA->approvedE = confL > ( ( int32 )1 << 23 ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_setMaxImageSize( struct bbs_Context* cpA, |
| struct bpi_BFFaceFinder* ptrA, |
| uint32 maxImageWidthA, |
| uint32 maxImageHeightA ) |
| { |
| ptrA->detectorE.maxImageWidthE = maxImageWidthA; |
| ptrA->detectorE.maxImageHeightE = maxImageHeightA; |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_setParams( struct bbs_Context* cpA, |
| struct bpi_FaceFinder* ptrA, |
| uint32 maxImageWidthA, |
| uint32 maxImageHeightA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_setParams" ); |
| |
| if( bbs_Context_error( cpA ) ) return; |
| |
| if( ptrA->typeE != bpi_FF_BF_FACE_FINDER ) |
| { |
| bbs_ERROR1( "%s:\nObject type mismatch", fNameL ); |
| return; |
| } |
| bpi_BFFaceFinder_setMaxImageSize( cpA, ( struct bpi_BFFaceFinder* )ptrA, maxImageWidthA, maxImageHeightA ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_setRange( struct bbs_Context* cpA, |
| struct bpi_FaceFinder* ptrA, |
| uint32 minEyeDistanceA, |
| uint32 maxEyeDistanceA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_setParams" ); |
| |
| if( bbs_Context_error( cpA ) ) return; |
| |
| if( ptrA->typeE != bpi_FF_BF_FACE_FINDER ) |
| { |
| bbs_ERROR1( "%s:\nObject type mismatch", fNameL ); |
| return; |
| } |
| bpi_BFFaceFinder_setMinEyeDistance( cpA, ( struct bpi_BFFaceFinder* )ptrA, minEyeDistanceA ); |
| bpi_BFFaceFinder_setMaxEyeDistance( cpA, ( struct bpi_BFFaceFinder* )ptrA, maxEyeDistanceA ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| int32 bpi_BFFaceFinder_processDcr( struct bbs_Context* cpA, |
| const struct bpi_FaceFinder* ptrA, |
| struct bpi_DCR* dcrPtrA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_processDcr" ); |
| |
| if( bbs_Context_error( cpA ) ) return 0; |
| |
| if( ptrA->typeE != bpi_FF_BF_FACE_FINDER ) |
| { |
| bbs_ERROR1( "%s:\nObject type mismatch", fNameL ); |
| return 0; |
| } |
| |
| return bpi_BFFaceFinder_process( cpA, |
| ( const struct bpi_BFFaceFinder* )ptrA, |
| dcrPtrA->imageDataPtrE, |
| dcrPtrA->imageWidthE, |
| dcrPtrA->imageHeightE, |
| &dcrPtrA->roiRectE, |
| &dcrPtrA->offsE, |
| &dcrPtrA->mainClusterE ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| int32 bpi_BFFaceFinder_putDcr( struct bbs_Context* cpA, |
| const struct bpi_FaceFinder* ptrA, |
| struct bpi_DCR* dcrPtrA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_putDcr" ); |
| |
| if( bbs_Context_error( cpA ) ) return 0; |
| |
| if( ptrA->typeE != bpi_FF_BF_FACE_FINDER ) |
| { |
| bbs_ERROR1( "%s:\nObject type mismatch", fNameL ); |
| return 0; |
| } |
| |
| return bpi_BFFaceFinder_multiProcess( cpA, |
| ( const struct bpi_BFFaceFinder* )ptrA, |
| dcrPtrA->imageDataPtrE, |
| dcrPtrA->imageWidthE, |
| dcrPtrA->imageHeightE, |
| &dcrPtrA->roiRectE ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| void bpi_BFFaceFinder_getDcr( struct bbs_Context* cpA, |
| const struct bpi_FaceFinder* ptrA, |
| uint32 indexA, |
| struct bpi_DCR* dcrPtrA ) |
| { |
| bbs_DEF_fNameL( "bpi_BFFaceFinder_getDcr" ); |
| |
| if( bbs_Context_error( cpA ) ) return; |
| |
| if( ptrA->typeE != bpi_FF_BF_FACE_FINDER ) |
| { |
| bbs_ERROR1( "%s:\nObject type mismatch", fNameL ); |
| return; |
| } |
| |
| bpi_BFFaceFinder_getFaceDCR( cpA, ( const struct bpi_BFFaceFinder* )ptrA, indexA, dcrPtrA ); |
| } |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* ========================================================================= */ |