|
|
#include <stdlib.h>
#include <stdio.h>
#include <wtypes.h>
#include <ASSERT.h>
#include <math.h>
#include "common.h"
#include "memmgr.h"
#include "bboxfeat.h"
#define OverlapBins 1
//#define OverlapBins 2
#define RatioBins 11
#define StrokeBins 8
#define SpaceBins 1
//#define SpaceBins 5
// All unary feature bins should fall in the range 0<=bin<UnaryFeatureRange
#define UnaryFeatureRange (RatioBins*StrokeBins*SpaceBins)
// All binary feature bins should fall in the range 0<=bin<BinaryFeatureRange
#define BinaryFeatureRange (OverlapBins*RatioBins*StrokeBins*StrokeBins*RatioBins*SpaceBins)
// Convert a ratio (for example, aspect ratio) to a feature number in the range 0 to 10 (inclusive)
int RatioToFeature(float num, float denom) { ASSERT(num>=0); ASSERT(denom>=0);
if (denom>num*8) return 0; if (denom>num*4) return 1; if (denom>num*3) return 2; if (denom>num*2) return 3; if (denom*2>num*3) return 4;
if (num>denom*8) return 10; if (num>denom*4) return 9; if (num>denom*3) return 8; if (num>denom*2) return 7; if (num*2>denom*3) return 6;
return 5; }
/*
int ScoreToFeature(FLOAT score) { int iScore=(int)floor(-score); if (iScore<0) iScore=0; if (iScore>=ScoreBins) iScore=ScoreBins-1; return iScore; } */
// Convert a stroke count to a feature number from 0 to 6 (inclusive)
int StrokeCountToFeature(int nStrokes) { ASSERT(nStrokes>=1); if (nStrokes==1) return 0; if (nStrokes==2) return 1; if (nStrokes==3) return 2; if (nStrokes==4) return 3; if (nStrokes<=8) return 4; if (nStrokes<=16) return 5; if (nStrokes<=32) return 6; return 7; }
// Convert an aspect ratio to a feature number
int AspectRatioToFeature(RECT r) { ASSERT(r.left<=r.right); ASSERT(r.top<=r.bottom); return RatioToFeature((float)r.right-r.left+1,(float)r.bottom-r.top+1); }
// Convert a ratio which has the range 0 to 1 to a feature number of 0 to 4 inclusive
int FractionToFeature(int num, int denom) { return 0; if (5*num<=1*denom) return 0; if (5*num<=2*denom) return 1; if (5*num<=3*denom) return 2; if (5*num<=4*denom) return 3; return 4; }
// A binary overlap feature: 1 if overlapped, 0 otherwise
int OverlapRatioToFeature(RECT r1, RECT r2) { return 0; if (r1.left>r2.right || r1.right<r2.left || r1.top>r2.bottom || r1.bottom<r2.top) return 0; return 1; }
// Convert an area ratio to a feature number
int SizeRatioToFeature(RECT r1, RECT r2) { ASSERT(r1.left<=r1.right); ASSERT(r1.top<=r1.bottom); ASSERT(r2.left<=r2.right); ASSERT(r2.top<=r2.bottom); 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)); }
// Convert a matching space with associated score to a feature number
int MatchSpaceScoreToFeature(int nStrokes, FLOAT score, int matchSpace) { int iScore=(int)floor(-score); ASSERT(matchSpace>=0 && matchSpace<32); if (iScore<0) iScore=0; if (nStrokes<3) iScore/=10; if (iScore>=ScoreBins) iScore=ScoreBins-1; if (nStrokes<3) return matchSpace*ScoreBins+iScore; else return (matchSpace+32)*ScoreBins+iScore; }
// Returns the unary feature bin of one range of the ink, from index iStart<=index<iEnd
// The returned bin should be in the range 0<=bin<UnaryFeatureRange
int ComputeUnaryFeatures(STROKE_SET_STATS *stats, int nStrokes) { int bin; ASSERT(nStrokes>0); bin=StrokeBins*RatioBins*FractionToFeature(stats->space,stats->area)+StrokeBins*AspectRatioToFeature(stats->rect)+StrokeCountToFeature(nStrokes); ASSERT(bin>=0 && bin<UnaryFeatureRange); return bin; }
// Returns the unary feature bin of one range of the ink, from index iStart1<=index<iStart2
// and iStart2<=index<iEnd
// The returned bin should be in the range 0<=bin<BinaryFeatureRange
int ComputeBinaryFeatures(STROKE_SET_STATS *stats1, STROKE_SET_STATS *stats2, int nStrokes1, int nStrokes2) { int bin; ASSERT(nStrokes1>0); ASSERT(nStrokes2>0); bin= RatioBins*StrokeBins*StrokeBins*OverlapBins*RatioBins*FractionToFeature(stats2->space,stats2->area)+ RatioBins*StrokeBins*StrokeBins*OverlapBins*AspectRatioToFeature(stats2->rect)+ RatioBins*StrokeBins*StrokeBins*OverlapRatioToFeature(stats1->rect,stats2->rect)+ StrokeBins*StrokeBins*SizeRatioToFeature(stats1->rect,stats2->rect)+ StrokeBins*StrokeCountToFeature(nStrokes1)+ StrokeCountToFeature(nStrokes2); ASSERT(bin>=0 && bin<BinaryFeatureRange); return bin; }
// The following functions will be replaced by Greg's code
// Compute the log base 2 of the ratio of the two arguments. There are several special
// cases to consider: If denom is zero, then the returned value is zero. If the numerator
// is zero (it should never be negative), then the value returned is Log2Range. All other
// values are clipped to the range Log2Range<=val<=0
PROB ClippedLog2(COUNTER num, COUNTER denom) { double ratio, val; ASSERT(num>=0); ASSERT(denom>=0); if (denom==0) return Log2Range; if (num==0) return Log2Range; ratio=(double)num/(double)denom; val=log(ratio)/log(2.0); if (val<Log2Range) val=Log2Range; if (val>0) val=0; return (int)floor(val+0.5); }
PROB ClippedLog2Threshold(COUNTER num, COUNTER denom, COUNTER threshold) { ASSERT(num>=0); ASSERT(denom>=0); if (num<threshold) return ClippedLog2(0,denom); if (denom-num<threshold) return 0; return ClippedLog2(num,denom); }
// Interval management code: Given a range of numbers, and many ranges within it which are removed,
// keeps track of the remaining free space. This is used to compute how much white space there is in
// a proposed character, once it is projected on to the X and Y axes.
// Initialize the interval structure
void EmptyIntervals(INTERVALS *intervals, int min, int max) { ASSERT(intervals!=NULL); ASSERT(min<=max); intervals->numIntervals=0; intervals->minRange=min; intervals->maxRange=max; }
// Add a given range of ink to the interval structure.
void ExpandIntervalsRange(INTERVALS *intervals, int min, int max) { int i; ASSERT(intervals!=NULL); ASSERT(min<=max);
// If the added range extends beyond the minimum of the current range, then
// extend.
if (min<intervals->minRange) { // Find the free interval that touches the current minimum
BOOL minFound=FALSE; for (i=0; i<intervals->numIntervals; i++) { if (intervals->min[i]==intervals->minRange) { // When found, extend it.
intervals->min[i]=min; minFound=TRUE; } } // If there wasn't a free interval touching the boundary, then
// make one to account for the extra space
if (!minFound) { intervals->min[intervals->numIntervals]=min; intervals->max[intervals->numIntervals]=intervals->minRange-1; intervals->numIntervals++; } // Extend the range of the interval set.
intervals->minRange=min; } // If the added range extends beyond the maximum of the current range,
// then extend.
if (max>intervals->maxRange) { // Find the free interval that touches the current maximum
BOOL maxFound=FALSE; for (i=0; i<intervals->numIntervals; i++) { if (intervals->max[i]==intervals->maxRange) { // When found, extend it.
intervals->max[i]=max; maxFound=TRUE; } } // If there wasnt' a free interval touching the boundary, then
// make one to accoutn for the extra space.
if (!maxFound) { intervals->min[intervals->numIntervals]=intervals->maxRange+1; intervals->max[intervals->numIntervals]=max; intervals->numIntervals++; } // Extend the range of the interval set.
intervals->maxRange=max; } }
// Remove a given range of ink from the interval structure.
void RemoveInterval(INTERVALS *intervals, int min, int max) { int i; ASSERT(intervals!=NULL); ASSERT(min<=max); // Scan through all the free intervals currently in the set.
for (i=0; i<intervals->numIntervals; i++) { // No overlap case
if (min>intervals->max[i] || max<intervals->min[i]) { continue; } // Complete overlap case: delete interval
if (min<=intervals->min[i] && max>=intervals->max[i]) { int nMove=intervals->numIntervals-i-1; if (nMove>0) { memmove(intervals->min+i,intervals->min+i+1,nMove*sizeof(int)); memmove(intervals->max+i,intervals->max+i+1,nMove*sizeof(int)); } intervals->numIntervals--; i--; continue; } // Complete overlap case: break free interval in two
if (min>intervals->min[i] && max<intervals->max[i]) { intervals->min[intervals->numIntervals]=max+1; intervals->max[intervals->numIntervals]=intervals->max[i]; intervals->max[i]=min-1; intervals->numIntervals++; continue; } // Min side overlapped
if (min<=intervals->min[i] && max<intervals->max[i]) { intervals->min[i]=max+1; continue; } // Max side overlapped
if (min>intervals->min[i] && max>=intervals->max[i]) { intervals->max[i]=min-1; continue; } } #ifdef DBG
for (i=0; i<intervals->numIntervals; i++) { ASSERT(min>intervals->max[i] || max<intervals->min[i]); } #endif
}
// Get the total range of the interval set
int TotalRange(INTERVALS *intervals) { ASSERT(intervals!=NULL); return intervals->maxRange-intervals->minRange+1; }
// Get the total amount of free space in the interval set
int TotalPresent(INTERVALS *intervals) { int i, total; ASSERT(intervals!=NULL); total=0; for (i=0; i<intervals->numIntervals; i++) { total += intervals->max[i]-intervals->min[i]+1; } return total; }
// Test two rectangles for overlap (duplicates a system provided function)
BOOL Overlapping(RECT r1, RECT r2) { if (r1.left>r2.right || r1.right<r2.left || r1.top>r2.bottom || r1.bottom<r2.top) return 0; return 1; }
// Get the area of a rectangle (may duplicate a system provided function)
int Area(RECT r) { return (r.right-r.left)*(r.bottom-r.top); }
// Compute the convex hull of the two rectangles (may duplicate a system provided function)
RECT Union(RECT r1, RECT r2) { RECT result; result.left=__min(r1.left,r2.left); result.right=__max(r1.right,r2.right); result.top=__min(r1.top,r2.top); result.bottom=__max(r1.bottom,r2.bottom); return result; }
#ifndef USE_RESOURCES
// Load a bbox probability table from a file with the given name
BBOX_PROB_TABLE *LoadBBoxProbTableFile(wchar_t *pRecogDir, LOAD_INFO *pInfo) { wchar_t wszFile[_MAX_PATH]; BYTE *pByte; FormatPath(wszFile, pRecogDir, NULL, NULL, NULL, L"free.dat"); pByte = DoOpenFile(pInfo, wszFile); if (!pByte) return NULL; return (BBOX_PROB_TABLE*)pByte; }
BOOL UnLoadBBoxProbTableFile(LOAD_INFO *pInfo) { return DoCloseFile(pInfo); }
#else // USE_RESOURCES
// Load a bbox probability table from a resource (actually, just point at the
// resource).
BBOX_PROB_TABLE *LoadBBoxProbTableRes(HINSTANCE hInst, int nResID, int nType) { return (BBOX_PROB_TABLE *)DoLoadResource(NULL, hInst, nResID, nType); }
#endif // USE_RESOURCES
|