|
|
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//
// Copyright (c) 2001 Microsoft Corporation. All rights reserved.
//
// Module:
// volcano/dll/segmnet.c
//
// Description:
// Functions to implement the functionality of the segmentation 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 segmentations net used in Free mode
static int s_aiSegmNetSize[MAX_SEGMENTATIONS + 1]; static LOCAL_NET s_aSegmNet[MAX_SEGMENTATIONS + 1];
// validates the header of the brknet
int CheckSegmNetHeader (void *pData) { NNET_HEADER *pHeader = (NNET_HEADER *)pData;
// wrong magic number
ASSERT (pHeader->dwFileType == SEGMNET_FILE_TYPE);
if (pHeader->dwFileType != SEGMNET_FILE_TYPE) { return FALSE; }
// check version
ASSERT(pHeader->iFileVer >= SEGMNET_OLD_FILE_VERSION); ASSERT(pHeader->iMinCodeVer <= SEGMNET_CUR_FILE_VERSION);
ASSERT ( !memcmp ( pHeader->adwSignature, g_locRunInfo.adwSignature, sizeof (pHeader->adwSignature) ) );
if ( pHeader->iFileVer >= SEGMNET_OLD_FILE_VERSION && pHeader->iMinCodeVer <= SEGMNET_CUR_FILE_VERSION && !memcmp ( pHeader->adwSignature, g_locRunInfo.adwSignature, sizeof (pHeader->adwSignature) ) ) { return pHeader->cSpace; } else { return 0; } }
// does the necessary preparations for a net to be used later
static BOOL PrepareSegmNet(BYTE *pData) { int iSpc, cSpc, iSpaceID; NNET_SPACE_HEADER *pSpaceHeader; BYTE *pPtr, *pNetData;
if (!pData) { return FALSE; }
// init all nets data
memset (s_aiSegmNetSize, 0, sizeof (s_aiSegmNetSize)); memset (s_aSegmNet, 0, sizeof (s_aSegmNet));
// check the header info
cSpc = CheckSegmNetHeader (pData); if (cSpc <= 0) { return FALSE; } pPtr = pData + sizeof (NNET_HEADER);
for (iSpc = 0; iSpc < cSpc; iSpc++) { // point to the one and only space that we have
pSpaceHeader = (NNET_SPACE_HEADER *)pPtr; pPtr += sizeof (NNET_SPACE_HEADER);
// point to the actual data
pNetData = pData + pSpaceHeader->iDataOffset; iSpaceID = pSpaceHeader->iSpace;
if (iSpaceID < 2 || iSpaceID > MAX_SEGMENTATIONS) { ASSERT (iSpaceID >= 2 && iSpaceID <= MAX_SEGMENTATIONS); return FALSE; }
// restore the connections
if (!restoreLocalConnectNet(pNetData, 0, s_aSegmNet + iSpaceID)) { return FALSE; }
// compute the run time memory requirements of the net
s_aiSegmNetSize[iSpaceID] = getRunTimeNetMemoryRequirements(pNetData);
if (s_aiSegmNetSize[iSpaceID] <= 0) { return FALSE; } }
return TRUE; }
// load the brk net from resources
BOOL LoadSegmNetFromFile(wchar_t *pwszRecogDir, LOAD_INFO *pLoadInfo) { BYTE *pData; wchar_t awszFileName[MAX_PATH]; wsprintf (awszFileName, L"%s\\segmnet.bin", pwszRecogDir);
// memory map the file
pData = DoOpenFile (pLoadInfo, awszFileName); if (!pData) { return FALSE; }
// prepare Brk net
if (!PrepareSegmNet(pData)) { return FALSE; }
return TRUE; }
// load the brk net from resources
BOOL LoadSegmNetFromResource (HINSTANCE hInst, int nResID, int nType) { BYTE *pData; LOAD_INFO LoadInfo; // init the size to zero, in case we fail
pData = DoLoadResource (&LoadInfo, hInst, nResID, nType); if (!pData) { return FALSE; }
// prepare Brk net
if (!PrepareSegmNet(pData)) { return FALSE; }
return TRUE; }
// update segmentations in the lattice by running a neural
// net that picks a segmentation from a list within an inksegment
BOOL UpdateSegmentations (LATTICE *pLat, int iStrtStrk, int iEndStrk) { int iNet, iSeg, jSeg, cStrk, cFeat, iWinner, cOut, iWord, iStrk, iAlt;
BOOL bRet = FALSE, b;
RREAL *pNetBuffer, *pNetOut;
INK_SEGMENT InkSegment;
// Check to see if we loaded the segmentation nets.
// If not just exit
if (s_aiSegmNetSize[2] <= 0) { return TRUE; }
// create the range
memset (&InkSegment, 0, sizeof (INK_SEGMENT)); InkSegment.StrokeRange.iStartStrk = iStrtStrk; InkSegment.StrokeRange.iEndStrk = iEndStrk;
// alloc memory for the back path
cStrk = iEndStrk - iStrtStrk + 1; // harvest the segmentations that made it to the final stroke in the ink segment
b = EnumerateInkSegmentations (pLat, &InkSegment); if (!b || InkSegment.cSegm < 1) { goto exit; }
// if the number of segmentations is greater than max_seg, or less than two
// then there is nothing for us to do
if (InkSegment.cSegm < 2 || InkSegment.cSegm > MAX_SEGMENTATIONS) { iWinner = 0; } else { // sort segmentations by char count
for(iSeg = 0; iSeg < (InkSegment.cSegm - 1); iSeg++) { ELEMLIST *pSeg;
for (jSeg = iSeg + 1; jSeg < InkSegment.cSegm; jSeg++) { if (InkSegment.ppSegm[iSeg]->cElem > InkSegment.ppSegm[jSeg]->cElem) { pSeg = InkSegment.ppSegm[iSeg]; InkSegment.ppSegm[iSeg] = InkSegment.ppSegm[jSeg]; InkSegment.ppSegm[jSeg] = pSeg; } } }
// run the appropriate segmentation net
iNet = InkSegment.cSegm;
pNetBuffer = (RREAL *) ExternAlloc (s_aiSegmNetSize[iNet] * sizeof (*pNetBuffer)); if (!pNetBuffer) { goto exit; }
// featurize this inksegment
cFeat = FeaturizeInkSegment (pLat, &InkSegment, (int *)pNetBuffer);
// run the net
pNetOut = runLocalConnectNet (&s_aSegmNet[iNet], pNetBuffer, &iWinner, &cOut); ASSERT (cOut == InkSegment.cSegm);
if (!pNetOut) { goto exit; }
ExternFree (pNetBuffer); } // reset the current path in the specified stroke range
for (iStrk = iStrtStrk; iStrk <= iEndStrk; iStrk++) { for (iAlt = 0; iAlt < pLat->pAltList[iStrk].nUsed; iAlt++) { pLat->pAltList[iStrk].alts[iAlt].fCurrentPath = FALSE; } }
// now mark the characters proposed by the winning segmentation as part
// of the best path
for (iWord = 0; iWord < InkSegment.ppSegm[iWinner]->cElem; iWord++) { iStrk = InkSegment.ppSegm[iWinner]->pElem[iWord].iStroke; iAlt = InkSegment.ppSegm[iWinner]->pElem[iWord].iAlt;
pLat->pAltList[iStrk].alts[iAlt].fCurrentPath = TRUE; }
bRet = TRUE;
exit: FreeInkSegment (&InkSegment);
return bRet; }
|