317 lines
6.4 KiB
C
317 lines
6.4 KiB
C
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
|
//
|
|
// Copyright (c) 2001 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Module:
|
|
// volcano/dll/brknet.c
|
|
//
|
|
// Description:
|
|
// Functions to implement the functionality of the break Neural net that
|
|
// modifies the lattice structure to correct segmentation errors.
|
|
//
|
|
// Author:
|
|
// ahmadab 11/05/01
|
|
//
|
|
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
|
|
|
#include "common.h"
|
|
#include "volcanop.h"
|
|
#include "lattice.h"
|
|
#include "runnet.h"
|
|
#include "brknet.h"
|
|
#include "segm.h"
|
|
#include "nnet.h"
|
|
|
|
// the size and structure representing the Breaking net used in Free mode
|
|
// if the is not available for a particular configuration, s_iBrkNetSize will be zero
|
|
static int s_iBrkNetSize = 0;
|
|
static LOCAL_NET s_BrkNet;
|
|
|
|
// validates the header of the brknet
|
|
BOOL CheckBrkNetHeader (void *pData)
|
|
{
|
|
NNET_HEADER *pHeader = (NNET_HEADER *)pData;
|
|
|
|
// wrong magic number
|
|
ASSERT (pHeader->dwFileType == BRKNET_FILE_TYPE);
|
|
|
|
if (pHeader->dwFileType != BRKNET_FILE_TYPE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// check version
|
|
ASSERT(pHeader->iFileVer >= BRKNET_OLD_FILE_VERSION);
|
|
ASSERT(pHeader->iMinCodeVer <= BRKNET_CUR_FILE_VERSION);
|
|
|
|
ASSERT ( !memcmp ( pHeader->adwSignature,
|
|
g_locRunInfo.adwSignature,
|
|
sizeof (pHeader->adwSignature)
|
|
)
|
|
);
|
|
|
|
ASSERT (pHeader->cSpace == 1);
|
|
|
|
if ( pHeader->iFileVer >= BRKNET_OLD_FILE_VERSION &&
|
|
pHeader->iMinCodeVer <= BRKNET_CUR_FILE_VERSION &&
|
|
!memcmp ( pHeader->adwSignature,
|
|
g_locRunInfo.adwSignature,
|
|
sizeof (pHeader->adwSignature)
|
|
) &&
|
|
pHeader->cSpace == 1
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// does the necessary preparations for a net to be used later
|
|
static LOCAL_NET *PrepareBrkNet(BYTE *pData, int *piNetSize, LOCAL_NET *pNet)
|
|
{
|
|
NNET_SPACE_HEADER *pSpaceHeader;
|
|
|
|
if (!pData)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// check the header info
|
|
if (!CheckBrkNetHeader (pData))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// point to the one and only space that we have
|
|
pSpaceHeader = (NNET_SPACE_HEADER *)(pData + sizeof (NNET_HEADER));
|
|
|
|
// point to the actual data
|
|
pData = pData + pSpaceHeader->iDataOffset;
|
|
|
|
// restore the connections
|
|
if (!(pNet = restoreLocalConnectNet(pData, 0, pNet)) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// compute the run time memory requirements of the net
|
|
(*piNetSize) = getRunTimeNetMemoryRequirements(pData);
|
|
|
|
if ((*piNetSize) <= 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pNet;
|
|
}
|
|
|
|
// load the brk net from resources
|
|
BOOL LoadBrkNetFromFile(wchar_t *pwszRecogDir, LOAD_INFO *pLoadInfo)
|
|
{
|
|
BYTE *pData;
|
|
wchar_t awszFileName[MAX_PATH];
|
|
|
|
// init the size to zero, in case we fail
|
|
s_iBrkNetSize = 0;
|
|
|
|
swprintf (awszFileName, L"%s\\brknet.bin", pwszRecogDir);
|
|
|
|
// memory map the file
|
|
pData = DoOpenFile (pLoadInfo, awszFileName);
|
|
if (!pData)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare Brk net
|
|
if (!PrepareBrkNet(pData, &s_iBrkNetSize, &s_BrkNet))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// load the brk net from resources
|
|
BOOL LoadBrkNetFromResource (HINSTANCE hInst, int nResID, int nType)
|
|
{
|
|
BYTE *pData;
|
|
LOAD_INFO LoadInfo;
|
|
|
|
// init the size to zero, in case we fail
|
|
s_iBrkNetSize = 0;
|
|
|
|
pData = DoLoadResource (&LoadInfo, hInst, nResID, nType);
|
|
if (!pData)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare the net
|
|
if (!PrepareBrkNet(pData, &s_iBrkNetSize, &s_BrkNet))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// update the lattice by running the BRK-NET on all the possible break points.
|
|
// Currently only one segmentation survives which is the one suggested by the BRK-NET
|
|
// returns the number of charcaters in the updated lattice on success, -1 upon failure
|
|
int UpdateLattice (LATTICE *pLat)
|
|
{
|
|
int iPos,
|
|
iStrk,
|
|
cStrk,
|
|
iWinner,
|
|
cOut,
|
|
cBrk;
|
|
|
|
BOOL *pIsBreak = NULL;
|
|
|
|
BRKPT *pBrk = NULL;
|
|
|
|
RREAL *pNetMem = NULL,
|
|
*pNetOut;
|
|
|
|
int iRet = -1,
|
|
iBrk;
|
|
|
|
// if the net has not been successfully loaded, we'll fail
|
|
if (s_iBrkNetSize <= 0)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// alloc memory for the Net's running buffer
|
|
pNetMem = (RREAL *) ExternAlloc (s_iBrkNetSize * sizeof (*pNetMem));
|
|
if (!pNetMem)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// create the break pts structure
|
|
cStrk = pLat->nStrokes;
|
|
pBrk = CreateBrkPtList (pLat);
|
|
|
|
// if we have succeeded, lets process these break points
|
|
if (pBrk)
|
|
{
|
|
// allocate a boolean struct to mark ON break points
|
|
pIsBreak = (BOOL *) ExternAlloc (cStrk * sizeof (*pIsBreak));
|
|
if (!pIsBreak)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// for all break points
|
|
for (iStrk = 0, cBrk = 0; iStrk < cStrk; iStrk++)
|
|
{
|
|
int iFeat, cFeat, aFeat[MAX_BRK_NET_FEAT];
|
|
|
|
// featurize for this break point
|
|
cFeat = FeaturizeBrkPt (pLat, pBrk + iStrk, aFeat);
|
|
ASSERT (cFeat <= MAX_BRK_NET_FEAT);
|
|
|
|
// prepare the nets input
|
|
for (iFeat = 0; iFeat < cFeat; iFeat++)
|
|
{
|
|
pNetMem[iFeat] = aFeat[iFeat];
|
|
}
|
|
|
|
// run the net
|
|
pNetOut = runLocalConnectNet (&s_BrkNet, pNetMem, &iWinner, &cOut);
|
|
ASSERT (cOut == 2);
|
|
|
|
// this is considered a hard break point if the net's output is higher than the threshold
|
|
pIsBreak[iStrk] = pNetOut[1] >= (BREAKING_THRESHOLD);
|
|
|
|
// mark it a as a breakpoint
|
|
if (pIsBreak[iStrk])
|
|
{
|
|
cBrk++;
|
|
}
|
|
|
|
// copy the score in the lattice
|
|
pLat->pAltList[iStrk].iBrkNetScore = pNetOut[1];
|
|
}
|
|
|
|
ASSERT (cBrk <= cStrk);
|
|
|
|
// make sure there is a break point always at the end,
|
|
if (!pIsBreak[cStrk - 1])
|
|
{
|
|
pIsBreak[cStrk - 1] = TRUE;
|
|
cBrk++;
|
|
}
|
|
|
|
// clear out all the existing alternate lists at every stroke
|
|
for (iStrk = 0; iStrk < cStrk; iStrk++)
|
|
{
|
|
ClearAltList (pLat->pAltList + iStrk);
|
|
}
|
|
|
|
// change the lattice to reflect the new segmentation
|
|
for (iBrk = iStrk = 0; iBrk < cBrk; iBrk++)
|
|
{
|
|
iPos = iStrk;
|
|
|
|
// find the next break point
|
|
while (!pIsBreak[iStrk] && iStrk < cStrk)
|
|
{
|
|
iStrk++;
|
|
}
|
|
|
|
// build the alt list at the the ending stroke with the
|
|
// current stroke being the starting one
|
|
//BuildStrokeCountRecogAlts(pLat, iStrk, iStrk - iPos + 1);
|
|
|
|
if (!ProcessLatticeRange (pLat, iPos, iStrk))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
UpdateSegmentations (pLat, iPos, iStrk);
|
|
|
|
iStrk++;
|
|
}
|
|
|
|
// Mark the best path through the lattice
|
|
//iRet = FindFullPath (pLat);
|
|
FixupBackPointers (pLat);
|
|
}
|
|
|
|
exit:
|
|
|
|
// free the local buffers if had been allocated
|
|
if (pBrk)
|
|
{
|
|
FreeBreaks (cStrk, pBrk);
|
|
}
|
|
|
|
if (pIsBreak)
|
|
{
|
|
ExternFree (pIsBreak);
|
|
}
|
|
|
|
if (pNetMem)
|
|
{
|
|
ExternFree (pNetMem);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
void BrkNetUnloadfile (LOAD_INFO *pLoadInfo)
|
|
{
|
|
if (s_iBrkNetSize != 0)
|
|
{
|
|
DoCloseFile (pLoadInfo);
|
|
}
|
|
}
|