1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - PRC -
3 File: prc_algo_fine.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 #include <nitro.h>
19 #include <nitro/prc/algo_fine.h>
20
21 /*===========================================================================*
22 Prototype Declarations
23 *===========================================================================*/
24
25 static inline u32 PRCi_GetPatternLocalBufferSize_Fine(void);
26
27 static void
28 PRCi_CalcStrokeDistance_Fine(fx32 *score,
29 fx32 *weight,
30 const PRCiPatternData_Common *inputData,
31 const PRCiPatternData_Common *protoData,
32 int normalizeSize,
33 int lengthFilterThreshold,
34 int lengthFilterRatio, int iStroke, void *buffer);
35
36 /*===========================================================================*
37 Variable Definitions
38 *===========================================================================*/
39
40 /*===========================================================================*
41 Functions
42 *===========================================================================*/
43
44 /*---------------------------------------------------------------------------*
45 Name: PRC_GetRecognitionBufferSizeEx_Fine
46
47 Description: Calculates the work area size required for recognition algorithm.
48
49
50 Arguments: maxPointCount: Upper limit of number of input points (includes pen up marker)
51 maxStrokeCount: Upper limit of stroke count
52 protoDB: Sample DB
53 param: Parameters for recognition processing
54
55 Returns: The memory capacity required for the recognition algorithm.
56 *---------------------------------------------------------------------------*/
57 u32
PRC_GetRecognitionBufferSizeEx_Fine(int maxPointCount,int maxStrokeCount,const PRCPrototypeDB_Fine * protoDB,const PRCRecognizeParam_Fine * param)58 PRC_GetRecognitionBufferSizeEx_Fine(int maxPointCount,
59 int maxStrokeCount,
60 const PRCPrototypeDB_Fine *protoDB,
61 const PRCRecognizeParam_Fine *param)
62 {
63 u32 size = 0;
64
65 (void)maxStrokeCount;
66 (void)param;
67
68 if (maxPointCount < protoDB->maxPointCount)
69 {
70 maxPointCount = protoDB->maxPointCount;
71 }
72
73 size += PRCi_ARRAY_SIZE(int, maxPointCount * maxPointCount,);
74 size += PRCi_ARRAY_SIZE(int, maxPointCount * maxPointCount,);
75 size += PRCi_ARRAY_SIZE(int, maxPointCount * maxPointCount,);
76 size += PRCi_ARRAY_SIZE(int, ((maxPointCount + 1) * (maxPointCount + 1)),);
77 return size;
78 }
79
80 /*---------------------------------------------------------------------------*
81 Name: PRC_GetRecognizedEntriesEx_Fine
82
83 Description: Compares and recognizes a specific kind entry and input pattern to return the top numRanking ranking of the result.
84
85
86 Arguments: resultEntries Pointer to array that holds pointer to recognition result.
87 If less than the requested number could be recognized, fill in remainder with NULL.
88
89 resultScores: Pointer to recognition result score array
90 numRanking: Number of returns to result*
91 buffer: Pointer to memory region used by recognition algorithm
92 (Region size >= return value of PRC_GetRecognitionBufferSize)
93 input: Input pattern
94 protoDB: Sample DB
95 kindMask: Takes the logical AND of the 'kind' values for all the sample DB entries. Considered valid if it is non-zero.
96
97 param: Parameters for recognition processing
98
99 Returns: Number of patterns in the compared sample DBs.
100 *---------------------------------------------------------------------------*/
101 int
PRC_GetRecognizedEntriesEx_Fine(PRCPrototypeEntry ** resultEntries,fx32 * resultScores,int numRanking,void * buffer,const PRCInputPattern_Fine * input,const PRCPrototypeDB_Fine * protoDB,u32 kindMask,const PRCRecognizeParam_Fine * param)102 PRC_GetRecognizedEntriesEx_Fine(PRCPrototypeEntry **resultEntries,
103 fx32 *resultScores,
104 int numRanking,
105 void *buffer,
106 const PRCInputPattern_Fine *input,
107 const PRCPrototypeDB_Fine *protoDB,
108 u32 kindMask, const PRCRecognizeParam_Fine *param)
109 {
110 int i;
111 const PRCiPatternData_Common *inputData;
112 int numCompared;
113 int normalizeSize;
114 int lengthFilterThreshold, lengthFilterRatio;
115
116 SDK_ASSERT(resultEntries);
117 SDK_ASSERT(resultScores);
118 SDK_ASSERT(input);
119 SDK_ASSERT(protoDB);
120 SDK_ASSERT(numRanking > 0);
121
122 for (i = 0; i < numRanking; i++)
123 {
124 resultEntries[i] = NULL;
125 resultScores[i] = 0;
126 }
127
128 normalizeSize = protoDB->normalizeSize;
129 if (normalizeSize < input->normalizeSize)
130 {
131 normalizeSize = input->normalizeSize;
132 }
133
134 if (param == NULL)
135 {
136 lengthFilterThreshold = PRC_LENGTH_FILTER_DEFAULT_THRESHOLD_FINE;
137 lengthFilterRatio = PRC_LENGTH_FILTER_DEFAULT_RATIO_FINE;
138 }
139 else
140 {
141 lengthFilterThreshold = param->lengthFilterThreshold;
142 lengthFilterRatio = param->lengthFilterRatio;
143 }
144
145 inputData = &input->data;
146 numCompared = 0;
147
148 {
149 const PRCiPrototypeEntry_Common *proto;
150 int iPattern;
151
152 proto = protoDB->patterns;
153
154 for (iPattern = 0; iPattern < protoDB->patternCount; iPattern++, proto++)
155 {
156 const PRCiPatternData_Common *protoData;
157 int iStroke;
158 fx32 wholeScore, wholeWeight;
159
160 if (!proto->entry->enabled || !(proto->entry->kind & kindMask))
161 continue;
162
163 protoData = &proto->data;
164
165 if (inputData->strokeCount != protoData->strokeCount)
166 continue;
167
168 numCompared++;
169 wholeScore = 0;
170 wholeWeight = 0;
171
172 for (iStroke = 0; iStroke < inputData->strokeCount; iStroke++)
173 {
174 fx32 score, weight;
175
176 score = 0;
177
178 PRCi_CalcStrokeDistance_Fine(&score, &weight, inputData, protoData, normalizeSize,
179 lengthFilterThreshold, lengthFilterRatio, iStroke,
180 buffer);
181
182 wholeScore += score;
183 wholeWeight += weight;
184 }
185
186 wholeScore = FX_Div(wholeScore * 4, wholeWeight * normalizeSize); // 4 == (1<<FX32_SHIFT)/(512*2) , about 512 and 2, see below.
187 // wholeScore = FX_Div(wholeScore<<FX32_SHIFT, wholeWeight*normalizeSize*2*512); // normalizeSize*2 == doubleWidth, 512 = max of angleScore * 2
188
189 if (wholeScore < 0)
190 wholeScore = 0;
191 if (wholeScore >= FX32_ONE)
192 wholeScore = FX32_ONE;
193 if (proto->entry->correction != 0)
194 {
195 wholeScore = FX_Mul(wholeScore, FX32_ONE - proto->entry->correction)
196 + proto->entry->correction;
197 }
198
199 if (resultScores[numRanking - 1] < wholeScore)
200 {
201 resultScores[numRanking - 1] = wholeScore;
202 resultEntries[numRanking - 1] = (PRCPrototypeEntry *)proto->entry;
203 for (i = numRanking - 2; i >= 0; i--)
204 {
205 if (resultScores[i] < resultScores[i + 1])
206 {
207 fx32 tmpScore;
208 PRCPrototypeEntry *tmpEntry;
209 tmpScore = resultScores[i];
210 resultScores[i] = resultScores[i + 1];
211 resultScores[i + 1] = tmpScore;
212 tmpEntry = resultEntries[i];
213 resultEntries[i] = resultEntries[i + 1];
214 resultEntries[i + 1] = tmpEntry;
215 }
216 }
217 }
218 }
219 }
220
221 return numCompared;
222 }
223
224 /*===========================================================================*
225 Static Functions
226 *===========================================================================*/
227 #define PRCi_SINGLE_ANGLE_SCORE 128
228
CityBlockDistance(const PRCPoint * p1,const PRCPoint * p2)229 static inline int CityBlockDistance(const PRCPoint *p1, const PRCPoint *p2)
230 {
231 int x = p1->x - p2->x;
232 int y = p1->y - p2->y;
233 if (x < 0)
234 x = -x;
235 if (y < 0)
236 y = -y;
237 return (x + y);
238 }
239
240 #define PRCi_ABS(x) (((x)>=0)?(x):-(x))
241
242 #define PRCi_ANGLE_SCORE(input, proto) ((32768-PRCi_ABS((s16)(protoAngles[(proto)]-inputAngles[(input)])))/128)
243
244 static void
PRCi_CalcStrokeDistance_Fine(fx32 * score,fx32 * weight,const PRCiPatternData_Common * inputData,const PRCiPatternData_Common * protoData,int normalizeSize,int lengthFilterThreshold,int lengthFilterRatio,int iStroke,void * buffer)245 PRCi_CalcStrokeDistance_Fine(fx32 *score,
246 fx32 *weight,
247 const PRCiPatternData_Common *inputData,
248 const PRCiPatternData_Common *protoData,
249 int normalizeSize,
250 int lengthFilterThreshold,
251 int lengthFilterRatio, int iStroke, void *buffer)
252 {
253 #define nMatches_(x,y) (*(nMatches + (x) * maxPointCount + (y)))
254 #define sumScore_(x,y) (*(sumScore + (x) * maxPointCount + (y)))
255 #define direction_(x,y) (*(direction + (x) * maxPointCount + (y)))
256 #define angleScores_(x,y) (*(angleScores + (x) * (maxPointCount+1) + (y)))
257
258 // Calculate the degree of similarity between strokes, with DP matching
259 int iInput, iProto;
260 int *nMatches; //[STROKE_PACKED_POINT_MAX][STROKE_PACKED_POINT_MAX];
261 int *sumScore; //[STROKE_PACKED_POINT_MAX][STROKE_PACKED_POINT_MAX];
262 int *direction; //[STROKE_PACKED_POINT_MAX][STROKE_PACKED_POINT_MAX];
263 int *angleScores; //[STROKE_PACKED_POINT_MAX+1][STROKE_PACKED_POINT_MAX+1];
264
265 int protoStrokeIndex, inputStrokeIndex;
266 int protoSize, inputSize;
267 const PRCPoint *protoPoints;
268 const PRCPoint *inputPoints;
269 const u16 *protoAngles;
270 const u16 *inputAngles;
271 const fx16 *protoRatios;
272 const fx16 *inputRatios;
273 const fx32 *protoLengths;
274 const fx32 *inputLengths;
275 fx32 protoStrokeLength, inputStrokeLength;
276 int maxPointCount;
277 int doubleWidth;
278
279 maxPointCount = inputData->pointCount;
280 if (maxPointCount < protoData->pointCount)
281 maxPointCount = protoData->pointCount;
282
283 #ifdef SDK_DEBUG
284 {
285 int width, tmp;
286
287 width = inputData->wholeBoundingBox.x2 - inputData->wholeBoundingBox.x1;
288 tmp = inputData->wholeBoundingBox.y2 - inputData->wholeBoundingBox.y1;
289 if (tmp > width)
290 width = tmp;
291 tmp = protoData->wholeBoundingBox.x2 - protoData->wholeBoundingBox.x1;
292 if (tmp > width)
293 width = tmp;
294 tmp = protoData->wholeBoundingBox.y2 - protoData->wholeBoundingBox.y1;
295 if (tmp > width)
296 width = tmp;
297
298 width++;
299 if (width > normalizeSize)
300 {
301 OS_Warning
302 ("too small normalizeSize. PRCPrototypeList.normalizeSize seems smaller than actual data.");
303 }
304 }
305 #endif
306 doubleWidth = normalizeSize * 2;
307
308 // Allocate the buffer
309 {
310 int addr;
311 addr = 0;
312 PRCi_ALLOC_ARRAY(nMatches, int, maxPointCount * maxPointCount, buffer, addr);
313 PRCi_ALLOC_ARRAY(sumScore, int, maxPointCount * maxPointCount, buffer, addr);
314 PRCi_ALLOC_ARRAY(direction, int, maxPointCount * maxPointCount, buffer, addr);
315 PRCi_ALLOC_ARRAY(angleScores,
316 int, ((maxPointCount + 1) * (maxPointCount + 1)), buffer, addr);
317 }
318
319 protoStrokeIndex = protoData->strokes[iStroke];
320 inputStrokeIndex = inputData->strokes[iStroke];
321 protoSize = protoData->strokeSizes[iStroke];
322 inputSize = inputData->strokeSizes[iStroke];
323 protoPoints = &protoData->pointArray[protoStrokeIndex];
324 inputPoints = &inputData->pointArray[inputStrokeIndex];
325 protoAngles = &protoData->lineSegmentAngleArray[protoStrokeIndex];
326 inputAngles = &inputData->lineSegmentAngleArray[inputStrokeIndex];
327 protoRatios = &protoData->lineSegmentRatioToStrokeArray[protoStrokeIndex];
328 inputRatios = &inputData->lineSegmentRatioToStrokeArray[inputStrokeIndex];
329 protoLengths = &protoData->lineSegmentLengthArray[protoStrokeIndex];
330 inputLengths = &inputData->lineSegmentLengthArray[inputStrokeIndex];
331 protoStrokeLength = protoData->strokeLengths[iStroke];
332 inputStrokeLength = inputData->strokeLengths[iStroke];
333
334 *weight = FX32_ONE;
335 *score = 0;
336
337 if (protoSize == 0 || inputSize == 0)
338 return;
339
340 // Line segments whose length are too different will have their similarity set at 0 and no further calculation will be done.
341 if (inputStrokeLength > lengthFilterThreshold || protoStrokeLength > lengthFilterThreshold)
342 {
343 if (inputStrokeLength * lengthFilterRatio < protoStrokeLength
344 || protoStrokeLength * lengthFilterRatio < inputStrokeLength)
345 {
346 #ifdef PRC_DEBUG_RECOGNIZE_DEEPLY
347 OS_Printf("Skipped because of length filter %d <=> %d\n", FX_Whole(inputStrokeLength),
348 FX_Whole(protoStrokeLength));
349 #endif
350 return;
351 }
352 }
353
354 // Calculates angleScores[][] in advance, which is scores relating to angles
355 if (protoSize == 1 || inputSize == 1)
356 {
357 for (iInput = 0; iInput < inputSize; iInput++)
358 {
359 for (iProto = 0; iProto < protoSize; iProto++)
360 {
361 angleScores_(iInput, iProto) = PRCi_SINGLE_ANGLE_SCORE;
362 }
363 }
364 }
365 else
366 {
367 angleScores_(0, 0) = PRCi_ANGLE_SCORE(1, 1);
368 angleScores_(inputSize, 0) = PRCi_ANGLE_SCORE(inputSize - 1, 1);
369 angleScores_(0, protoSize) = PRCi_ANGLE_SCORE(1, protoSize - 1);
370 angleScores_(inputSize, protoSize) = PRCi_ANGLE_SCORE(inputSize - 1, protoSize - 1);
371
372 for (iInput = 1; iInput < inputSize; iInput++)
373 {
374 angleScores_(iInput, 0) = PRCi_ANGLE_SCORE(iInput, 1);
375 angleScores_(iInput, protoSize) = PRCi_ANGLE_SCORE(iInput, protoSize - 1);
376 }
377 for (iProto = 1; iProto < protoSize; iProto++)
378 {
379 angleScores_(0, iProto) = PRCi_ANGLE_SCORE(1, iProto);
380 angleScores_(inputSize, iProto) = PRCi_ANGLE_SCORE(inputSize - 1, iProto);
381 }
382
383 for (iInput = 1; iInput < inputSize; iInput++)
384 {
385 for (iProto = 1; iProto < protoSize; iProto++)
386 {
387 angleScores_(iInput, iProto) = PRCi_ANGLE_SCORE(iInput, iProto);
388 }
389 }
390 }
391
392 // Use DP matching to find corresponding points between strokes
393 #if 1
394 sumScore_(0, 0) =
395 (doubleWidth - CityBlockDistance(&inputPoints[0], &protoPoints[0])) * angleScores_(0,
396 0) * 2;
397 nMatches_(0, 0) = 1;
398 for (iInput = 1; iInput < inputSize; iInput++)
399 {
400 sumScore_(iInput, 0) =
401 (doubleWidth -
402 CityBlockDistance(&inputPoints[iInput], &protoPoints[0])) * (angleScores_(iInput,
403 0) +
404 angleScores_(iInput + 1,
405 1)) +
406 sumScore_(iInput - 1, 0);
407 nMatches_(iInput, 0) = nMatches_(iInput - 1, 0) + 1;
408 direction_(iInput, 0) = 2;
409 }
410 for (iProto = 1; iProto < protoSize; iProto++)
411 {
412 sumScore_(0, iProto) =
413 (doubleWidth -
414 CityBlockDistance(&inputPoints[0], &protoPoints[iProto])) * (angleScores_(0,
415 iProto) +
416 angleScores_(1,
417 iProto +
418 1)) +
419 sumScore_(0, iProto - 1);
420 nMatches_(0, iProto) = nMatches_(0, iProto - 1) + 1;
421 direction_(0, iProto) = 1;
422 }
423
424 for (iInput = 1; iInput < inputSize; iInput++)
425 {
426 for (iProto = 1; iProto < protoSize; iProto++)
427 {
428 int sum, n, localScore;
429 int sumMax, nMax, dirMax;
430
431 localScore =
432 (doubleWidth
433 - CityBlockDistance(&inputPoints[iInput], &protoPoints[iProto]))
434 * (angleScores_(iInput, iProto) + angleScores_(iInput + 1, iProto + 1));
435
436 dirMax = 0;
437 sumMax = localScore + sumScore_(iInput - 1, iProto - 1);
438 nMax = nMatches_(iInput - 1, iProto - 1) + 1;
439
440 sum = localScore + sumScore_(iInput, iProto - 1);
441 n = nMatches_(iInput, iProto - 1) + 1;
442 if (sum * nMax > sumMax * n)
443 {
444 sumMax = sum;
445 nMax = n;
446 dirMax = 1;
447 }
448
449 sum = localScore + sumScore_(iInput - 1, iProto);
450 n = nMatches_(iInput - 1, iProto) + 1;
451 if (sum * nMax > sumMax * n)
452 {
453 sumMax = sum;
454 nMax = n;
455 dirMax = 2;
456 }
457
458 sumScore_(iInput, iProto) = sumMax;
459 nMatches_(iInput, iProto) = nMax;
460 direction_(iInput, iProto) = dirMax;
461 }
462 }
463 #elif // beam search version. // Commenting out because doesn't speed up
464 {
465 int beamThreshold, beamN, beamValue, beamLow, beamHigh, nextBeamHigh;
466 int maxScore, maxScoreN;
467 BOOL fInBeamLow;
468
469 maxScore = 0;
470 maxScoreN = 1;
471
472 sumScore_(0, 0) =
473 (doubleWidth - CityBlockDistance(&inputPoints[0], &protoPoints[0])) * angleScores_(0,
474 0) *
475 2;
476 nMatches_(0, 0) = 1;
477 for (iProto = 1; iProto < protoSize; iProto++)
478 {
479 sumScore_(0, iProto) =
480 (doubleWidth -
481 CityBlockDistance(&inputPoints[0], &protoPoints[iProto])) * (angleScores_(0,
482 iProto) +
483 angleScores_(1,
484 iProto +
485 1)) +
486 sumScore_(0, iProto - 1);
487 nMatches_(0, iProto) = nMatches_(0, iProto - 1) + 1;
488 direction_(0, iProto) = 1;
489 }
490 for (iInput = 1; iInput < inputSize; iInput++)
491 {
492 int sc, n;
493
494 sc = (doubleWidth -
495 CityBlockDistance(&inputPoints[iInput], &protoPoints[0])) * (angleScores_(iInput,
496 0) +
497 angleScores_(iInput +
498 1,
499 1)) +
500 sumScore_(iInput - 1, 0);
501 n = nMatches_(iInput - 1, 0) + 1;
502 if (sc * maxScoreN > maxScore * n)
503 {
504 maxScore = sc;
505 maxScoreN = n;
506 }
507 sumScore_(iInput, 0) = sc;
508 nMatches_(iInput, 0) = n;
509 direction_(iInput, 0) = 2;
510 }
511
512 beamValue = normalizeSize * 2 * 512 / 8;
513 beamLow = 1;
514 nextBeamHigh = inputSize - 1;
515
516 for (iProto = 1; iProto < protoSize; iProto++)
517 {
518 beamHigh = nextBeamHigh + 1;
519 if (beamHigh < inputSize)
520 {
521 beamHigh++;
522 }
523 nextBeamHigh = 1;
524 beamN = maxScoreN;
525 beamThreshold = maxScore - beamValue * beamN;
526 fInBeamLow = TRUE;
527 maxScore = 0;
528 maxScoreN = 1;
529 // OS_Printf(" beam: [%d, %d]\n", beamLow, beamHigh);
530 if (beamLow > 1)
531 {
532 sumScore_(beamLow - 1, iProto) = 0;
533 nMatches_(beamLow - 1, iProto) = nMatches_(beamLow - 1, iProto - 1) + 1;
534 direction_(beamLow - 1, iProto) = 1;
535 }
536 for (iInput = beamLow; iInput < beamHigh; iInput++)
537 {
538 int sum, n, localScore;
539 int sumMax, nMax, dirMax;
540
541 localScore =
542 (doubleWidth
543 - CityBlockDistance(&inputPoints[iInput], &protoPoints[iProto]))
544 * (angleScores_(iInput, iProto) + angleScores_(iInput + 1, iProto + 1));
545
546 dirMax = 0;
547 sumMax = localScore + sumScore_(iInput - 1, iProto - 1);
548 nMax = nMatches_(iInput - 1, iProto - 1) + 1;
549
550 sum = localScore + sumScore_(iInput, iProto - 1);
551 n = nMatches_(iInput, iProto - 1) + 1;
552 if (sum * nMax > sumMax * n)
553 {
554 sumMax = sum;
555 nMax = n;
556 dirMax = 1;
557 }
558
559 sum = localScore + sumScore_(iInput - 1, iProto);
560 n = nMatches_(iInput - 1, iProto) + 1;
561 if (sum * nMax > sumMax * n)
562 {
563 sumMax = sum;
564 nMax = n;
565 dirMax = 2;
566 }
567
568 sumScore_(iInput, iProto) = sumMax;
569 nMatches_(iInput, iProto) = nMax;
570 direction_(iInput, iProto) = dirMax;
571
572 if (sumMax * beamN < beamThreshold * nMax)
573 {
574 if (fInBeamLow)
575 {
576 beamLow = iInput;
577 }
578 }
579 else
580 {
581 fInBeamLow = FALSE;
582 nextBeamHigh = iInput;
583 }
584 if (sumMax * maxScoreN > maxScore * nMax)
585 {
586 maxScore = sumMax;
587 maxScoreN = nMax;
588 }
589 }
590 }
591 if (beamHigh < inputSize)
592 {
593 for (iInput = beamHigh; iInput < inputSize; iInput++)
594 {
595 sumScore_(iInput, protoSize - 1) = sumScore_(iInput - 1, protoSize - 1) + 1;
596 nMatches_(iInput, protoSize - 1) = nMatches_(iInput - 1, protoSize - 1) + 1;
597 direction_(iInput, protoSize - 1) = 2;
598 }
599 }
600 }
601 #endif
602
603 #ifdef PRC_DEBUG_RECOGNIZE
604 {
605 int localScore, angleScore;
606 iInput = inputSize - 1;
607 iProto = protoSize - 1;
608 while (!(iInput == 0 && iProto == 0))
609 {
610 int dx, dy;
611 dx = -1 + (direction_(iInput, iProto) & 1);
612 dy = -1 + ((direction_(iInput, iProto) & 2) >> 1);
613 localScore = sumScore_(iInput, iProto) - sumScore_(iInput + dx, iProto + dy);
614 angleScore = angleScores_(iInput, iProto) + angleScores_(iInput + 1, iProto + 1);
615
616 OS_Printf(" %2d <-> %2d : 0.%03d = 0.%03d * 0.%03d, average from begin: 0.%03d\n",
617 iInput, iProto, localScore / normalizeSize,
618 localScore * 512 / angleScore / normalizeSize, angleScore * 2,
619 sumScore_(iInput, iProto) / nMatches_(iInput, iProto) / normalizeSize);
620
621 iInput += dx;
622 iProto += dy;
623 }
624 localScore = sumScore_(iInput, iProto);
625 angleScore = angleScores_(iInput, iProto) + angleScores_(iInput + 1, iProto + 1);
626 OS_Printf(" %2d <-> %2d : 0.%03d = 0.%03d * 0.%03d\n", iInput, iProto,
627 localScore / normalizeSize, localScore * 512 / angleScore / normalizeSize,
628 angleScore * 2);
629 }
630
631 OS_Printf("total: %d, matches: %d\n", sumScore_(inputSize - 1, protoSize - 1),
632 nMatches_(inputSize - 1, protoSize - 1));
633 #endif
634
635 *score = sumScore_(inputSize - 1, protoSize - 1);
636 *weight = nMatches_(inputSize - 1, protoSize - 1) << FX32_SHIFT;
637 }
638
639
640 /*---------------------------------------------------------------------------*
641 End of file
642 *---------------------------------------------------------------------------*/
643