Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
10 KiB

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <wtypes.h>
  4. #include <ASSERT.h>
  5. #include <math.h>
  6. #include "common.h"
  7. #include "memmgr.h"
  8. #include "bboxfeat.h"
  9. #define OverlapBins 1
  10. //#define OverlapBins 2
  11. #define RatioBins 11
  12. #define StrokeBins 8
  13. #define SpaceBins 1
  14. //#define SpaceBins 5
  15. // All unary feature bins should fall in the range 0<=bin<UnaryFeatureRange
  16. #define UnaryFeatureRange (RatioBins*StrokeBins*SpaceBins)
  17. // All binary feature bins should fall in the range 0<=bin<BinaryFeatureRange
  18. #define BinaryFeatureRange (OverlapBins*RatioBins*StrokeBins*StrokeBins*RatioBins*SpaceBins)
  19. // Convert a ratio (for example, aspect ratio) to a feature number in the range 0 to 10 (inclusive)
  20. int RatioToFeature(float num, float denom)
  21. {
  22. ASSERT(num>=0);
  23. ASSERT(denom>=0);
  24. if (denom>num*8) return 0;
  25. if (denom>num*4) return 1;
  26. if (denom>num*3) return 2;
  27. if (denom>num*2) return 3;
  28. if (denom*2>num*3) return 4;
  29. if (num>denom*8) return 10;
  30. if (num>denom*4) return 9;
  31. if (num>denom*3) return 8;
  32. if (num>denom*2) return 7;
  33. if (num*2>denom*3) return 6;
  34. return 5;
  35. }
  36. /*
  37. int ScoreToFeature(FLOAT score)
  38. {
  39. int iScore=(int)floor(-score);
  40. if (iScore<0) iScore=0;
  41. if (iScore>=ScoreBins) iScore=ScoreBins-1;
  42. return iScore;
  43. }
  44. */
  45. // Convert a stroke count to a feature number from 0 to 6 (inclusive)
  46. int StrokeCountToFeature(int nStrokes)
  47. {
  48. ASSERT(nStrokes>=1);
  49. if (nStrokes==1) return 0;
  50. if (nStrokes==2) return 1;
  51. if (nStrokes==3) return 2;
  52. if (nStrokes==4) return 3;
  53. if (nStrokes<=8) return 4;
  54. if (nStrokes<=16) return 5;
  55. if (nStrokes<=32) return 6;
  56. return 7;
  57. }
  58. // Convert an aspect ratio to a feature number
  59. int AspectRatioToFeature(RECT r)
  60. {
  61. ASSERT(r.left<=r.right);
  62. ASSERT(r.top<=r.bottom);
  63. return RatioToFeature((float)r.right-r.left+1,(float)r.bottom-r.top+1);
  64. }
  65. // Convert a ratio which has the range 0 to 1 to a feature number of 0 to 4 inclusive
  66. int FractionToFeature(int num, int denom)
  67. {
  68. return 0;
  69. if (5*num<=1*denom) return 0;
  70. if (5*num<=2*denom) return 1;
  71. if (5*num<=3*denom) return 2;
  72. if (5*num<=4*denom) return 3;
  73. return 4;
  74. }
  75. // A binary overlap feature: 1 if overlapped, 0 otherwise
  76. int OverlapRatioToFeature(RECT r1, RECT r2)
  77. {
  78. return 0;
  79. if (r1.left>r2.right || r1.right<r2.left || r1.top>r2.bottom || r1.bottom<r2.top)
  80. return 0;
  81. return 1;
  82. }
  83. // Convert an area ratio to a feature number
  84. int SizeRatioToFeature(RECT r1, RECT r2)
  85. {
  86. ASSERT(r1.left<=r1.right);
  87. ASSERT(r1.top<=r1.bottom);
  88. ASSERT(r2.left<=r2.right);
  89. ASSERT(r2.top<=r2.bottom);
  90. return RatioToFeature(((float)r1.right-r1.left+1)*((float)r1.bottom-r1.top+1),((float)r2.right-r2.left+1)*((float)r2.bottom-r2.top+1));
  91. }
  92. // Convert a matching space with associated score to a feature number
  93. int MatchSpaceScoreToFeature(int nStrokes, FLOAT score, int matchSpace)
  94. {
  95. int iScore=(int)floor(-score);
  96. ASSERT(matchSpace>=0 && matchSpace<32);
  97. if (iScore<0) iScore=0;
  98. if (nStrokes<3) iScore/=10;
  99. if (iScore>=ScoreBins) iScore=ScoreBins-1;
  100. if (nStrokes<3) return matchSpace*ScoreBins+iScore; else
  101. return (matchSpace+32)*ScoreBins+iScore;
  102. }
  103. // Returns the unary feature bin of one range of the ink, from index iStart<=index<iEnd
  104. // The returned bin should be in the range 0<=bin<UnaryFeatureRange
  105. int ComputeUnaryFeatures(STROKE_SET_STATS *stats, int nStrokes)
  106. {
  107. int bin;
  108. ASSERT(nStrokes>0);
  109. bin=StrokeBins*RatioBins*FractionToFeature(stats->space,stats->area)+StrokeBins*AspectRatioToFeature(stats->rect)+StrokeCountToFeature(nStrokes);
  110. ASSERT(bin>=0 && bin<UnaryFeatureRange);
  111. return bin;
  112. }
  113. // Returns the unary feature bin of one range of the ink, from index iStart1<=index<iStart2
  114. // and iStart2<=index<iEnd
  115. // The returned bin should be in the range 0<=bin<BinaryFeatureRange
  116. int ComputeBinaryFeatures(STROKE_SET_STATS *stats1, STROKE_SET_STATS *stats2, int nStrokes1, int nStrokes2)
  117. {
  118. int bin;
  119. ASSERT(nStrokes1>0);
  120. ASSERT(nStrokes2>0);
  121. bin=
  122. RatioBins*StrokeBins*StrokeBins*OverlapBins*RatioBins*FractionToFeature(stats2->space,stats2->area)+
  123. RatioBins*StrokeBins*StrokeBins*OverlapBins*AspectRatioToFeature(stats2->rect)+
  124. RatioBins*StrokeBins*StrokeBins*OverlapRatioToFeature(stats1->rect,stats2->rect)+
  125. StrokeBins*StrokeBins*SizeRatioToFeature(stats1->rect,stats2->rect)+
  126. StrokeBins*StrokeCountToFeature(nStrokes1)+
  127. StrokeCountToFeature(nStrokes2);
  128. ASSERT(bin>=0 && bin<BinaryFeatureRange);
  129. return bin;
  130. }
  131. // The following functions will be replaced by Greg's code
  132. // Compute the log base 2 of the ratio of the two arguments. There are several special
  133. // cases to consider: If denom is zero, then the returned value is zero. If the numerator
  134. // is zero (it should never be negative), then the value returned is Log2Range. All other
  135. // values are clipped to the range Log2Range<=val<=0
  136. PROB ClippedLog2(COUNTER num, COUNTER denom)
  137. {
  138. double ratio, val;
  139. ASSERT(num>=0);
  140. ASSERT(denom>=0);
  141. if (denom==0) return Log2Range;
  142. if (num==0) return Log2Range;
  143. ratio=(double)num/(double)denom;
  144. val=log(ratio)/log(2.0);
  145. if (val<Log2Range) val=Log2Range;
  146. if (val>0) val=0;
  147. return (int)floor(val+0.5);
  148. }
  149. PROB ClippedLog2Threshold(COUNTER num, COUNTER denom, COUNTER threshold)
  150. {
  151. ASSERT(num>=0);
  152. ASSERT(denom>=0);
  153. if (num<threshold) return ClippedLog2(0,denom);
  154. if (denom-num<threshold) return 0;
  155. return ClippedLog2(num,denom);
  156. }
  157. // Interval management code: Given a range of numbers, and many ranges within it which are removed,
  158. // keeps track of the remaining free space. This is used to compute how much white space there is in
  159. // a proposed character, once it is projected on to the X and Y axes.
  160. // Initialize the interval structure
  161. void EmptyIntervals(INTERVALS *intervals, int min, int max)
  162. {
  163. ASSERT(intervals!=NULL);
  164. ASSERT(min<=max);
  165. intervals->numIntervals=0;
  166. intervals->minRange=min;
  167. intervals->maxRange=max;
  168. }
  169. // Add a given range of ink to the interval structure.
  170. void ExpandIntervalsRange(INTERVALS *intervals, int min, int max)
  171. {
  172. int i;
  173. ASSERT(intervals!=NULL);
  174. ASSERT(min<=max);
  175. // If the added range extends beyond the minimum of the current range, then
  176. // extend.
  177. if (min<intervals->minRange) {
  178. // Find the free interval that touches the current minimum
  179. BOOL minFound=FALSE;
  180. for (i=0; i<intervals->numIntervals; i++) {
  181. if (intervals->min[i]==intervals->minRange) {
  182. // When found, extend it.
  183. intervals->min[i]=min;
  184. minFound=TRUE;
  185. }
  186. }
  187. // If there wasn't a free interval touching the boundary, then
  188. // make one to account for the extra space
  189. if (!minFound) {
  190. intervals->min[intervals->numIntervals]=min;
  191. intervals->max[intervals->numIntervals]=intervals->minRange-1;
  192. intervals->numIntervals++;
  193. }
  194. // Extend the range of the interval set.
  195. intervals->minRange=min;
  196. }
  197. // If the added range extends beyond the maximum of the current range,
  198. // then extend.
  199. if (max>intervals->maxRange) {
  200. // Find the free interval that touches the current maximum
  201. BOOL maxFound=FALSE;
  202. for (i=0; i<intervals->numIntervals; i++) {
  203. if (intervals->max[i]==intervals->maxRange) {
  204. // When found, extend it.
  205. intervals->max[i]=max;
  206. maxFound=TRUE;
  207. }
  208. }
  209. // If there wasnt' a free interval touching the boundary, then
  210. // make one to accoutn for the extra space.
  211. if (!maxFound) {
  212. intervals->min[intervals->numIntervals]=intervals->maxRange+1;
  213. intervals->max[intervals->numIntervals]=max;
  214. intervals->numIntervals++;
  215. }
  216. // Extend the range of the interval set.
  217. intervals->maxRange=max;
  218. }
  219. }
  220. // Remove a given range of ink from the interval structure.
  221. void RemoveInterval(INTERVALS *intervals, int min, int max)
  222. {
  223. int i;
  224. ASSERT(intervals!=NULL);
  225. ASSERT(min<=max);
  226. // Scan through all the free intervals currently in the set.
  227. for (i=0; i<intervals->numIntervals; i++) {
  228. // No overlap case
  229. if (min>intervals->max[i] || max<intervals->min[i]) {
  230. continue;
  231. }
  232. // Complete overlap case: delete interval
  233. if (min<=intervals->min[i] && max>=intervals->max[i]) {
  234. int nMove=intervals->numIntervals-i-1;
  235. if (nMove>0) {
  236. memmove(intervals->min+i,intervals->min+i+1,nMove*sizeof(int));
  237. memmove(intervals->max+i,intervals->max+i+1,nMove*sizeof(int));
  238. }
  239. intervals->numIntervals--;
  240. i--;
  241. continue;
  242. }
  243. // Complete overlap case: break free interval in two
  244. if (min>intervals->min[i] && max<intervals->max[i]) {
  245. intervals->min[intervals->numIntervals]=max+1;
  246. intervals->max[intervals->numIntervals]=intervals->max[i];
  247. intervals->max[i]=min-1;
  248. intervals->numIntervals++;
  249. continue;
  250. }
  251. // Min side overlapped
  252. if (min<=intervals->min[i] && max<intervals->max[i]) {
  253. intervals->min[i]=max+1;
  254. continue;
  255. }
  256. // Max side overlapped
  257. if (min>intervals->min[i] && max>=intervals->max[i]) {
  258. intervals->max[i]=min-1;
  259. continue;
  260. }
  261. }
  262. #ifdef DBG
  263. for (i=0; i<intervals->numIntervals; i++) {
  264. ASSERT(min>intervals->max[i] || max<intervals->min[i]);
  265. }
  266. #endif
  267. }
  268. // Get the total range of the interval set
  269. int TotalRange(INTERVALS *intervals)
  270. {
  271. ASSERT(intervals!=NULL);
  272. return intervals->maxRange-intervals->minRange+1;
  273. }
  274. // Get the total amount of free space in the interval set
  275. int TotalPresent(INTERVALS *intervals)
  276. {
  277. int i, total;
  278. ASSERT(intervals!=NULL);
  279. total=0;
  280. for (i=0; i<intervals->numIntervals; i++) {
  281. total += intervals->max[i]-intervals->min[i]+1;
  282. }
  283. return total;
  284. }
  285. // Test two rectangles for overlap (duplicates a system provided function)
  286. BOOL Overlapping(RECT r1, RECT r2)
  287. {
  288. if (r1.left>r2.right || r1.right<r2.left ||
  289. r1.top>r2.bottom || r1.bottom<r2.top)
  290. return 0;
  291. return 1;
  292. }
  293. // Get the area of a rectangle (may duplicate a system provided function)
  294. int Area(RECT r)
  295. {
  296. return (r.right-r.left)*(r.bottom-r.top);
  297. }
  298. // Compute the convex hull of the two rectangles (may duplicate a system provided function)
  299. RECT Union(RECT r1, RECT r2)
  300. {
  301. RECT result;
  302. result.left=__min(r1.left,r2.left);
  303. result.right=__max(r1.right,r2.right);
  304. result.top=__min(r1.top,r2.top);
  305. result.bottom=__max(r1.bottom,r2.bottom);
  306. return result;
  307. }
  308. #ifndef USE_RESOURCES
  309. // Load a bbox probability table from a file with the given name
  310. BBOX_PROB_TABLE *LoadBBoxProbTableFile(wchar_t *pRecogDir, LOAD_INFO *pInfo)
  311. {
  312. wchar_t wszFile[_MAX_PATH];
  313. BYTE *pByte;
  314. FormatPath(wszFile, pRecogDir, NULL, NULL, NULL, L"free.dat");
  315. pByte = DoOpenFile(pInfo, wszFile);
  316. if (!pByte) return NULL;
  317. return (BBOX_PROB_TABLE*)pByte;
  318. }
  319. BOOL UnLoadBBoxProbTableFile(LOAD_INFO *pInfo)
  320. {
  321. return DoCloseFile(pInfo);
  322. }
  323. #else // USE_RESOURCES
  324. // Load a bbox probability table from a resource (actually, just point at the
  325. // resource).
  326. BBOX_PROB_TABLE *LoadBBoxProbTableRes(HINSTANCE hInst, int nResID, int nType)
  327. {
  328. return (BBOX_PROB_TABLE *)DoLoadResource(NULL, hInst, nResID, nType);
  329. }
  330. #endif // USE_RESOURCES