📄 bars2symupc.cpp
字号:
}
(*pResult)[i] = sum / sumWeights;
}
Mem::Copy((TAny*) vector, (TAny*) &(*pResult)[0], nLength*sizeof(TReal));
CleanupStack::PopAndDestroy(pResult);
}
void CBars2SymUpc::BuildLeftSideMaskL(Code& code, TInt16*& pnMask, TInt &width)
{
TReal pfMask[MidOffset + MidWidth];
width = MidOffset + MidWidth;
// build left mask
pfMask[0] = -1.0;
pfMask[1] = 1.0;
pfMask[2] = -1.0;
TInt d;
// add digit mask
for (d=0; d<Digits; d++) {
Mem::Copy((TAny*) &pfMask[LeftWidth + d*DigitWidth],
(TAny*) &iDigitCodes[code[d]][0],
DigitWidth * sizeof(TReal));
}
// add right mask
pfMask[MidOffset] = -1.0;
pfMask[MidOffset+1] = 1.0;
pfMask[MidOffset+2] = -1.0;
pfMask[MidOffset+3] = 1.0;
pfMask[MidOffset+4] = -1.0;
BlurPatternL(pfMask, width);
pnMask = new (ELeave) TInt16 [width];
// note code below can't leave
NormalizePattern(
pfMask,
width,
pnMask,
true,
true);
}
void CBars2SymUpc::BuildRightSideMaskL(Code& code, TInt16*& pnMask, TInt &width)
{
TReal pfMask[MidWidth + Digits*DigitWidth + RightWidth];
width = MidWidth + Digits*DigitWidth + RightWidth;
// build mid mask
pfMask[0] = -1.0;
pfMask[1] = 1.0;
pfMask[2] = -1.0;
pfMask[3] = 1.0;
pfMask[4] = -1.0;
TInt d;
// add digit mask -- reversed because of b/w reversal on right
for (d=0; d<Digits; d++) {
TInt i;
for (i=0; i<DigitWidth; i++) {
pfMask[MidWidth + d*DigitWidth + i] = -iDigitCodes[code[d]][i];
}
}
// add right mask
TInt rightOffset = MidWidth + Digits*DigitWidth;
pfMask[rightOffset] = -1.0;
pfMask[rightOffset+1] = 1.0;
pfMask[rightOffset+2] = -1.0;
BlurPatternL(pfMask, width);
pnMask = new (ELeave) TInt16 [width];
// note code below can't leave
NormalizePattern(
pfMask,
width,
pnMask,
true,
true);
}
void CBars2SymUpc::ClearHash()
{
iHashLeft->Clear();
iHashRight->Clear();
if (iCodes) {
int i;
for (i=0; i<iCodes->Count(); i++) {
delete iCodes->At(i);
}
iCodes->Reset();
}
}
void CBars2SymUpc::ComputeCoefficientsL()
{
ipfCoeff = new (ELeave) CArrayFixFlat<TReal>(128);
const TReal threshold = 0.05;
// = Sqrt(2*Pi)
const TReal Sqrt2Pi = 2.506628274631000;
TReal denom1 = 1.0 / (Sqrt2Pi * ifSigma);
TReal denom2 = 1.0 / (2.0 * ifSigma * ifSigma);
TInt x = 0;
TReal coeff;
do {
TReal exp;
Math::Exp(exp, -x * x * denom2);
coeff = denom1 * exp;
ipfCoeff->AppendL(coeff);
x += 1;
} while (coeff > threshold); // track through end of tail
// now normalize so the sum is 1, taking into account
// the symmetric pattern of the weights, of which we've
// computed one side
TReal sum = ipfCoeff->At(0);
TInt i;
for (i=1; i<ipfCoeff->Count(); i++) {
sum += ipfCoeff->At(i) * 2;
}
for (i=0; i<ipfCoeff->Count(); i++) {
ipfCoeff->At(i) /= sum;
}
}
TInt32 CBars2SymUpc::Convolve(
IGrayIndex index,
TInt16 *pnWeights,
TInt nLength,
TInt nPixelsPerBar,
TInt nRow,
TInt nPos)
{
TInt32 nConv = 0;
TInt j;
for (j=0; j<nLength; j++) {
TInt k;
for (k=0; k<nPixelsPerBar; k++) {
nConv += TInt32(index[nRow][nPos + j*nPixelsPerBar + k]) * TInt32(pnWeights[j]);
}
}
return nConv;
}
TInt32 CBars2SymUpc::Convolve(
CArray<unsigned char> &row,
TInt16 *pnWeights,
TInt nLength,
TInt nPixelsPerBar,
TInt nCol)
{
TInt32 nConv = 0;
TInt j;
for (j=0; j<nLength; j++) {
TInt k;
for (k=0; k<nPixelsPerBar; k++) {
nConv += TInt32(row[nCol + j*nPixelsPerBar + k]) * TInt32(pnWeights[j]);
}
}
return nConv;
}
/*
Input: a rectified and normalized image of a UPC barcode.
Output: the UPC barcode and a measure of the "goodness" of the
match between the barcode and its image.
Make guesses at the left and right barcodes for each row.
For each reasonably popular guess at the left barcode,
form a mask based on its digits and convolve it with
a vertically average of the barcode image, storing the
convolution result.
Repeat this with each reasonably popular guess at the right barcode.
For each pair of guesses at the left and right barcodes,
check to see if the pair passes the check digit test.
If it does, take its combined convolution result, and
compare it with the best convolution result so far.
If it is better, this pair is the new best guess at the barcode.
*/
IMPORT_C bool CBars2SymUpc::DecodeL(
CImage image,
CBars2Sym::CodeType*& pCode,
TInt32 &goodness)
{
pCode = NULL; // no return
IImageSize size(image);
int pixelsPerBar = size.Width() / TotalWidth;
TInt avgLeftEdge;
// estimate the barcodes on the left and right side
// for each row in the image and store them into hash
// tables
EstimateBarcodesL(image, avgLeftEdge);
// form the vertical average of the image for verifying
// the codes
CVerticalAverage *pAvg = CVerticalAverage::NewL();
CleanupStack::PushL(pAvg);
CArray<unsigned char> *pSum;
pAvg->DoItL(image, pSum);
CleanupStack::PopAndDestroy(pAvg);
CleanupStack::PushL(pSum);
CArrayFixFlat<CodeConv> *pLeftCodes;
// take the most common left barcodes and estimate their
// match with the left side of the average
/*
The point of the code below is that EstimateBarcodesL
does not use an exact test. As we form the barcode guesses
in EstimateBarcodesL, we generate the next digit by testing
all pairs combined with the previous digit. This forms the
best guess at a digit by taking into account the blurring
that results from the digit to the left, but ignores the
blurring that results from the digit to the right. So we
need a way to weed out those guesses where the inaccuracy
of considering just pairs of digits from left to right
results in a bad result. When we form the complete digit
mask in GrabBestBarcodesL we blur both to the left and right,
so that the match estimate is more exact. Also, by convolving
with a vertically averaged barcode image, we eliminate as much
noise as possible.
*/
if (!GrabBestBarcodesL(*iHashLeft, pSum, size.Height(), pixelsPerBar, avgLeftEdge, pLeftCodes, true)) {
CleanupStack::PopAndDestroy(pSum);
return false;
}
CleanupDeletePushL(pLeftCodes);
CArrayFixFlat<CodeConv> *pRightCodes;
// take the most common right barcodes and estimate their
// match with the right side of the image
if (!GrabBestBarcodesL(*iHashRight, pSum, size.Height(), pixelsPerBar, avgLeftEdge, pRightCodes, false)) {
CleanupStack::PopAndDestroy(pLeftCodes);
CleanupStack::PopAndDestroy(pSum);
return false;
}
CleanupDeletePushL(pRightCodes);
goodness = KMinTInt32;
pCode = NULL;
TInt nLeft;
// combine the left and right barcode estimates
// and verify the check digit. Maximize the match
// over all pairs of left and right barcodes.
for (nLeft = 0; nLeft < pLeftCodes->Count(); nLeft++) {
TInt nRight;
for (nRight = 0; nRight < pRightCodes->Count(); nRight++) {
TInt32 thisGoodness = (*pLeftCodes)[nLeft].Conv() + (*pRightCodes)[nRight].Conv();
if (thisGoodness > goodness) {
TBuf8<Digits*2> completeCode;
completeCode.Append((*pLeftCodes)[nLeft].Code());
completeCode.Append((*pRightCodes)[nRight].Code());
if (VerifyCheckDigit(completeCode)) {
if (pCode) {
delete pCode;
}
pCode = TurnDigitsToText(completeCode);
goodness = thisGoodness;
}
}
}
}
CleanupStack::PopAndDestroy(pRightCodes);
CleanupStack::PopAndDestroy(pLeftCodes);
CleanupStack::PopAndDestroy(pSum);
return (pCode != NULL);
}
TBool CBars2SymUpc::EstimateBarcodesL(CImage image, TInt &avgLeftEdge)
{
ClearHash();
IImageSize size(image);
int pixelsPerBar = size.Width() / TotalWidth;
TInt row;
TInt sumLeftEdge = 0;
for (row = 0; row<size.Height(); row++) {
TInt nOffset = EstimateLeftEdge(image, row);
if (nOffset < 0) {
return false;
}
sumLeftEdge += nOffset;
TBuf8<Digits> code;
EstimateCodeLeftL(image, row, nOffset, code);
if (iHashLeft->Find((Code*)&code[0])) {
iHashLeft->Value() += 1;
} else {
TBuf8<Digits> *pCode = new (ELeave) TBuf8<Digits>;
pCode->Copy(code);
iCodes->AppendL(pCode); // so it gets deleted later
iHashLeft->AddL((Code*)&(*pCode)[0], 1);
}
EstimateCodeRightL(image, row, nOffset + MidOffset * pixelsPerBar, code);
if (iHashRight->Find((Code*)&code[0])) {
iHashRight->Value() += 1;
} else {
TBuf8<Digits> *pCode = new (ELeave) TBuf8<Digits>;
pCode->Copy(code);
iCodes->AppendL(pCode); // so it gets deleted later
iHashRight->AddL((Code*)&(*pCode)[0], 1);
}
}
avgLeftEdge = sumLeftEdge / size.Height();
return true;
}
/*
The guesses at the left barcodes are made here.
CBars2SymUpc::BuildLeftSideMaskL has built one hundred masks, one for each
of the digit pairs 00, 01,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -