272 lines
6.2 KiB
C
272 lines
6.2 KiB
C
|
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||
|
//
|
||
|
// Copyright (c) 2001 Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// Module:
|
||
|
// volcano/dll/segm.c
|
||
|
//
|
||
|
// Description:
|
||
|
// Functions to implement the functionality of managing segmentation structures.
|
||
|
//
|
||
|
// Author:
|
||
|
// ahmadab 11/14/01
|
||
|
//
|
||
|
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "volcanop.h"
|
||
|
#include "lattice.h"
|
||
|
#include "runnet.h"
|
||
|
#include "brknet.h"
|
||
|
#include "segm.h"
|
||
|
#include "nnet.h"
|
||
|
|
||
|
float FuguSegScore(int cStrokes, STROKE *pStrokes, LOCRUN_INFO *pLocRunInfo);
|
||
|
|
||
|
// enumerate all the segmentations currently present in the lattice
|
||
|
// for the specified ink segment
|
||
|
BOOL EnumerateInkSegmentations (LATTICE *pLat, INK_SEGMENT *pInkSegment)
|
||
|
{
|
||
|
int cAlt, iAlt, iPrevAlt;
|
||
|
LATTICE_ALT_LIST *pAlt;
|
||
|
|
||
|
// find unique segmentations
|
||
|
pAlt = pLat->pAltList + pInkSegment->StrokeRange.iEndStrk;
|
||
|
cAlt = pAlt->nUsed;
|
||
|
|
||
|
// for each alt find out if there is any prev alt that suggests the same stroke count
|
||
|
for (iAlt = 0; iAlt < cAlt; iAlt++)
|
||
|
{
|
||
|
for (iPrevAlt = 0; iPrevAlt < iAlt; iPrevAlt++)
|
||
|
{
|
||
|
// found one, that is enough exit this prev loop
|
||
|
if (pAlt->alts[iAlt].nStrokes == pAlt->alts[iPrevAlt].nStrokes)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if we found no match, then this is the first existense of this count, we want it
|
||
|
if (iPrevAlt == iAlt)
|
||
|
{
|
||
|
ELEMLIST *pSegm;
|
||
|
int iStrk, iStrkAlt;
|
||
|
LATTICE_ALT_LIST *pStrkAlt;
|
||
|
|
||
|
// now we want to create a new segmentation
|
||
|
pInkSegment->ppSegm = (ELEMLIST **) ExternRealloc (pInkSegment->ppSegm,
|
||
|
(pInkSegment->cSegm + 1) * sizeof (*pInkSegment->ppSegm));
|
||
|
|
||
|
if (!pInkSegment->ppSegm)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pInkSegment->ppSegm[pInkSegment->cSegm] =
|
||
|
(ELEMLIST *) ExternAlloc (sizeof (*pInkSegment->ppSegm[pInkSegment->cSegm]));
|
||
|
|
||
|
if (!pInkSegment->ppSegm[pInkSegment->cSegm])
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pSegm = pInkSegment->ppSegm[pInkSegment->cSegm];
|
||
|
pInkSegment->cSegm++;
|
||
|
|
||
|
memset (pSegm, 0, sizeof (*pSegm));
|
||
|
|
||
|
iStrk = pInkSegment->StrokeRange.iEndStrk;
|
||
|
iStrkAlt = iAlt;
|
||
|
|
||
|
while (iStrk >= pInkSegment->StrokeRange.iStartStrk)
|
||
|
{
|
||
|
pStrkAlt = pLat->pAltList + iStrk;
|
||
|
|
||
|
if (!InsertListElement (pSegm, iStrk, iStrkAlt, pStrkAlt->alts + iStrkAlt))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
iStrk -= pStrkAlt->alts[iStrkAlt].nStrokes;
|
||
|
iStrkAlt = pStrkAlt->alts[iStrkAlt].iPrevAlt;
|
||
|
}
|
||
|
|
||
|
ReverseElementList (pSegm);
|
||
|
|
||
|
// if we had already exceed the maximum number of segmentations, return
|
||
|
if (pInkSegment->cSegm > MAX_SEGMENTATIONS)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// computes the set of features for a segmentation
|
||
|
int FeaturizeSegmentation (LATTICE *pLat, ELEMLIST *pSeg, int *pFeat)
|
||
|
{
|
||
|
int cFeat = 0;
|
||
|
LATTICE_ELEMENT *pElem, *pPrevElem;
|
||
|
LATTICE_PATH_ELEMENT *pPathElem;
|
||
|
int iChar,
|
||
|
iBrkNetOut;
|
||
|
|
||
|
pPrevElem = NULL;
|
||
|
iBrkNetOut = 0;
|
||
|
|
||
|
pPathElem = pSeg->pElem;
|
||
|
|
||
|
for (iChar = 0; iChar < MAX_SEG_CHAR; iChar++, pPathElem++)
|
||
|
{
|
||
|
// we going beyond the actual number of chars
|
||
|
if (iChar >= pSeg->cElem)
|
||
|
{
|
||
|
// char features
|
||
|
|
||
|
// FEATURE 0: is this a real char
|
||
|
pFeat[cFeat++] = 0;
|
||
|
|
||
|
// FEATURE 1: # of strokes
|
||
|
pFeat[cFeat++] = 0;
|
||
|
|
||
|
// FEATURE 2: -log prob
|
||
|
pFeat[cFeat++] = 65535;
|
||
|
|
||
|
// FEATURE 3: unigram of code point
|
||
|
pFeat[cFeat++] = 65535;
|
||
|
|
||
|
// FEATURE 3: fake fugu score
|
||
|
pFeat[cFeat++] = 0;
|
||
|
|
||
|
// char pair features
|
||
|
if (iChar > 0)
|
||
|
{
|
||
|
// FEATURE 0: bigram pair
|
||
|
pFeat[cFeat++] = 65535;
|
||
|
|
||
|
// FEATURE 1: normalized delx
|
||
|
pFeat[cFeat++] = 0;
|
||
|
|
||
|
// FEATURE 2: output of brk net
|
||
|
pFeat[cFeat++] = 0;
|
||
|
}
|
||
|
|
||
|
pPrevElem = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ASSERT (pPathElem->iStroke < pLat->nStrokes);
|
||
|
ASSERT (pPathElem->iAlt < pLat->pAltList[pPathElem->iStroke].nUsed);
|
||
|
|
||
|
pElem = pLat->pAltList[pPathElem->iStroke].alts + pPathElem->iAlt;
|
||
|
|
||
|
// FEATURE 0: is this a real char
|
||
|
pFeat[cFeat++] = 65535;
|
||
|
|
||
|
// FEATURE 1: # of strokes
|
||
|
pFeat[cFeat++] = min (65535, pElem->nStrokes * 1000);
|
||
|
|
||
|
// FEATURE 2: -log prob
|
||
|
pFeat[cFeat++] = min (65535, (int) (-1000.0 * pElem->logProb));
|
||
|
|
||
|
// FEATURE 3: unigram of code point
|
||
|
pFeat[cFeat++] =
|
||
|
min (65535, (int) (-255.0 * UnigramCost (&g_unigramInfo, pElem->wChar)));
|
||
|
|
||
|
// feature 4: char detector score
|
||
|
if (pElem->iCharDetectorScore == -1)
|
||
|
{
|
||
|
pElem->iCharDetectorScore =
|
||
|
min (65535, (int) (65535.0 * FuguSegScore (pElem->nStrokes,
|
||
|
pLat->pStroke + pPathElem->iStroke - pElem->nStrokes + 1,
|
||
|
&g_locRunInfo)));
|
||
|
}
|
||
|
|
||
|
pFeat[cFeat++] = max (min (65535, pElem->iCharDetectorScore), 0);
|
||
|
|
||
|
|
||
|
// char pair features
|
||
|
if (iChar > 0)
|
||
|
{
|
||
|
int xDist, yHgt;
|
||
|
|
||
|
ASSERT (pPrevElem != NULL);
|
||
|
|
||
|
// FEATURE 0: bigram pair
|
||
|
pFeat[cFeat++] = min (65536,
|
||
|
(int) (-1000.0 * BigramTransitionCost (&g_locRunInfo, &g_bigramInfo,
|
||
|
pPrevElem->wChar, pElem->wChar)));
|
||
|
|
||
|
// FEATURE 1: normalized delx
|
||
|
xDist = pElem->bbox.left - pPrevElem->bbox.right;
|
||
|
yHgt = 1 + ( (pElem->bbox.bottom - pElem->bbox.top) +
|
||
|
(pPrevElem->bbox.bottom - pPrevElem->bbox.top)
|
||
|
) / 2;
|
||
|
|
||
|
pFeat[cFeat++] = 32768 +
|
||
|
max (-32767, min (32767, (int)(32768.0 * xDist / (abs(xDist) + yHgt))));
|
||
|
|
||
|
// FEATURE 2: output of brk net after prev char
|
||
|
pFeat[cFeat++] = iBrkNetOut;
|
||
|
}
|
||
|
|
||
|
iBrkNetOut = pLat->pAltList[pPathElem->iStroke].iBrkNetScore;
|
||
|
pPrevElem = pElem;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return cFeat;
|
||
|
}
|
||
|
|
||
|
|
||
|
// frees an ink segment
|
||
|
void FreeInkSegment (INK_SEGMENT *pInkSegment)
|
||
|
{
|
||
|
int iSeg;
|
||
|
|
||
|
for (iSeg = 0; iSeg < pInkSegment->cSegm; iSeg++)
|
||
|
{
|
||
|
if (pInkSegment->ppSegm[iSeg])
|
||
|
{
|
||
|
FreeElemList (pInkSegment->ppSegm[iSeg]);
|
||
|
|
||
|
ExternFree (pInkSegment->ppSegm[iSeg]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pInkSegment->ppSegm)
|
||
|
{
|
||
|
ExternFree (pInkSegment->ppSegm);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// featurize an ink segment
|
||
|
int FeaturizeInkSegment (LATTICE *pLat, INK_SEGMENT *pInkSegment, int *pFeat)
|
||
|
{
|
||
|
int iSeg,
|
||
|
cSegFeat,
|
||
|
cFeat = 0;
|
||
|
|
||
|
for (iSeg = 0; iSeg < pInkSegment->cSegm; iSeg++)
|
||
|
{
|
||
|
// featurize this segmentation
|
||
|
cSegFeat = FeaturizeSegmentation (pLat,
|
||
|
pInkSegment->ppSegm[iSeg], pFeat + cFeat);
|
||
|
|
||
|
// did we fail
|
||
|
if (cSegFeat <= 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// increment the number of features
|
||
|
cFeat += cSegFeat;
|
||
|
}
|
||
|
|
||
|
return cFeat;
|
||
|
}
|
||
|
|