1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - PRC -
3   File:     prc_algo_light.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_light.h>
20 
21 /*===========================================================================*
22   Prototype Declarations
23  *===========================================================================*/
24 
25 /*===========================================================================*
26   Variable Definitions
27  *===========================================================================*/
28 
29 /*===========================================================================*
30   Functions
31  *===========================================================================*/
32 
33 /*---------------------------------------------------------------------------*
34   Name:         PRC_GetRecognitionBufferSizeEx_Light
35 
36   Description:  Calculates the work area size required for recognition algorithm.
37 
38 
39   Arguments:    maxPointCount: Upper limit of number of input points (includes pen up marker)
40                 maxStrokeCount: Upper limit of stroke count
41                 protoDB: Sample DB
42                 param: Parameters for recognition processing
43 
44   Returns:      The memory capacity required for the recognition algorithm.
45  *---------------------------------------------------------------------------*/
46 u32
PRC_GetRecognitionBufferSizeEx_Light(int maxPointCount,int maxStrokeCount,const PRCPrototypeDB_Light * protoDB,const PRCRecognizeParam_Light * param)47 PRC_GetRecognitionBufferSizeEx_Light(int maxPointCount,
48                                      int maxStrokeCount,
49                                      const PRCPrototypeDB_Light *protoDB,
50                                      const PRCRecognizeParam_Light *param)
51 {
52     (void)maxPointCount;
53     (void)maxStrokeCount;
54     (void)protoDB;
55     (void)param;
56 
57     return 1;                          // Because OS_Alloc(0) causes an error
58 }
59 
60 /*---------------------------------------------------------------------------*
61   Name:         PRC_GetRecognizedEntriesEx_Light
62 
63   Description:  Compares and recognizes a specific kind entry and input pattern to return the top numRanking ranking of the result.
64 
65 
66   Arguments:    resultEntries: Pointer to array that holds pointers to recognition results.
67                                 If less than the requested number could be recognized, fill in remainder with NULL.
68 
69                 resultScores: Pointer to recognition result score array
70                 numRanking: Number of returns to result*
71                 buffer: Pointer to memory region used by recognition algorithm
72                                 (Region size >= return value of PRC_GetRecognitionBufferSize)
73                 input: Input pattern
74                 protoDB: Sample DB
75                 kindMask: Takes the logical AND of the 'kind' values for all the sample DB entries. Considered valid if it is non-zero.
76 
77                 param: Parameters for recognition processing
78 
79   Returns:      Number of patterns in the compared sample DBs.
80  *---------------------------------------------------------------------------*/
81 int
PRC_GetRecognizedEntriesEx_Light(PRCPrototypeEntry ** resultEntries,fx32 * resultScores,int numRanking,void * buffer,const PRCInputPattern_Light * input,const PRCPrototypeDB_Light * protoDB,u32 kindMask,const PRCRecognizeParam_Light * param)82 PRC_GetRecognizedEntriesEx_Light(PRCPrototypeEntry **resultEntries,
83                                  fx32 *resultScores,
84                                  int numRanking,
85                                  void *buffer,
86                                  const PRCInputPattern_Light *input,
87                                  const PRCPrototypeDB_Light *protoDB,
88                                  u32 kindMask, const PRCRecognizeParam_Light *param)
89 {
90     int     i;
91     const PRCiPatternData_Common *inputData;
92     int     numCompared;
93 
94     (void)buffer;
95     (void)param;
96 
97     SDK_ASSERT(resultEntries);
98     SDK_ASSERT(resultScores);
99     SDK_ASSERT(input);
100     SDK_ASSERT(protoDB);
101     SDK_ASSERT(numRanking > 0);
102 
103     for (i = 0; i < numRanking; i++)
104     {
105         resultEntries[i] = NULL;
106         resultScores[i] = FX32_ONE * 32768;
107     }
108 
109     inputData = &input->data;
110     numCompared = 0;
111 
112     {
113         const PRCiPrototypeEntry_Common *proto;
114         int     iPattern;
115         fx32    border;
116 
117         border = FX32_ONE;             // Cutoff level: If this value is set to FX32_ONE/2, then those with a score below 0.5 will not be evaluated at all.
118         border *= 32768;               // Coefficient of the internal score
119 
120         proto = protoDB->patterns;
121 
122         for (iPattern = 0; iPattern < protoDB->patternCount; iPattern++, proto++)
123         {
124             const PRCiPatternData_Common *protoData;
125             int     iStroke;
126             fx32    wholeScore;
127             fx32    patternBorder;
128 
129             if (!proto->entry->enabled || !(proto->entry->kind & kindMask))
130                 continue;
131 
132             protoData = &proto->data;
133 
134             if (inputData->strokeCount != protoData->strokeCount)
135                 continue;
136 
137             wholeScore = 0;
138 
139             // Set as cutoff the value which returned the amount of correction
140             patternBorder = border;
141             if (proto->entry->correction != 0)
142             {
143                 // For parts where [patternBorder *= 1 / (FX32_ONE - correction)] really must be done, cut corners with larger values by suitably approximating with straight lines
144                 //
145                 if (proto->entry->correction < -FX32_ONE)
146                 {
147                     patternBorder >>= 1;        // Approximated by 1/2 or less
148                 }
149                 else if (proto->entry->correction < 0)
150                 {
151                     // -1 < correction < 0  is approximated by correction/2+1
152                     patternBorder = FX_Mul(patternBorder, FX32_ONE + proto->entry->correction / 2);
153                 }
154                 else if (proto->entry->correction < FX32_ONE / 2)
155                 {
156                     // 0 < correction < 1/2 is approximated by correction*2+1
157                     patternBorder = FX_Mul(patternBorder, FX32_ONE + proto->entry->correction * 2);
158                 }
159                 else
160                 {
161                     patternBorder = FX32_ONE * 32768;
162                 }                      // Give up on the cutoff
163             }
164 
165             for (iStroke = 0; iStroke < inputData->strokeCount; iStroke++)
166             {
167                 int     iProto, iInput;
168                 int     protoStrokeIndex, inputStrokeIndex;
169                 int     protoSize, inputSize;
170                 const u16 *protoAngle;
171                 const u16 *inputAngle;
172                 const fx16 *protoRatio;
173                 const fx16 *inputRatio;
174                 fx16    protoNextRatio, inputNextRatio;
175                 fx32    score;
176                 fx32    localBorder;
177                 fx16    strokeRatio;
178                 int     loopEnd;
179 
180                 score = 0;
181 
182                 protoStrokeIndex = protoData->strokes[iStroke];
183                 inputStrokeIndex = inputData->strokes[iStroke];
184                 protoSize = protoData->strokeSizes[iStroke];
185                 inputSize = inputData->strokeSizes[iStroke];
186                 protoAngle = &protoData->lineSegmentAngleArray[protoStrokeIndex];
187                 inputAngle = &inputData->lineSegmentAngleArray[inputStrokeIndex];
188                 protoRatio = &protoData->lineSegmentRatioToStrokeArray[protoStrokeIndex];
189                 inputRatio = &inputData->lineSegmentRatioToStrokeArray[inputStrokeIndex];
190 
191                 strokeRatio = protoData->strokeRatios[iStroke]; // If here do inputData->, then the relative weight of the strokes of the input image takes on great importance
192 
193                 // Set the cutoff level
194                 if (strokeRatio == FX32_ONE)
195                 {
196                     localBorder = patternBorder;
197                 }
198                 else if (strokeRatio >= FX32_ONE / 2)
199                 {
200                     localBorder = patternBorder * 2;    // No problem with taking excess
201                 }
202                 else if (strokeRatio >= FX32_ONE / 3)
203                 {
204                     localBorder = patternBorder * 3;    // No problem with taking excess
205                 }
206                 else
207                 {
208                     localBorder = FX32_ONE * 32768;     // Doesn't consider the cutoff
209                 }
210 
211                 SDK_ASSERT(protoSize >= 2);
212                 SDK_ASSERT(inputSize >= 2);
213 
214                 iProto = iInput = 1;
215                 protoNextRatio = protoRatio[iProto];
216                 inputNextRatio = inputRatio[iInput];
217                 loopEnd = protoSize + inputSize - 3;
218                 for (i = 0; i < loopEnd; i++)
219                 {
220                     int     diff;
221                     SDK_ASSERT(iProto < protoSize);
222                     SDK_ASSERT(iInput < inputSize);
223                     diff = (s16)(protoAngle[iProto] - inputAngle[iInput]);
224                     if (diff < 0)
225                     {
226                         diff = -diff;
227                     }
228                     if (protoNextRatio <= inputNextRatio)
229                     {
230                         score += protoNextRatio * diff;
231                         iProto++;
232                         inputNextRatio -= protoNextRatio;
233                         protoNextRatio = protoRatio[iProto];
234                     }
235                     else
236                     {
237                         score += inputNextRatio * diff;
238                         iInput++;
239                         protoNextRatio -= inputNextRatio;
240                         inputNextRatio = inputRatio[iInput];
241                     }
242                     // Cutoff check
243                     if (score > localBorder)
244                     {
245                         // The likelihood of getting held up on the lowest-ranked candidate is gone now
246                         wholeScore = FX32_ONE * 32768;
247                         goto quit_compare;
248                     }
249                 }
250 
251                 wholeScore += FX_Mul(score, strokeRatio);
252             }
253 
254             if (proto->entry->correction != 0)
255             {
256                 wholeScore = FX_Mul(wholeScore, FX32_ONE - proto->entry->correction);
257             }
258 
259 //                wholeScore = FX_Mul(wholeScore, FX32_ONE - proto->entry->correction)
260 //                            + proto->entry->correction;
261 
262             // Note that low scores are better at this stage
263           quit_compare:
264             numCompared++;
265             if (resultScores[numRanking - 1] > wholeScore)
266             {
267                 resultScores[numRanking - 1] = wholeScore;
268                 resultEntries[numRanking - 1] = (PRCPrototypeEntry *)proto->entry;
269                 for (i = numRanking - 2; i >= 0; i--)
270                 {
271                     if (resultScores[i] > resultScores[i + 1])
272                     {
273                         fx32    tmpScore;
274                         PRCPrototypeEntry *tmpEntry;
275                         tmpScore = resultScores[i];
276                         resultScores[i] = resultScores[i + 1];
277                         resultScores[i + 1] = tmpScore;
278                         tmpEntry = resultEntries[i];
279                         resultEntries[i] = resultEntries[i + 1];
280                         resultEntries[i + 1] = tmpEntry;
281                     }
282                 }
283                 // Set the cutoff score
284                 border = resultScores[numRanking - 1];
285             }
286         }
287     }
288     // Normalize the score
289     {
290         int     iRank;
291         fx32    score;
292         for (iRank = 0; iRank < numRanking; iRank++)
293         {
294             if (resultEntries[iRank] == NULL)
295                 break;
296 
297             score = resultScores[iRank];
298             score = FX32_ONE - (score / 32768);
299             if (score < 0)
300                 score = 0;
301             if (score >= FX32_ONE)
302                 score = FX32_ONE;
303 
304             resultScores[iRank] = score;
305         }
306     }
307 
308     return numCompared;
309 }
310 
311 /*===========================================================================*
312   Static Functions
313  *===========================================================================*/
314 
315 
316 /*---------------------------------------------------------------------------*
317   End of file
318  *---------------------------------------------------------------------------*/
319