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_BasicEm/Functions.h"
20#include "b_BasicEm/Math.h"
21#include "b_ImageEm/Functions.h"
22#include "b_BitFeatureEm/LocalScanDetector.h"
23
24/* ------------------------------------------------------------------------- */
25
26/* ========================================================================= */
27/*                                                                           */
28/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
29/*                                                                           */
30/* ========================================================================= */
31
32/* ------------------------------------------------------------------------- */
33
34/** applies PCA mapping
35 *  Input and output clusters may be identical
36 */
37void bbf_LocalScanDetector_pcaMap( struct bbs_Context* cpA,
38								   const struct bbf_LocalScanDetector* ptrA,
39								   const struct bts_IdCluster2D* inClusterPtrA,
40								   struct bts_IdCluster2D* outClusterPtrA )
41{
42	bbs_DEF_fNameL( "bbf_LocalScanDetector_pcaMap" )
43
44	struct bts_Cluster2D* tmpCl1PtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E;
45	struct bts_Cluster2D* tmpCl2PtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E;
46	struct bts_RBFMap2D*  rbfPtrL     = ( struct bts_RBFMap2D* )&ptrA->rbfMapE;
47	struct bts_Flt16Alt2D altL;
48	uint32 outBbpL = inClusterPtrA->clusterE.bbpE;
49	uint32 iL, jL;
50
51	/* setup two equivalent clusters holding the essential (alt-free) moves to be handled by PCA */
52	bts_IdCluster2D_convertToEqivalentClusters( cpA,
53												inClusterPtrA,
54												&ptrA->pcaClusterE,
55												tmpCl1PtrL,
56												tmpCl2PtrL );
57
58	altL = bts_Cluster2D_alt( cpA, tmpCl1PtrL, tmpCl2PtrL, bts_ALT_RIGID );
59	bts_Cluster2D_transform( cpA, tmpCl1PtrL, altL );
60	bts_RBFMap2D_compute( cpA, rbfPtrL, tmpCl2PtrL, tmpCl1PtrL );
61	bts_RBFMap2D_mapCluster( cpA, rbfPtrL, &ptrA->pcaClusterE.clusterE, tmpCl1PtrL, 6/* ! */ );
62
63	/* PCA projection: cluster1 -> cluster1 */
64	{
65		/* mat elements: 8.8 */
66		const int16* matPtrL = ptrA->pcaMatE.arrPtrE;
67
68		/* same bbp as pca cluster */
69		const int16* avgPtrL = ptrA->pcaAvgE.arrPtrE;
70
71		struct bts_Int16Vec2D* vecArrL = tmpCl1PtrL->vecArrE;
72
73		/* projected vector */
74		int32 prjVecL[ bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM ];
75
76		/* width of matrix */
77		uint16 matWidthL = tmpCl1PtrL->sizeE * 2;
78
79		if( ptrA->pcaDimSubSpaceE > bpi_LOCAL_SCAN_DETECTOR_MAX_PCA_DIM )
80		{
81			bbs_ERROR1( "%s:\nbpi_RF_LANDMARKER_MAX_PCA_DIM exceeded", fNameL );
82			return;
83		}
84
85		/* forward trafo */
86		for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ )
87		{
88			int32 sumL = 0;
89			avgPtrL = ptrA->pcaAvgE.arrPtrE;
90			for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ )
91			{
92				sumL += matPtrL[ 0 ] * ( vecArrL[ jL ].xE - avgPtrL[ 0 ] );
93				sumL += matPtrL[ 1 ] * ( vecArrL[ jL ].yE - avgPtrL[ 1 ] );
94				avgPtrL += 2;
95				matPtrL += 2;
96			}
97			prjVecL[ iL ] = ( sumL + 128 ) >> 8;
98		}
99
100		matPtrL = ptrA->pcaMatE.arrPtrE;
101		avgPtrL = ptrA->pcaAvgE.arrPtrE;
102		vecArrL = tmpCl1PtrL->vecArrE;
103
104		/* backward trafo */
105		for( jL = 0; jL < tmpCl1PtrL->sizeE; jL++ )
106		{
107			int32 sumL = 0;
108			for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ )
109			{
110				sumL += matPtrL[ iL * matWidthL + 0 ] * prjVecL[ iL ];
111			}
112
113			vecArrL[ jL ].xE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 0 ];
114
115			sumL = 0;
116			for( iL = 0; iL < ptrA->pcaDimSubSpaceE; iL++ )
117			{
118				sumL += matPtrL[ iL * matWidthL + 1 ] * prjVecL[ iL ];
119			}
120
121			vecArrL[ jL ].yE = ( ( sumL + 128 ) >> 8 ) + avgPtrL[ 1 ];
122
123			matPtrL += 2;
124			avgPtrL += 2;
125		}
126	}
127
128	/* ALT backtransformation */
129	bts_IdCluster2D_copy( cpA, outClusterPtrA, &ptrA->pcaClusterE );
130	bts_Cluster2D_copyTransform( cpA, &outClusterPtrA->clusterE, tmpCl1PtrL, bts_Flt16Alt2D_inverted( &altL ), outBbpL );
131}
132
133/* ------------------------------------------------------------------------- */
134
135/* ========================================================================= */
136/*                                                                           */
137/* ---- \ghd{ constructor / destructor } ----------------------------------- */
138/*                                                                           */
139/* ========================================================================= */
140
141/* ------------------------------------------------------------------------- */
142
143void bbf_LocalScanDetector_init( struct bbs_Context* cpA,
144							     struct bbf_LocalScanDetector* ptrA )
145{
146	bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) );
147	bts_RBFMap2D_init( cpA, &ptrA->rbfMapE );
148	bts_Cluster2D_init( cpA, &ptrA->tmpCluster1E );
149	bts_Cluster2D_init( cpA, &ptrA->tmpCluster2E );
150	bts_Cluster2D_init( cpA, &ptrA->tmpCluster3E );
151	bts_Cluster2D_init( cpA, &ptrA->tmpCluster4E );
152	bbf_LocalScanner_init( cpA, &ptrA->scannerE );
153	bbs_Int32Arr_init( cpA, &ptrA->actArrE );
154	bbs_Int16Arr_init( cpA, &ptrA->idxArrE );
155	bbs_UInt8Arr_init( cpA, &ptrA->workImageBufE );
156	ptrA->maxImageWidthE = 0;
157	ptrA->maxImageHeightE = 0;
158
159	ptrA->patchWidthE = 0;
160	ptrA->patchHeightE = 0;
161	ptrA->scanWidthE = 0;
162	ptrA->scanHeightE = 0;
163	ptrA->scaleExpE = 0;
164	ptrA->interpolatedWarpingE = TRUE;
165	ptrA->warpScaleThresholdE = 0;
166	bts_IdCluster2D_init( cpA, &ptrA->refClusterE );
167	bts_Cluster2D_init( cpA, &ptrA->scanClusterE );
168	bbs_UInt16Arr_init( cpA, &ptrA->ftrDataArrE );
169	bbf_BitParam_init( cpA, &ptrA->bitParamE );
170	ptrA->outlierDistanceE = 0;
171	bts_IdCluster2D_init( cpA, &ptrA->pcaClusterE );
172	bbs_Int16Arr_init( cpA, &ptrA->pcaAvgE );
173	bbs_Int16Arr_init( cpA, &ptrA->pcaMatE );
174	ptrA->pcaDimSubSpaceE = 0;
175	ptrA->maxImageWidthE = 0;
176	ptrA->maxImageHeightE = 0;
177}
178
179/* ------------------------------------------------------------------------- */
180
181void bbf_LocalScanDetector_exit( struct bbs_Context* cpA,
182							     struct bbf_LocalScanDetector* ptrA )
183{
184	uint16 iL;
185	for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) bbf_featureExit( cpA, ptrA->ftrPtrArrE[ iL ] );
186	bbs_memset16( ptrA->ftrPtrArrE, 0, bbs_SIZEOF16( ptrA->ftrPtrArrE ) );
187
188	bts_RBFMap2D_exit( cpA, &ptrA->rbfMapE );
189	bts_Cluster2D_exit( cpA, &ptrA->tmpCluster1E );
190	bts_Cluster2D_exit( cpA, &ptrA->tmpCluster2E );
191	bts_Cluster2D_exit( cpA, &ptrA->tmpCluster3E );
192	bts_Cluster2D_exit( cpA, &ptrA->tmpCluster4E );
193	bbf_LocalScanner_exit( cpA, &ptrA->scannerE );
194	bbs_Int32Arr_exit( cpA, &ptrA->actArrE );
195	bbs_Int16Arr_exit( cpA, &ptrA->idxArrE );
196	bbs_UInt8Arr_exit( cpA, &ptrA->workImageBufE );
197	ptrA->maxImageWidthE = 0;
198	ptrA->maxImageHeightE = 0;
199
200	ptrA->patchWidthE = 0;
201	ptrA->patchHeightE = 0;
202	ptrA->scanWidthE = 0;
203	ptrA->scanHeightE = 0;
204	ptrA->scaleExpE = 0;
205	ptrA->interpolatedWarpingE = TRUE;
206	ptrA->warpScaleThresholdE = 0;
207	bts_IdCluster2D_exit( cpA, &ptrA->refClusterE );
208	bts_Cluster2D_exit( cpA, &ptrA->scanClusterE );
209	bbs_UInt16Arr_exit( cpA, &ptrA->ftrDataArrE );
210	bbf_BitParam_exit( cpA, &ptrA->bitParamE );
211	ptrA->outlierDistanceE = 0;
212	bts_IdCluster2D_exit( cpA, &ptrA->pcaClusterE );
213	bbs_Int16Arr_exit( cpA, &ptrA->pcaAvgE );
214	bbs_Int16Arr_exit( cpA, &ptrA->pcaMatE );
215	ptrA->pcaDimSubSpaceE = 0;
216	ptrA->maxImageWidthE = 0;
217	ptrA->maxImageHeightE = 0;
218}
219
220/* ------------------------------------------------------------------------- */
221
222/* ========================================================================= */
223/*                                                                           */
224/* ---- \ghd{ operators } -------------------------------------------------- */
225/*                                                                           */
226/* ========================================================================= */
227
228/* ------------------------------------------------------------------------- */
229
230void bbf_LocalScanDetector_copy( struct bbs_Context* cpA,
231						    struct bbf_LocalScanDetector* ptrA,
232						    const struct bbf_LocalScanDetector* srcPtrA )
233{
234	bbs_ERROR0( "bbf_LocalScanDetector_copy:\n Function is not available" );
235}
236
237/* ------------------------------------------------------------------------- */
238
239flag bbf_LocalScanDetector_equal( struct bbs_Context* cpA,
240						     const struct bbf_LocalScanDetector* ptrA,
241						     const struct bbf_LocalScanDetector* srcPtrA )
242{
243	bbs_ERROR0( "bbf_LocalScanDetector_equal:\n Function is not available" );
244	return TRUE;
245}
246
247/* ------------------------------------------------------------------------- */
248
249/* ========================================================================= */
250/*                                                                           */
251/* ---- \ghd{ query functions } -------------------------------------------- */
252/*                                                                           */
253/* ========================================================================= */
254
255/* ------------------------------------------------------------------------- */
256
257/* ========================================================================= */
258/*                                                                           */
259/* ---- \ghd{ modify functions } ------------------------------------------- */
260/*                                                                           */
261/* ========================================================================= */
262
263/* ------------------------------------------------------------------------- */
264
265/* ========================================================================= */
266/*                                                                           */
267/* ---- \ghd{ I/O } -------------------------------------------------------- */
268/*                                                                           */
269/* ========================================================================= */
270
271/* ------------------------------------------------------------------------- */
272
273uint32 bbf_LocalScanDetector_memSize( struct bbs_Context* cpA,
274								      const struct bbf_LocalScanDetector* ptrA )
275{
276	uint32 iL;
277	uint32 memSizeL = bbs_SIZEOF16( uint32 ) +
278					  bbs_SIZEOF16( uint32 ); /* version */
279
280	memSizeL += bbs_SIZEOF16( ptrA->patchWidthE );
281	memSizeL += bbs_SIZEOF16( ptrA->patchHeightE );
282	memSizeL += bbs_SIZEOF16( ptrA->scanWidthE );
283	memSizeL += bbs_SIZEOF16( ptrA->scanHeightE );
284	memSizeL += bbs_SIZEOF16( ptrA->scaleExpE );
285	memSizeL += bbs_SIZEOF16( ptrA->interpolatedWarpingE );
286	memSizeL += bbs_SIZEOF16( ptrA->warpScaleThresholdE );
287	memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->refClusterE );
288	memSizeL += bts_Cluster2D_memSize( cpA, &ptrA->scanClusterE );
289	memSizeL += bbf_BitParam_memSize( cpA, &ptrA->bitParamE );
290	memSizeL += bbs_SIZEOF16( ptrA->outlierDistanceE );
291	memSizeL += bts_IdCluster2D_memSize( cpA, &ptrA->pcaClusterE );
292	memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaAvgE );
293	memSizeL += bbs_Int16Arr_memSize( cpA, &ptrA->pcaMatE );
294	memSizeL += bbs_SIZEOF16( ptrA->pcaDimSubSpaceE );
295	memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE );
296	memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE );
297	for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memSizeL += bbf_featureMemSize( cpA, ptrA->ftrPtrArrE[ iL ] );
298
299	return memSizeL;
300}
301
302/* ------------------------------------------------------------------------- */
303
304uint32 bbf_LocalScanDetector_memWrite( struct bbs_Context* cpA,
305									   const struct bbf_LocalScanDetector* ptrA,
306									   uint16* memPtrA )
307{
308	uint32 iL;
309	uint32 memSizeL = bbf_LocalScanDetector_memSize( cpA, ptrA );
310	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
311	memPtrA += bbs_memWriteUInt32( bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA );
312
313	memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA );
314	memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA );
315	memPtrA += bbs_memWrite32( &ptrA->scanWidthE, memPtrA );
316	memPtrA += bbs_memWrite32( &ptrA->scanHeightE, memPtrA );
317	memPtrA += bbs_memWrite32( &ptrA->scaleExpE, memPtrA );
318	memPtrA += bbs_memWrite32( &ptrA->interpolatedWarpingE, memPtrA );
319	memPtrA += bbs_memWrite32( &ptrA->warpScaleThresholdE, memPtrA );
320	memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->refClusterE, memPtrA );
321	memPtrA += bts_Cluster2D_memWrite( cpA, &ptrA->scanClusterE, memPtrA );
322	memPtrA += bbf_BitParam_memWrite( cpA, &ptrA->bitParamE, memPtrA );
323	memPtrA += bbs_memWrite32( &ptrA->outlierDistanceE, memPtrA );
324	memPtrA += bts_IdCluster2D_memWrite( cpA, &ptrA->pcaClusterE, memPtrA );
325	memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaAvgE, memPtrA );
326	memPtrA += bbs_Int16Arr_memWrite( cpA, &ptrA->pcaMatE, memPtrA );
327	memPtrA += bbs_memWrite32( &ptrA->pcaDimSubSpaceE, memPtrA );
328	memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA );
329	memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA );
330
331	for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ ) memPtrA += bbf_featureMemWrite( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA );
332
333	return memSizeL;
334}
335
336/* ------------------------------------------------------------------------- */
337
338uint32 bbf_LocalScanDetector_memRead( struct bbs_Context* cpA,
339									  struct bbf_LocalScanDetector* ptrA,
340									  const uint16* memPtrA,
341									  struct bbs_MemTbl* mtpA )
342{
343	uint32 iL;
344	uint32 memSizeL, versionL;
345	struct bbs_MemTbl memTblL = *mtpA;
346	struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 );
347	struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 );
348	if( bbs_Context_error( cpA ) ) return 0;
349
350	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
351	memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_LOCAL_SCAN_DETECTOR_VERSION, memPtrA );
352
353
354	memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA );
355	memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA );
356	memPtrA += bbs_memRead32( &ptrA->scanWidthE, memPtrA );
357	memPtrA += bbs_memRead32( &ptrA->scanHeightE, memPtrA );
358	memPtrA += bbs_memRead32( &ptrA->scaleExpE, memPtrA );
359	memPtrA += bbs_memRead32( &ptrA->interpolatedWarpingE, memPtrA );
360	memPtrA += bbs_memRead32( &ptrA->warpScaleThresholdE, memPtrA );
361	memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->refClusterE, memPtrA, espL );
362	memPtrA += bts_Cluster2D_memRead( cpA, &ptrA->scanClusterE, memPtrA, espL );
363	memPtrA += bbf_BitParam_memRead( cpA, &ptrA->bitParamE, memPtrA );
364	memPtrA += bbs_memRead32( &ptrA->outlierDistanceE, memPtrA );
365	memPtrA += bts_IdCluster2D_memRead( cpA, &ptrA->pcaClusterE, memPtrA, espL );
366	memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaAvgE, memPtrA, espL );
367	memPtrA += bbs_Int16Arr_memRead( cpA, &ptrA->pcaMatE, memPtrA, espL );
368	memPtrA += bbs_memRead32( &ptrA->pcaDimSubSpaceE, memPtrA );
369	memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA );
370	memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA );
371
372	/* check features & allocate data buffer */
373	{
374		const uint16* memPtrL = memPtrA;
375		uint32 dataSizeL = 0;
376		for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ )
377		{
378			enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrL + 4 );
379			dataSizeL += bbf_featureSizeOf16( cpA, typeL );
380			memPtrL += bbs_memPeek32( memPtrL );
381		}
382		bbs_UInt16Arr_create( cpA, &ptrA->ftrDataArrE, dataSizeL, espL );
383	}
384
385	/* load features & initialize pointers */
386	{
387		uint16* dataPtrL = ptrA->ftrDataArrE.arrPtrE;
388		for( iL = 0; iL < ptrA->scanClusterE.sizeE; iL++ )
389		{
390			enum bbf_FeatureType typeL = ( enum bbf_FeatureType )bbs_memPeek32( memPtrA + 4 );
391			ptrA->ftrPtrArrE[ iL ] = ( struct bbf_Feature* )dataPtrL;
392			bbf_featureInit( cpA, ptrA->ftrPtrArrE[ iL ], typeL );
393			memPtrA += bbf_featureMemRead( cpA, ptrA->ftrPtrArrE[ iL ], memPtrA, &memTblL );
394			dataPtrL += bbf_featureSizeOf16( cpA, typeL );
395		}
396	}
397
398	if( memSizeL != bbf_LocalScanDetector_memSize( cpA, ptrA ) )
399	{
400		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
401			        "size mismatch" );
402		return 0;
403	}
404
405	if( ptrA->maxImageWidthE * ptrA->maxImageHeightE == 0 )
406	{
407		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanDetector_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
408								        "maximum image width/height not set" );
409		return 0;
410	}
411
412	/* initialize internal data */
413
414	/* ought to be placed on shared memory later */
415	bts_RBFMap2D_create( cpA, &ptrA->rbfMapE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
416	ptrA->rbfMapE.RBFTypeE = bts_RBF_LINEAR;
417	ptrA->rbfMapE.altTypeE = bts_ALT_RIGID;
418
419	bts_Cluster2D_create( cpA, &ptrA->tmpCluster1E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
420	bts_Cluster2D_create( cpA, &ptrA->tmpCluster2E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
421	bts_Cluster2D_create( cpA, &ptrA->tmpCluster3E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
422	bts_Cluster2D_create( cpA, &ptrA->tmpCluster4E, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
423
424	bbs_Int32Arr_create( cpA, &ptrA->actArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
425	bbs_Int16Arr_create( cpA, &ptrA->idxArrE, bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE, sspL );
426
427	/* working image memory */
428	/* ought to be placed on shared memory later */
429	bbs_UInt8Arr_create( cpA, &ptrA->workImageBufE, ptrA->maxImageWidthE * ptrA->maxImageHeightE, sspL );
430
431	/* initialize local scanner (be aware of shared memory usage when moving this create function) */
432	bbf_LocalScanner_create( cpA, &ptrA->scannerE,
433							 ptrA->patchWidthE,
434							 ptrA->patchHeightE,
435							 ptrA->scaleExpE,
436							 ptrA->maxImageWidthE,
437							 ptrA->maxImageHeightE,
438							 ptrA->scaleExpE,
439							 ptrA->bitParamE.outerRadiusE,
440							 &memTblL );
441
442	return memSizeL;
443}
444
445/* ------------------------------------------------------------------------- */
446
447/* ========================================================================= */
448/*                                                                           */
449/* ---- \ghd{ exec functions } --------------------------------------------- */
450/*                                                                           */
451/* ========================================================================= */
452
453/* ------------------------------------------------------------------------- */
454
455int32 bbf_LocalScanDetector_process( struct bbs_Context* cpA,
456									 const struct bbf_LocalScanDetector* ptrA,
457                                     uint8* imagePtrA,
458									 uint32 imageWidthA,
459									 uint32 imageHeightA,
460									 const struct bts_Int16Vec2D*  offsPtrA,
461									 const struct bts_IdCluster2D* inClusterPtrA,
462									 struct bts_IdCluster2D* outClusterPtrA )
463{
464	bbs_DEF_fNameL( "bbf_LocalScanDetector_process" )
465
466	int32 pw0L = ptrA->patchWidthE;
467	int32 ph0L = ptrA->patchHeightE;
468	int32 pw1L = pw0L << ptrA->scaleExpE;
469	int32 ph1L = ph0L << ptrA->scaleExpE;
470
471	struct bts_Cluster2D* wrkClPtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster1E;
472	struct bts_Cluster2D* refClPtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster2E;
473	struct bts_Cluster2D* dstClPtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster3E;
474	struct bts_Cluster2D* tmpClPtrL  = ( struct bts_Cluster2D* )&ptrA->tmpCluster4E;
475	struct bts_RBFMap2D*  rbfPtrL    = ( struct bts_RBFMap2D* )&ptrA->rbfMapE;
476	struct bbf_LocalScanner* scnPtrL = ( struct bbf_LocalScanner* )&ptrA->scannerE;
477
478	int32* actArrL = ( int32* )ptrA->actArrE.arrPtrE;
479	int16* idxArrL = ( int16* )ptrA->idxArrE.arrPtrE;
480
481	uint32 workImageWidthL, workImageHeightL;
482
483	struct bts_Flt16Alt2D altL;
484
485	int32 confidenceL;
486	uint32 iL;
487	uint32 sizeL = ptrA->scanClusterE.sizeE;
488
489	if( sizeL > bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE )
490	{
491		bbs_ERROR1( "%s:\nScan cluster size exceeds bpi_LOCAL_SCAN_DETECTOR_MAX_CLUSTER_SIZE", fNameL );
492		return 0;
493	}
494
495	/* compute equivalent clusters (matching ids) from input and reference cluster */
496	bts_IdCluster2D_convertToEqivalentClusters( cpA, inClusterPtrA, &ptrA->refClusterE, wrkClPtrL, refClPtrL );
497
498	/* altL: orig image -> normalized image */
499	altL = bts_Cluster2D_alt( cpA, wrkClPtrL, refClPtrL, bts_ALT_RIGID );
500
501	/* transorm work cluster to normalized image */
502	bts_Cluster2D_transformBbp( cpA, wrkClPtrL, altL, 6 );
503
504	/* map: ref cluster -> work cluster */
505	bts_RBFMap2D_compute( cpA, rbfPtrL, refClPtrL, wrkClPtrL );
506
507	/* copy: scanClusterE -> work cluster */
508	bts_Cluster2D_copy( cpA, wrkClPtrL, &ptrA->scanClusterE );
509
510	/* copy: refClusterE -> ref cluster */
511	bts_Cluster2D_copy( cpA, refClPtrL, &ptrA->refClusterE.clusterE );
512
513	/* apply map to work cluster */
514	bts_Cluster2D_rbfTransform( cpA, wrkClPtrL, rbfPtrL );
515
516	/* apply map to ref cluster */
517	bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL );
518
519	{
520		/* analyze boundaries; get exact dimensions of working image */
521		int32 workBorderWL = ( ( ptrA->scanWidthE  + pw1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */
522		int32 workBorderHL = ( ( ptrA->scanHeightE + ph1L + 1 ) >> 1 ) + 1; /* add a pixel to ensure full search area */
523		struct bts_Int16Rect workAreaL = bts_Cluster2D_boundingBox( cpA, wrkClPtrL );
524		workAreaL.x1E = workAreaL.x1E >> wrkClPtrL->bbpE;
525		workAreaL.y1E = workAreaL.y1E >> wrkClPtrL->bbpE;
526		workAreaL.x2E = workAreaL.x2E >> wrkClPtrL->bbpE;
527		workAreaL.y2E = workAreaL.y2E >> wrkClPtrL->bbpE;
528		workAreaL.x1E -= workBorderWL;
529		workAreaL.y1E -= workBorderHL;
530		workAreaL.x2E += workBorderWL;
531		workAreaL.y2E += workBorderHL;
532
533		workImageWidthL  = workAreaL.x2E - workAreaL.x1E;
534		workImageHeightL = workAreaL.y2E - workAreaL.y1E;
535
536		/* truncate if necessary (should not occur in normal operation) */
537		workImageWidthL = workImageWidthL > ptrA->maxImageWidthE ? ptrA->maxImageWidthE : workImageWidthL;
538		workImageHeightL = workImageHeightL > ptrA->maxImageHeightE ? ptrA->maxImageHeightE : workImageHeightL;
539
540		/* adjust ALT */
541		altL.vecE.xE -= workAreaL.x1E << altL.vecE.bbpE;
542		altL.vecE.yE -= workAreaL.y1E << altL.vecE.bbpE;
543
544		/* adjust work cluster */
545		for( iL = 0; iL < wrkClPtrL->sizeE; iL++ )
546		{
547			wrkClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << wrkClPtrL->bbpE;
548			wrkClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << wrkClPtrL->bbpE;
549		}
550
551		/* adjust ref cluster */
552		for( iL = 0; iL < wrkClPtrL->sizeE; iL++ )
553		{
554			refClPtrL->vecArrE[ iL ].xE -= workAreaL.x1E << refClPtrL->bbpE;
555			refClPtrL->vecArrE[ iL ].yE -= workAreaL.y1E << refClPtrL->bbpE;
556		}
557
558		/* transform image */
559		bim_filterWarp( cpA,
560					    ptrA->workImageBufE.arrPtrE,
561						imagePtrA, imageWidthA, imageHeightA,
562						offsPtrA,
563						&altL,
564						workImageWidthL, workImageHeightL,
565						NULL,
566						ptrA->warpScaleThresholdE,
567						ptrA->interpolatedWarpingE );
568
569	}
570
571	/* scan over all positions of work cluster; target positions are stored in *dstClPtrL*/
572	{
573		int32 regionWHL = ( ptrA->scanWidthE  + pw1L + 1 ) >> 1;
574		int32 regionHHL = ( ptrA->scanHeightE + ph1L + 1 ) >> 1;
575		struct bts_Int16Vec2D* srcVecArrL = wrkClPtrL->vecArrE;
576		struct bts_Int16Vec2D* dstVecArrL = dstClPtrL->vecArrE;
577		int32 vecBbpL = wrkClPtrL->bbpE;
578		bts_Cluster2D_size( cpA, dstClPtrL, sizeL );
579		dstClPtrL->bbpE = vecBbpL;
580
581		/* initialize scanner */
582		scnPtrL->patchWidthE = ptrA->patchWidthE;
583		scnPtrL->patchHeightE = ptrA->patchWidthE;
584		scnPtrL->scaleExpE = ptrA->scaleExpE;
585
586		bbf_LocalScanner_assign( cpA, scnPtrL, ptrA->workImageBufE.arrPtrE, workImageWidthL, workImageHeightL, &ptrA->bitParamE );
587
588		bbs_memset32( actArrL, 0x80000000, sizeL );
589
590		do
591		{
592			for( iL = 0; iL < sizeL; iL++ )
593			{
594				int32 bestActL = 0x80000000;
595				uint32 bestIdxL = 0;
596				struct bbf_Feature* ftrPtrL = ptrA->ftrPtrArrE[ iL ];
597
598				/* set scan region */
599				{
600					int32 x0L = ( ( wrkClPtrL->vecArrE[ iL ].xE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1;
601					int32 y0L = ( ( wrkClPtrL->vecArrE[ iL ].yE >> ( wrkClPtrL->bbpE - 1 ) ) + 1 ) >> 1;
602					struct bts_Int16Rect scanRegionL = bts_Int16Rect_create( x0L - regionWHL, y0L - regionHHL, x0L + regionWHL, y0L + regionHHL );
603					bbf_LocalScanner_origScanRegion( cpA, scnPtrL, &scanRegionL );
604				}
605
606				do
607				{
608					int32 actL = ftrPtrL->vpActivityE( ftrPtrL, bbf_LocalScanner_getPatch( scnPtrL ) );
609
610					if( actL > bestActL )
611					{
612						bestActL = actL;
613						bestIdxL = bbf_LocalScanner_scanIndex( scnPtrL );
614					}
615				}
616				while( bbf_LocalScanner_next( cpA, scnPtrL ) );
617
618				{
619					int32 xL, yL; /* 16.16 */
620					bbf_LocalScanner_idxPos( scnPtrL, bestIdxL, &xL, &yL );
621					xL += pw1L << 15;
622					yL += ph1L << 15;
623					if( bestActL > actArrL[ iL ] )
624					{
625						dstVecArrL[ iL ].xE = ( ( xL >> ( 15 - vecBbpL ) ) + 1 ) >> 1;
626						dstVecArrL[ iL ].yE = ( ( yL >> ( 15 - vecBbpL ) ) + 1 ) >> 1;
627						actArrL[ iL ] = bestActL;
628					}
629				}
630			}
631		}
632		while( bbf_LocalScanner_nextOffset( cpA, scnPtrL ) );
633
634		/* outlier analysis: outliers are disabled by setting their similarity to -1 */
635		if( ptrA->outlierDistanceE > 0 )
636		{
637			/* altL: work cluster -> ref cluster */
638			struct bts_Flt16Alt2D localAltL = bts_Cluster2D_alt( cpA, wrkClPtrL, dstClPtrL, bts_ALT_RIGID );
639
640			/* squared distance 16.16 */
641			uint32 dist2L = ( ptrA->outlierDistanceE >> 8 ) * ( ptrA->outlierDistanceE >> 8 );
642
643			/* analyze deviations */
644			for( iL = 0; iL < sizeL; iL++ )
645			{
646				struct bts_Flt16Vec2D vecL = bts_Flt16Vec2D_create32( srcVecArrL[ iL ].xE, srcVecArrL[ iL ].yE, vecBbpL );
647				uint32 dev2L; /* squared deviation 16.16 */
648				vecL = bts_Flt16Alt2D_mapFlt( &localAltL, &vecL );
649				vecL = bts_Flt16Vec2D_sub( vecL, bts_Flt16Vec2D_create32( dstVecArrL[ iL ].xE, dstVecArrL[ iL ].yE, vecBbpL ) );
650				dev2L = bbs_convertU32( bts_Flt16Vec2D_norm2( &vecL ), vecL.bbpE << 1, 16 );
651				if( dev2L > dist2L ) actArrL[ iL ] = 0xF0000000;
652			}
653		}
654
655		/* remove undetected positions but keep at least 1/2 best positions */
656		{
657			flag sortedL;
658
659			/* bubble sort (no speed issue in this case) */
660			for( iL = 0; iL < sizeL; iL++ ) idxArrL[ iL ] = iL;
661
662			do
663			{
664				sortedL = TRUE;
665				for( iL = 1; iL < sizeL; iL++ )
666				{
667					if( actArrL[ idxArrL[ iL - 1 ] ] < actArrL[ idxArrL[ iL ] ] )
668					{
669						int16 tmpL = idxArrL[ iL - 1 ];
670						idxArrL[ iL - 1 ] = idxArrL[ iL ];
671						idxArrL[ iL ] = tmpL;
672						sortedL = FALSE;
673					}
674				}
675			}
676			while( !sortedL );
677
678			for( iL = ( sizeL >> 1 ); iL < sizeL && actArrL[ idxArrL[ iL ] ] >= 0; iL++ );
679
680			{
681				uint32 subSizeL = iL;
682
683				/* reorder clusters */
684				bts_Cluster2D_size( cpA, tmpClPtrL, subSizeL );
685				{
686					struct bts_Int16Vec2D* tmpVecArrL = tmpClPtrL->vecArrE;
687					for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = srcVecArrL[ idxArrL[ iL ] ];
688					for( iL = 0; iL < subSizeL; iL++ ) srcVecArrL[ iL ] = tmpVecArrL[ iL ];
689					for( iL = 0; iL < subSizeL; iL++ ) tmpVecArrL[ iL ] = dstVecArrL[ idxArrL[ iL ] ];
690					for( iL = 0; iL < subSizeL; iL++ ) dstVecArrL[ iL ] = tmpVecArrL[ iL ];
691				}
692				bts_Cluster2D_size( cpA, wrkClPtrL, subSizeL );
693				bts_Cluster2D_size( cpA, dstClPtrL, subSizeL );
694			}
695		}
696
697		/* compute confidence */
698		{
699			int16* idxArrL = ptrA->idxArrE.arrPtrE;
700			int32* actArrL = ptrA->actArrE.arrPtrE;
701			int32 actSumL = 0; /* .20 */
702			for( iL = 0; iL < sizeL; iL++ )
703			{
704				float actL = ( actArrL[ idxArrL[ iL ] ] + 128 ) >> 8;
705				if( actL < 0 ) break;
706				actSumL += actL;
707			}
708
709			/* actSumL = average positive activity */
710			actSumL = ( iL > 0 ) ? actSumL / iL : 0;
711
712			confidenceL = ( ( ( int32 )iL << 20 ) - ( ( ( int32 )1 << 20 ) - actSumL ) ) / sizeL;
713
714			/* adjust to 4.28 */
715			confidenceL <<= 8;
716		}
717
718	}
719
720	/* map: wrkCluster -> dstCluster */
721	bts_RBFMap2D_compute( cpA, rbfPtrL, wrkClPtrL, dstClPtrL );
722
723	/* apply map to ref cluster */
724	bts_Cluster2D_rbfTransform( cpA, refClPtrL, rbfPtrL );
725
726	/* copy ref cluster to outCluster */
727	bts_Cluster2D_copy( cpA, &outClusterPtrA->clusterE, refClPtrL );
728	bbs_Int16Arr_copy( cpA, &outClusterPtrA->idArrE, &ptrA->refClusterE.idArrE );
729
730	/* PCA Mapping */
731	if( ptrA->pcaDimSubSpaceE > 0 )
732	{
733		bbf_LocalScanDetector_pcaMap( cpA, ptrA, outClusterPtrA, outClusterPtrA );
734	}
735
736	/* backtransform out cluster to original image */
737	bts_Cluster2D_transformBbp( cpA, &outClusterPtrA->clusterE, bts_Flt16Alt2D_inverted( &altL ), inClusterPtrA->clusterE.bbpE );
738
739	return confidenceL;
740}
741
742/* ------------------------------------------------------------------------- */
743
744/* ========================================================================= */
745
746