📄 bars2symupcx2.cpp
字号:
//
// Bars2SymUpc
// Given an array of bar code widths read a UPC bar
// code, if present.
//
// This code was written based on the Wikipedia entry for the
// UPC barcode: http://en.wikipedia.org/wiki/Universal_Product_Code.
//
// Copyright (C) 2006 by Jon A. Webb
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
//
#include "Bars2SymUpc.h"
#include "Array.h"
#include "GrayIndex.h"
#include "HistEq.h"
#include "ImageSize.h"
#include "RectStretch.h"
#include "Sequence.h"
using namespace Algorithm;
using namespace Barcode;
using namespace Core;
class CodeValue
{
public:
CodeValue(TInt conv)
{
this->iConv = conv;
this->iCount = 1;
}
void Add(TInt conv)
{
this->iCount ++;
this->iConv = Max(this->iConv, conv);
}
TInt Conv() const
{
return iConv;
}
TInt Count() const
{
return iCount;
}
private:
TInt iConv;
TInt iCount;
};
CBars2SymUpc::~CBars2SymUpc(void)
{
ClearHash();
delete iCodes;
iCodes = NULL;
ipfCoeff->Reset();
delete ipfCoeff;
ipfCoeff = NULL;
}
EXPORT_C CBars2SymUpc* CBars2SymUpc::NewL()
{
CBars2SymUpc *pMe = new (ELeave) CBars2SymUpc();
CleanupStack::PushL(pMe);
pMe->ConstructL();
CleanupStack::Pop(pMe);
return pMe;
}
CBars2SymUpc::CBars2SymUpc() :
CBars2Sym(),
ifSigma(0.2)
{
}
void CBars2SymUpc::ConstructL()
{
/* The (L) codes for the ten digits are:
0 = 3-2-1-1 = 0001101 = 0x0d
1 = 2-2-2-1 = 0011001 = 0x19
2 = 2-1-2-2 = 0010011 = 0x13
3 = 1-4-1-1 = 0111101 = 0x3d
4 = 1-1-3-2 = 0100011 = 0x23
5 = 1-2-3-1 = 0110001 = 0x31
6 = 1-1-1-4 = 0101111 = 0x2f
7 = 1-3-1-2 = 0111011 = 0x3b
8 = 1-2-1-3 = 0110111 = 0x37
9 = 3-1-1-2 = 0001011 = 0x0b
*/
// The R codes for the digits are the 1-complements
// of the L codes. But we encode the R digits by
// encoded a white bar as 1 and a black bar as 0
// so we automatically get the 1-complement without
// while using the same table
char digitCodes[] = {0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b};
int i;
// initialize convolution table
// on the left side we append -1 and on the right side
// we apend +1
// because we expect that each barcode will be preceded
// by a black and followed by a white stripe
TReal conv[10][DigitWidth];
for (i=0; i<10; i++) {
char digitCode = digitCodes[i];
int j;
for (j=DigitWidth-1;j>=0;j--) {
if (digitCode & 1) {
conv[i][j] = -1.0;
} else {
conv[i][j] = 1.0;
}
digitCode = digitCode >> 1;
}
}
ComputeCoefficientsL();
// form left digit convolution masks
for (i=0; i<10; i++) {
int j;
for (j=0; j<10; j++) {
TReal fConvLeft[LeftWidth+DigitWidth*2];
fConvLeft[0] = -1.0;
fConvLeft[1] = 1.0;
fConvLeft[2] = -1.0;
Mem::Copy(
(TAny*) &fConvLeft[LeftWidth],
(TAny*) conv[i],
DigitWidth*sizeof(TReal));
Mem::Copy(
(TAny*) &fConvLeft[LeftWidth+DigitWidth],
(TAny*) conv[j],
DigitWidth*sizeof(TReal));
BlurPatternL(fConvLeft, LeftWidth+DigitWidth*2);
NormalizePattern(fConvLeft, LeftWidth+DigitWidth*2, iLeftConv[i][j], true, true);
}
}
// form middle digit convolution masks
for (i=0; i<10; i++) {
int j;
for (j=0; j<10; j++) {
TReal fConvMid[MidWidth+DigitWidth*2];
// Note: we reverse the sign of the middle convolution mask
// because the right side of the barcode exchanges white
// and black, and we subtract the convolution sum to compensate.
// In order for the middle pattern (which isn't reversed) to be convolved
// properly it must therefore be convolved with inverted weights.
fConvMid[0] = 1.0;
fConvMid[1] = -1.0;
fConvMid[2] = 1.0;
fConvMid[3] = -1.0;
fConvMid[4] = 1.0;
Mem::Copy(
(TAny*) &fConvMid[MidWidth],
(TAny*) conv[i],
DigitWidth*sizeof(TReal));
Mem::Copy(
(TAny*) &fConvMid[MidWidth+DigitWidth],
(TAny*) conv[j],
DigitWidth*sizeof(TReal));
BlurPatternL(fConvMid, MidWidth+DigitWidth*2);
NormalizePattern(fConvMid, MidWidth+DigitWidth*2, iMidConv[i][j], true, true);
}
}
// form adjacent digit convolution masks
for (i=0; i<10; i++) {
int j;
for (j=0; j<10; j++) {
TReal fConvPairs[DigitWidth*2];
Mem::Copy(
(TAny*) fConvPairs,
(TAny*) conv[i],
DigitWidth*sizeof(TReal));
Mem::Copy(
(TAny*) &fConvPairs[DigitWidth],
(TAny*) conv[j],
DigitWidth*sizeof(TReal));
// now blur the convolution patterns, scale and convert to int,
// then release memory
BlurPatternL(fConvPairs, DigitWidth*2);
NormalizePattern(fConvPairs,
DigitWidth*2,
iPairConv[i][j],
true,
true);
}
}
iCodes = new (ELeave) CArrayFixFlat<TBuf8<Digits*2>*>(16);
}
void CBars2SymUpc::BlurPatternL(TReal* vector, TInt nLength) const
{
CArray<TReal> *pResult = CArray<TReal>::NewL(nLength);
CleanupStack::PushL(pResult);
int i;
for (i=0; i<nLength; i++) {
int j;
TReal sum = 0.0;
TReal sumWeights = 0.0;
for (j=Max(0,i-ipfCoeff->Count()+1);
j<Min(nLength, i+ipfCoeff->Count());
j++) {
TReal weight = ipfCoeff->At(Abs(i-j));
sumWeights += weight;
sum += weight * vector[j];
}
(*pResult)[i] = sum / sumWeights;
}
Mem::Copy((TAny*) vector, (TAny*) &(*pResult)[0], nLength*sizeof(TReal));
CleanupStack::PopAndDestroy(pResult);
}
void CBars2SymUpc::ClearHash()
{
if (iHash) {
if (iHash->First()) {
do {
// delete the stored values
delete (CodeValue *)iHash->Value();
} while (iHash->Next());
}
delete iHash;
iHash = NULL;
}
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;
}
}
IMPORT_C bool CBars2SymUpc::DecodeL(
CImage image,
TRect rectangle,
CBars2Sym::CodeType*& pCode)
{
pCode = NULL; // no return
int CountDigits[Digits*2][10];
Mem::FillZ((TAny*) CountDigits, sizeof(CountDigits));
IImageSize size(image);
int i;
iHash = CHashTable::NewL(7);
int pixelsPerBar = size.Width() / TotalWidth;
TInt row;
int totalConv = 0;
for (row = 0; row<size.Height(); row++) {
TInt nOffset = EstimateLeftEdge(image, row);
TBuf8<Digits*2> code;
code.SetMax();
image.LockLC();
IGrayIndex index(image);
int pos = nOffset; // position of start of barcode pattern
int bestDigit = -1, bestDigit1 = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -