windows-nt/Source/XPSP1/NT/drivers/tpg/hwx/volcano/dll/segmnet.c
2020-09-26 16:20:57 +08:00

291 lines
6.3 KiB
C

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//
// 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;
}