Files
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
2025-04-27 07:49:33 -04:00

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