admin
base
com
developer
drivers
apm
ddk
dot4
drivers
filters
ftapi
inc
input
kmpi
ksfilter
net
nlsmsg
parallel
published
sac
serial
smartcrd
sound
storage
tpg
hwx
avalanche
bear
centipede
common
commonu
crane
factoid
fugu
holycow
hound
ifelang3
inferno
madcow
otter
sole
tsunami
twister
volcano
dll
chs
cht
jpn
kor
win2kunicode
bboxfeat.c
boxapi.c
brk.c
brknet.c
brknet.h
charrec.c
dirs
eafactoid.c
freeapi.c
fuguseg.c
hwxfe.def
hwxfei.def
jaws.c
jaws.h
lattice-lm.cpp
lattice.c
latticefl.c
latticers.c
res.h
segm.c
segm.h
segmnet.c
sole.c
sole.h
sources.inc
strkutil.c
volcano.dsp
volcano.vcproj
volcanoi.dsp
volcanoi.vcproj
volcanolib.dsp
volcanolibi.dsp
volcanop.h
vtune.c
vtunefl.c
wispapis.c
inc
dirs
wisp
zilla
dirs
wisp
video
watchdog
wdm
wmilib
dirs
project.mk
ds
enduser
inetcore
inetsrv
loc
mergedcomponents
multimedia
net
printscan
public
published
sdktools
shell
termsrv
tools
windows
dirs
makefil0
367 lines
11 KiB
C
367 lines
11 KiB
C
#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
|