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_APIEm/BFFaceFinder.h"
20#include "b_APIEm/Functions.h"
21#include "b_APIEm/DCR.h"
22#include "b_BasicEm/Functions.h"
23#include "b_BasicEm/Math.h"
24
25/* ------------------------------------------------------------------------- */
26
27/* ========================================================================= */
28/*                                                                           */
29/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
30/*                                                                           */
31/* ========================================================================= */
32
33/* ------------------------------------------------------------------------- */
34
35/* ========================================================================= */
36/*                                                                           */
37/* ---- \ghd{ constructor / destructor } ----------------------------------- */
38/*                                                                           */
39/* ========================================================================= */
40
41/* ------------------------------------------------------------------------- */
42
43void bpi_BFFaceFinder_init( struct bbs_Context* cpA,
44						    struct bpi_BFFaceFinder* ptrA )
45{
46	bpi_FaceFinder_init( cpA, &ptrA->baseE );
47	ptrA->baseE.typeE = ( uint32 )bpi_FF_BF_FACE_FINDER;
48	ptrA->baseE.vpSetParamsE = bpi_BFFaceFinder_setParams;
49	ptrA->baseE.vpSetRangeE = bpi_BFFaceFinder_setRange;
50	ptrA->baseE.vpProcessE = bpi_BFFaceFinder_processDcr;
51	ptrA->baseE.vpPutDcrE = bpi_BFFaceFinder_putDcr;
52	ptrA->baseE.vpGetDcrE = bpi_BFFaceFinder_getDcr;
53
54	ptrA->detectedFacesE = 0;
55	ptrA->availableFacesE = 0;
56	ptrA->faceDataBufferE = NULL;
57	bbf_ScanDetector_init( cpA, &ptrA->detectorE );
58}
59
60/* ------------------------------------------------------------------------- */
61
62void bpi_BFFaceFinder_exit( struct bbs_Context* cpA,
63						    struct bpi_BFFaceFinder* ptrA )
64{
65	ptrA->detectedFacesE = 0;
66	ptrA->availableFacesE = 0;
67	ptrA->faceDataBufferE = NULL;
68	bbf_ScanDetector_exit( cpA, &ptrA->detectorE );
69
70	bpi_FaceFinder_exit( cpA, &ptrA->baseE );
71}
72
73/* ------------------------------------------------------------------------- */
74
75/* ========================================================================= */
76/*                                                                           */
77/* ---- \ghd{ operators } -------------------------------------------------- */
78/*                                                                           */
79/* ========================================================================= */
80
81/* ------------------------------------------------------------------------- */
82
83void bpi_BFFaceFinder_copy( struct bbs_Context* cpA,
84						    struct bpi_BFFaceFinder* ptrA,
85							const struct bpi_BFFaceFinder* srcPtrA )
86{
87	bpi_FaceFinder_copy( cpA, &ptrA->baseE, &srcPtrA->baseE );
88	bbf_ScanDetector_copy( cpA, &ptrA->detectorE, &srcPtrA->detectorE );
89}
90
91/* ------------------------------------------------------------------------- */
92
93flag bpi_BFFaceFinder_equal( struct bbs_Context* cpA,
94							 const struct bpi_BFFaceFinder* ptrA,
95							 const struct bpi_BFFaceFinder* srcPtrA )
96{
97	if( !bpi_FaceFinder_equal( cpA, &ptrA->baseE, &srcPtrA->baseE ) ) return FALSE;
98	if( !bbf_ScanDetector_equal( cpA, &ptrA->detectorE, &srcPtrA->detectorE ) ) return FALSE;
99	return TRUE;
100}
101
102/* ------------------------------------------------------------------------- */
103
104/* ========================================================================= */
105/*                                                                           */
106/* ---- \ghd{ query functions } -------------------------------------------- */
107/*                                                                           */
108/* ========================================================================= */
109
110/* ------------------------------------------------------------------------- */
111
112uint32 bpi_BFFaceFinder_getMinEyeDistance( const struct bpi_BFFaceFinder* ptrA )
113{
114	return ( ( ptrA->detectorE.refDistanceE >> 8 ) * ( ptrA->detectorE.minScaleE >> 12 ) ) >> 16;
115}
116
117/* ------------------------------------------------------------------------- */
118
119uint32 bpi_BFFaceFinder_getMaxEyeDistance( const struct bpi_BFFaceFinder* ptrA )
120{
121	return ( ( ptrA->detectorE.refDistanceE >> 8 ) * ( ptrA->detectorE.maxScaleE >> 12 ) ) >> 16;
122}
123
124/* ------------------------------------------------------------------------- */
125
126/* ========================================================================= */
127/*                                                                           */
128/* ---- \ghd{ modify functions } ------------------------------------------- */
129/*                                                                           */
130/* ========================================================================= */
131
132/* ------------------------------------------------------------------------- */
133
134void bpi_BFFaceFinder_setMinEyeDistance( struct bbs_Context* cpA,
135										 struct bpi_BFFaceFinder* ptrA,
136										 uint32 distA )
137{
138	ptrA->detectorE.minScaleE = ( ( distA << 16 ) / ( ptrA->detectorE.refDistanceE >> 8 ) ) << 12;
139	if( ptrA->detectorE.minScaleE < 0x100000 /* 1.0 */ ) ptrA->detectorE.minScaleE = 0x100000;
140}
141
142/* ------------------------------------------------------------------------- */
143
144void bpi_BFFaceFinder_setMaxEyeDistance( struct bbs_Context* cpA,
145										 struct bpi_BFFaceFinder* ptrA,
146										 uint32 distA )
147{
148	if( distA > 0x0FFFF )
149	{
150		ptrA->detectorE.maxScaleE = 0; /* unlimited */
151	}
152	else
153	{
154		ptrA->detectorE.maxScaleE = ( ( distA << 16 ) / ( ptrA->detectorE.refDistanceE >> 8 ) ) << 12;
155	}
156}
157
158/* ------------------------------------------------------------------------- */
159
160/* ========================================================================= */
161/*                                                                           */
162/* ---- \ghd{ I/O } -------------------------------------------------------- */
163/*                                                                           */
164/* ========================================================================= */
165
166/* ------------------------------------------------------------------------- */
167
168uint32 bpi_BFFaceFinder_memSize( struct bbs_Context* cpA,
169								 const struct bpi_BFFaceFinder *ptrA )
170{
171	uint32 memSizeL = 0;
172	memSizeL += bbs_SIZEOF16( uint32 );
173	memSizeL += bbs_SIZEOF16( uint32 ); /* version */
174	memSizeL += bpi_FaceFinder_memSize( cpA, &ptrA->baseE );
175	memSizeL += bbf_ScanDetector_memSize( cpA, &ptrA->detectorE );
176	memSizeL += bbs_SIZEOF16( uint16 ); /* csa */
177	return memSizeL;
178}
179
180/* ------------------------------------------------------------------------- */
181
182uint32 bpi_BFFaceFinder_memWrite( struct bbs_Context* cpA,
183								  const struct bpi_BFFaceFinder* ptrA,
184								  uint16* memPtrA )
185{
186	uint32 memSizeL = bpi_BFFaceFinder_memSize( cpA, ptrA );
187	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
188	memPtrA += bbs_memWriteUInt32( bpi_BF_FACE_FINDER_VERSION, memPtrA );
189	memPtrA += bpi_FaceFinder_memWrite( cpA, &ptrA->baseE, memPtrA );
190	memPtrA += bbf_ScanDetector_memWrite( cpA, &ptrA->detectorE, memPtrA );
191	memPtrA += bpi_memWriteCsa16( memPtrA, memSizeL, 0xFFFF );
192	return memSizeL;
193}
194
195/* ------------------------------------------------------------------------- */
196
197uint32 bpi_BFFaceFinder_memRead( struct bbs_Context* cpA,
198								 struct bpi_BFFaceFinder* ptrA,
199								 const uint16* memPtrA,
200   								 struct bbs_MemTbl* mtpA )
201{
202	uint32 memSizeL, versionL;
203	if( bbs_Context_error( cpA ) ) return 0;
204	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
205	memPtrA += bbs_memReadVersion32( cpA, &versionL, bpi_BF_FACE_FINDER_VERSION, memPtrA );
206	memPtrA += bpi_FaceFinder_memRead( cpA, &ptrA->baseE, memPtrA );
207	if( bbs_Context_error( cpA ) ) return 0;
208
209	memPtrA += bbf_ScanDetector_memRead( cpA, &ptrA->detectorE, memPtrA, mtpA );
210	if( bbs_Context_error( cpA ) ) return 0;
211	memPtrA += bpi_memReadCsa16( memPtrA );
212
213/*	if( memSizeL != bpi_BFFaceFinder_memSize( cpA, ptrA ) )
214	{
215		bbs_ERROR0( "uint32 bpi_BFFaceFinder_memRead( .... ):\n"
216                    "Module file is corrupt or incorrect. Please check if the face finder module is still supported." );
217		return 0;
218	}
219*/
220	return memSizeL;
221}
222
223/* ------------------------------------------------------------------------- */
224
225/* ========================================================================= */
226/*                                                                           */
227/* ---- \ghd{ exec functions } --------------------------------------------- */
228/*                                                                           */
229/* ========================================================================= */
230
231/* ------------------------------------------------------------------------- */
232
233int32 bpi_BFFaceFinder_process( struct bbs_Context* cpA,
234							    const struct bpi_BFFaceFinder* ptrA,
235								void* imagePtrA,
236								uint32 imageWidthA,
237								uint32 imageHeightA,
238								const struct bts_Int16Rect* roiPtrA,
239								struct bts_Int16Vec2D* offsPtrA,
240								struct bts_IdCluster2D* idClusterPtrA )
241{
242	int32 xL = 0; /* 16.16 */
243	int32 yL = 0; /* 16.16 */
244	uint32 scaleL = 0;
245	int32 actL = 0;
246	int32* outArrL;
247
248	struct bts_Flt16Alt2D altL;
249	struct bts_Flt16Vec2D centerL;
250
251	struct bpi_BFFaceFinder* ptrL = ( struct bpi_BFFaceFinder* )ptrA;
252
253	/* reset multi face imformation so they are not accidentally used */
254	ptrL->detectedFacesE = 0;
255	ptrL->availableFacesE = 0;
256	ptrL->faceDataBufferE = NULL;
257
258	bbf_ScanDetector_process( cpA, ( struct bbf_ScanDetector* )&ptrA->detectorE, imagePtrA, imageWidthA, imageHeightA, roiPtrA, &outArrL );
259
260	xL      = outArrL[ 0 ]; /* 16.16 */
261	yL      = outArrL[ 1 ]; /* 16.16 */
262	scaleL  = outArrL[ 2 ]; /* 12.20 */
263	actL    = outArrL[ 3 ]; /*  4.28 */
264
265	if( bbs_Context_error( cpA ) ) return 0;
266
267	offsPtrA->xE = xL >> 16;
268	offsPtrA->yE = yL >> 16;
269	xL -= ( ( int32 )offsPtrA->xE << 16 );
270	yL -= ( ( int32 )offsPtrA->yE << 16 );
271
272	centerL = bts_Flt16Vec2D_create32( 0, 0, 0 );
273	altL = bts_Flt16Alt2D_createScale( scaleL, 20, &centerL );
274	altL.vecE = bts_Flt16Vec2D_create32( xL, yL, 16 );
275
276	/* compute cluster */
277	{
278		uint32 eyeDistL = ( ( ptrA->detectorE.refDistanceE >> 16 ) * scaleL ) >> 20;
279		uint32 logEyeDistL = bbs_intLog2( eyeDistL );
280		int32 bbpL = 11 - logEyeDistL;
281		bbpL = bbpL < 0 ? 0 : bbpL;
282		bbpL = bbpL > 6 ? 6 : bbpL;
283		bts_IdCluster2D_copyTransform( cpA, idClusterPtrA, &ptrA->detectorE.refClusterE, altL, bbpL );
284	}
285
286
287	return ( actL + 0x10000000 ) >> 5; /*output range 0...1 in 8.24*/
288}
289
290/* ------------------------------------------------------------------------- */
291
292uint32 bpi_BFFaceFinder_multiProcess( struct bbs_Context* cpA,
293									  const struct bpi_BFFaceFinder* ptrA,
294									  void* imagePtrA,
295									  uint32 imageWidthA,
296									  uint32 imageHeightA,
297									  const struct bts_Int16Rect* roiPtrA )
298{
299	struct bpi_BFFaceFinder* ptrL = ( struct bpi_BFFaceFinder* )ptrA;
300	ptrL->detectedFacesE = bbf_ScanDetector_process( cpA, ( struct bbf_ScanDetector* )&ptrA->detectorE, imagePtrA, imageWidthA, imageHeightA, roiPtrA, &ptrL->faceDataBufferE );
301	ptrL->availableFacesE = ptrA->detectedFacesE > 0 ? ptrA->detectedFacesE : 1;
302	if( bbs_Context_error( cpA ) ) return 0;
303	return ptrL->detectedFacesE;
304}
305
306/* ------------------------------------------------------------------------- */
307
308uint32 bpi_BFFaceFinder_getFace( struct bbs_Context* cpA,
309								 const struct bpi_BFFaceFinder* ptrA,
310								 uint32 indexA,
311								 struct bts_Int16Vec2D* offsPtrA,
312								 struct bts_IdCluster2D* idClusterPtrA )
313{
314	bbs_DEF_fNameL( "bpi_BFFaceFinder_getFace" )
315	int32 xL = 0; /* 16.16 */
316	int32 yL = 0; /* 16.16 */
317	uint32 scaleL = 0;
318	int32 actL = 0;
319	struct bts_Flt16Alt2D altL;
320	struct bts_Flt16Vec2D centerL;
321
322	if( bbs_Context_error( cpA ) ) return 0;
323
324	if( ptrA->availableFacesE == 0 || ptrA->faceDataBufferE == NULL )
325	{
326		bbs_ERROR1( "%s:\nNo faces are availabe. This function was called before the face finder could detect multiple faces in an image", fNameL );
327		return 0;
328	}
329
330	if( indexA >= ptrA->availableFacesE )
331	{
332		bbs_ERROR1( "%s:\nface index exceeds number of available faces", fNameL );
333		return 0;
334	}
335
336	xL      = ptrA->faceDataBufferE[ indexA * 4 + 0 ]; /* 16.16 */
337	yL      = ptrA->faceDataBufferE[ indexA * 4 + 1 ]; /* 16.16 */
338	scaleL  = ptrA->faceDataBufferE[ indexA * 4 + 2 ]; /* 12.20 */
339	actL    = ptrA->faceDataBufferE[ indexA * 4 + 3 ]; /*  4.28 */
340
341	offsPtrA->xE = xL >> 16;
342	offsPtrA->yE = yL >> 16;
343
344	xL -= ( ( int32 )offsPtrA->xE << 16 );
345	yL -= ( ( int32 )offsPtrA->yE << 16 );
346
347	centerL = bts_Flt16Vec2D_create32( 0, 0, 0 );
348	altL = bts_Flt16Alt2D_createScale( scaleL, 20, &centerL );
349	altL.vecE = bts_Flt16Vec2D_create32( xL, yL, 16 );
350
351	/* compute cluster */
352	{
353		uint32 eyeDistL = ( ( ptrA->detectorE.refDistanceE >> 16 ) * scaleL ) >> 20;
354		uint32 logEyeDistL = bbs_intLog2( eyeDistL );
355		int32 bbpL = 11 - logEyeDistL;
356		bbpL = bbpL < 0 ? 0 : bbpL;
357		bbpL = bbpL > 6 ? 6 : bbpL;
358		bts_IdCluster2D_copyTransform( cpA, idClusterPtrA, &ptrA->detectorE.refClusterE, altL, bbpL );
359	}
360
361	return ( actL + 0x10000000 ) >> 5; /*output range 0...1 in 8.24*/
362}
363
364/* ------------------------------------------------------------------------- */
365
366void bpi_BFFaceFinder_getFaceDCR( struct bbs_Context* cpA,
367								  const struct bpi_BFFaceFinder* ptrA,
368								  uint32 indexA,
369								  struct bpi_DCR* dcrPtrA )
370{
371	int32 confL = bpi_BFFaceFinder_getFace( cpA, ptrA, indexA, &dcrPtrA->offsE, &dcrPtrA->mainClusterE );
372	bts_IdCluster2D_copy( cpA, &dcrPtrA->sdkClusterE, &dcrPtrA->mainClusterE );
373	dcrPtrA->confidenceE = confL;
374	dcrPtrA->approvedE = confL > ( ( int32 )1 << 23 );
375}
376
377/* ------------------------------------------------------------------------- */
378
379void bpi_BFFaceFinder_setMaxImageSize( struct bbs_Context* cpA,
380									   struct bpi_BFFaceFinder* ptrA,
381									   uint32 maxImageWidthA,
382									   uint32 maxImageHeightA )
383{
384	ptrA->detectorE.maxImageWidthE = maxImageWidthA;
385	ptrA->detectorE.maxImageHeightE = maxImageHeightA;
386}
387
388/* ------------------------------------------------------------------------- */
389
390void bpi_BFFaceFinder_setParams( struct bbs_Context* cpA,
391								 struct bpi_FaceFinder* ptrA,
392								 uint32 maxImageWidthA,
393								 uint32 maxImageHeightA )
394{
395	bbs_DEF_fNameL( "bpi_BFFaceFinder_setParams" );
396
397	if( bbs_Context_error( cpA ) ) return;
398
399	if( ptrA->typeE != bpi_FF_BF_FACE_FINDER )
400	{
401		bbs_ERROR1( "%s:\nObject type mismatch", fNameL );
402		return;
403	}
404	bpi_BFFaceFinder_setMaxImageSize( cpA, ( struct bpi_BFFaceFinder* )ptrA, maxImageWidthA, maxImageHeightA );
405}
406
407/* ------------------------------------------------------------------------- */
408
409void bpi_BFFaceFinder_setRange( struct bbs_Context* cpA,
410								struct bpi_FaceFinder* ptrA,
411								uint32 minEyeDistanceA,
412								uint32 maxEyeDistanceA )
413{
414	bbs_DEF_fNameL( "bpi_BFFaceFinder_setParams" );
415
416	if( bbs_Context_error( cpA ) ) return;
417
418	if( ptrA->typeE != bpi_FF_BF_FACE_FINDER )
419	{
420		bbs_ERROR1( "%s:\nObject type mismatch", fNameL );
421		return;
422	}
423	bpi_BFFaceFinder_setMinEyeDistance( cpA, ( struct bpi_BFFaceFinder* )ptrA, minEyeDistanceA );
424	bpi_BFFaceFinder_setMaxEyeDistance( cpA, ( struct bpi_BFFaceFinder* )ptrA, maxEyeDistanceA );
425}
426
427/* ------------------------------------------------------------------------- */
428
429int32 bpi_BFFaceFinder_processDcr( struct bbs_Context* cpA,
430								   const struct bpi_FaceFinder* ptrA,
431						           struct bpi_DCR* dcrPtrA )
432{
433	bbs_DEF_fNameL( "bpi_BFFaceFinder_processDcr" );
434
435	if( bbs_Context_error( cpA ) ) return 0;
436
437	if( ptrA->typeE != bpi_FF_BF_FACE_FINDER )
438	{
439		bbs_ERROR1( "%s:\nObject type mismatch", fNameL );
440		return 0;
441	}
442
443	return bpi_BFFaceFinder_process( cpA,
444									( const struct bpi_BFFaceFinder* )ptrA,
445									dcrPtrA->imageDataPtrE,
446									dcrPtrA->imageWidthE,
447									dcrPtrA->imageHeightE,
448									&dcrPtrA->roiRectE,
449									&dcrPtrA->offsE,
450									&dcrPtrA->mainClusterE );
451}
452
453/* ------------------------------------------------------------------------- */
454
455int32 bpi_BFFaceFinder_putDcr( struct bbs_Context* cpA,
456							   const struct bpi_FaceFinder* ptrA,
457							   struct bpi_DCR* dcrPtrA )
458{
459	bbs_DEF_fNameL( "bpi_BFFaceFinder_putDcr" );
460
461	if( bbs_Context_error( cpA ) ) return 0;
462
463	if( ptrA->typeE != bpi_FF_BF_FACE_FINDER )
464	{
465		bbs_ERROR1( "%s:\nObject type mismatch", fNameL );
466		return 0;
467	}
468
469	return bpi_BFFaceFinder_multiProcess( cpA,
470										 ( const struct bpi_BFFaceFinder* )ptrA,
471										 dcrPtrA->imageDataPtrE,
472										 dcrPtrA->imageWidthE,
473										 dcrPtrA->imageHeightE,
474										 &dcrPtrA->roiRectE );
475}
476
477/* ------------------------------------------------------------------------- */
478
479void bpi_BFFaceFinder_getDcr( struct bbs_Context* cpA,
480							  const struct bpi_FaceFinder* ptrA,
481							  uint32 indexA,
482							  struct bpi_DCR* dcrPtrA )
483{
484	bbs_DEF_fNameL( "bpi_BFFaceFinder_getDcr" );
485
486	if( bbs_Context_error( cpA ) ) return;
487
488	if( ptrA->typeE != bpi_FF_BF_FACE_FINDER )
489	{
490		bbs_ERROR1( "%s:\nObject type mismatch", fNameL );
491		return;
492	}
493
494	bpi_BFFaceFinder_getFaceDCR( cpA, ( const struct bpi_BFFaceFinder* )ptrA, indexA, dcrPtrA );
495}
496
497/* ------------------------------------------------------------------------- */
498
499/* ========================================================================= */
500