EAN条形码译码器代码.docx
《EAN条形码译码器代码.docx》由会员分享,可在线阅读,更多相关《EAN条形码译码器代码.docx(37页珍藏版)》请在冰豆网上搜索。
EAN条形码译码器代码
#include
#include
#include
#include
#include
#defineBI_RGB0L
#defineBI_RLE81L
#defineBI_RLE42L
#defineBI_BITFIELDS3L
typedefstruct{
unsignedcharrgbBlue;
unsignedcharrgbGreen;
unsignedcharrgbRed;
unsignedcharrgbReserved;
}RGBQUAD;
typedefstruct{
unsignedlongbiSize;
longbiWidth;
longbiHeight;
unsignedshortbiPlanes;
unsignedshortbiBitCount;
unsignedlongbiCompression;
unsignedlongbiSizeImage;
longbiXPelsPerMeter;
longbiYPelsPerMeter;
unsignedlongbiClrUsed;
unsignedlongbiClrImportant;
}BITMAPINFOHEADER;
typedefstruct{
BITMAPINFOHEADERbmiHeader;
RGBQUADbmiColors[1];
}BITMAPINFO;
#include/////
typedefstruct{
unsignedshortbfType;
unsignedlongbfSize;
unsignedshortbfReserved1;
unsignedshortbfReserved2;
unsignedlongbfOffBits;
}BITMAPFILEHEADER;
#include
/*
参考BMP文件格式
*/
intReadBMPToBuf(char*FileName,unsignedchar**RawImageData,int*ImageWidth,int*ImageHeight)
{
BITMAPFILEHEADERbmfileh;//BMP文件头变量
BITMAPINFOHEADERbminfoh;//位图信息头
FILE*fp;
intTotalPixelNumber;
fp=fopen(FileName,"rb");//读写打开一个二进制文件,允许读数据
if(fp==NULL)
{
return-1;
}
ints1=sizeof(bmfileh);//求文件头字节数,
ints2=sizeof(bminfoh);//求位图信息头字节数,
fread(&bmfileh,1,sizeof(bmfileh),fp);
fread(&bminfoh,1,sizeof(bminfoh),fp);
*ImageHeight=abs(bminfoh.biHeight);
*ImageWidth=bminfoh.biWidth;
//TotalPixelNumber=bmih.biHeight*(bmih.biWidth);
TotalPixelNumber=bmfileh.bfSize-bmfileh.bfOffBits;
fseek(fp,bmfileh.bfOffBits,SEEK_SET);//指针偏移bmfileh.bfoffbits。
//bfOffBitsSpecifiestheoffset,inbytes,fromtheBITMAPFILEHEADERstructureto
thebitmapbits.
*RawImageData=(unsignedchar*)calloc((TotalPixelNumber),sizeof(unsignedchar));//在内存
的动态存储区中分配连续空间。
fread(*RawImageData,1,TotalPixelNumber,fp);
fclose(fp);
///////////////////////////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////////////////////////
//
if(bminfoh.biHeight>0)
//SpecifiestheImageHeightofthebitmap,inpixels.IfbiHeightispositive,the
bitmapisabottom-upDIBanditsoriginisthelower-leftcorner.IfbiHeightisnegative,the
bitmapisatop-downDIBanditsoriginistheupper-leftcorner.
//IfbiHeightisnegative,indicatingatop-downDIB,biCompressionmustbeeither
BI_RGBorBI_BITFIELDS.Top-downDIBscannotbecompressed.
{
unsignedchar*RowBuffer=NULL;
RowBuffer=(unsignedchar*)calloc((*ImageWidth),sizeof(unsignedchar));
inti,j;
j=*ImageHeight/2;
unsignedchar*ptr1,*ptr2;
ptr1=*RawImageData;//第一行,
ptr2=*RawImageData+(*ImageHeight-1)*(*ImageWidth);//最后一行,
for(i=0;i{
memcpy(RowBuffer,ptr1,*ImageWidth);
memcpy(ptr1,ptr2,*ImageWidth);
memcpy(ptr2,RowBuffer,*ImageWidth);
ptr1+=*ImageWidth;
ptr2-=*ImageWidth;
}
free(RowBuffer);
RowBuffer=NULL;
}
return0;
}
/*
*cell输入图像数据
nw输入图像宽度
nh输入图像高度
*edge_position输出边界坐标
*edge_num输出边界坐标个数
*/
intGet_Bar_edge(unsignedchar*cellbuf,intnw,intnh,int*edge_position,int*edge_num)
{
inti,j;
int*vertical=newint[nw];//垂直投影值
float*fvertical=newfloat[nw];//归一化后的投影值
intPmax,Pmin,T1,ration;
enumEdgeType{wtb,btw};//定义边界的性质是聪白到黑,还是聪黑到白
EdgeType*edgetype=newEdgeType[nw];
intedgecount=0;//边界的个数
//投影
for(i=0;i{
vertical[i]=0;
for(j=0;j{
vertical[i]+=cellbuf[j*nw+i];
}
}
//归一化处理
Pmax=Pmin=vertical[0];
for(i=0;i{
if(vertical[i]if(vertical[i]>Pmax)Pmax=vertical[i];
}
ration=Pmax-Pmin;
for(i=0;ifvertical[i]=(float)(vertical[i]-Pmin)*nh/ration;
//开始寻找边界,定义边界跳变的阈值
T1=nh/3;
//第一个边界一定是从白到黑的
for(i=5;iif(fvertical[i-1]-fvertical[i+1]>T1)
{
edge_position[edgecount]=i;
edgetype[edgecount]=wtb;
edgecount++;
break;
}
while(i{
if(fabs(fvertical[i-1]-fvertical[i+1])>T1)
{
if(fvertical[i-1]>fvertical[i+1]&&edgetype[edgecount-1]==btw)
{
edge_position[edgecount]=i;
edgetype[edgecount]=wtb;
edgecount++;
}
if((fvertical[i-1]{
edge_position[edgecount]=i;
edgetype[edgecount]=btw;
edgecount++;
}
}
i++;
}
*edge_num=edgecount;
////////释放内存
delete[]vertical;
delete[]fvertical;
delete[]edgetype;
return0;
}
//////////////////////////////////////////////////////////////////////
intsgn(floatx)
{
if(x>0)return
(1);
if(x<0)return(-1);
return(0);
}
intGet_Bar_edge_a(unsignedchar*cellbuf,intnw,intnh,int*edge_position,int*edge_num)
{
inti,j,stdh=255,strx,endx,sign,ret;
intPmax,Pmin,T1,ration,edgennum;
enumEdgeType{wtb,btw};
EdgeType*edgetype=newEdgeType[nw];
intedgecount=0;
int*edge=newint[nw];
int*vertical=newint[nw];
int*vertical1=newint[nw];
float*fvertical=newfloat[nw];//归一化后的投影值
int*vdis=newint[nw];
//投影
for(i=0;i{
vertical[i]=0;
for(j=0;j{
vertical[i]+=cellbuf[j*nw+i];
}
}
memcpy(vertical1,vertical,nw*sizeof(int));
//对投影排序
for(i=0;i{
for(j=i+1;j{
if(vertical1[j]{
inttmpv=vertical1[j];
vertical1[j]=vertical1[i];
vertical1[i]=tmpv;
}
}
}
intnmeant=nw/20;
//取最小的%5的均值为下限
Pmin=0;
for(i=0;i{
Pmin+=vertical1[i];
}
Pmin=Pmin/nmeant;
//取最大的%5的均值为上限
Pmax=0;
for(i=nw-nmeant;i{
Pmax+=vertical1[i];
}
Pmax=Pmax/nmeant;
//Pmax=Pmin=vertical[0];
//
//for(i=0;i//{
//
//if(vertical[i]//if(vertical[i]>Pmax)Pmax=vertical[i];
//}
ration=Pmax-Pmin;
if(ration==0)
{
ret=-1;
gotoENDPOINT;
}
//归一化操作
for(i=0;i{
if(vertical[i]{
fvertical[i]=0;
}
else
if(vertical[i]>Pmax)
{
fvertical[i]=stdh;
}
else
fvertical[i]=(float)(vertical[i]-Pmin)*stdh/ration;
}
edgecount=0;
T1=stdh/5;//定义为边界的阈值,太大拒识率高,太低误识率高
strx=5;
sign=1;
i=5;
while(i<(nw-5))
{
vdis[i]=abs(fvertical[i+1]-fvertical[i-1]);
intsigne=sgn(fvertical[i+1]-fvertical[i]);
if(signe==sign||signe==0)//如果没有变化,说明是连续的增加或下降
{
i++;
continue;
}
//如果signe发生变化,说明出现了极值点(局部最大值为最小值)
if(fabs(fvertical[i]-fvertical[strx])>T1)//如果变化的幅度超过阈值,说明可能是边界
{
if((i-strx)<2)
edge[edgecount]=i;
else
if((i-strx)<3)
edge[edgecount]=strx+1;
else
{
intmaxvdis=vdis[strx+1];
intmaxedge=strx+1;
for(j=strx+1;j
{
if(vdis[j]>maxvdis)//找出边界投影值跳跃最大的地方,定义为
边界点
{//这个理论不总是正确
maxvdis=vdis[j];
maxedge=j;
}
}
edge[edgecount]=maxedge;
}
if((fvertical[i]-fvertical[strx])>0)//定义边界点的性质
edgetype[edgecount]=btw;
else
edgetype[edgecount]=wtb;
edgecount++;
}
strx=i;
i++;
sign=signe;
}
///////////////////////////////////////////
if(fabs(fvertical[i]-fvertical[strx])>T1)//最后一个边界点
{
if((i-strx)<2)
edge[edgecount]=i;
else
if((i-strx)<3)
edge[edgecount]=strx+1;
else
{
intmaxvdis=vdis[strx+1];
intmaxedge=strx+1;
for(j=strx+1;j
{
if(vdis[j]>maxvdis)
{
maxvdis=vdis[j];
maxedge=j;
}
}
edge[edgecount]=maxedge;
}
if((fvertical[i]-fvertical[strx])>0)
edgetype[edgecount]=btw;
else
edgetype[edgecount]=wtb;
edgecount++;
}
///////////////////////////////////////////////////
i=0;
while
(1)
{
if(i>=edgecount)break;
if(edgetype[i]==wtb)//起始点一定是从空到条,即从白到黑
break;
i++;
}
edgennum=0;
for(;i{
edge_position[edgennum]=edge[i];
edgennum++;
}
*edge_num=edgennum;
ret=0;
ENDPOINT:
delete[]vdis;
delete[]fvertical;
delete[]vertical;
delete[]vertical1;
delete[]edge;
delete[]edgetype;
returnret;
}
/*
2代表为空
1代表为条
一个数字由两个条两个空组成,总长度为7个单元模块
每个条或者空的宽度最长为4个模块
*/
#defineCELL_LEN7/*9barswithagap*/
/*
根据单元模块查找对应的数字
*/
staticintlook_up(char*one_code)
{
typedefstruct{
charsymbol;
charbarcode[20];
}LOOKUP_ENTRY;
staticLOOKUP_ENTRYlookup_table_ean13[30]={
{'0',"2221121"},{'0',"2122111"},{'0',"1112212"},
{'1',"2211221"},{'1',"2112211"},{'1',"1122112"},
{'2',"2212211"},{'2',"2211211"},{'2',"1121122"},
{'3',"2111121"},{'3',"2122221"},{'3',"1222212"},
{'4',"2122211"},{'4',"2211121"},{'4',"1211122"},
{'5',"2112221"},{'5',"2111221"},{'5',"1221112"},
{'6',"2121111"},{'6',"2222121"},{'6',"1212222"},
{'7',"2111211"},{'7',"2212221"},{'7',"1222122"},
{'8',"2112111"},{'8',"2221221"},{'8',"1221222"},
{'9',"2221211"},{'9',"2212111"},{'9',"1112122"},
};
for(inti=0;i<30;i++)
if(strncmp(lookup_table_ean13[i].barcode,one_code,CELL_LEN)==0)
returnlookup_table_ean13[i].symbol;
return(-1);
}
////////////////////////////////////////////////////////////////
/*
确定数字的奇偶性,在这里是指条在单元模块中的比例是奇数还是偶数,比如2221211,因为条的比例是
3,所以是奇数
*/
staticcharCheck_OE(char*one_code)
{
intsum=0;
charsymbol;
for(inti=0;i{
sum+=one_code[i];
}
if(sum%2==0)
symbol='E';
else
symbol='O';
returnsymbol;
}
///////////////////////////////////////////////////////////////
/*
根据左边六个数字的奇偶性来确定最前面的那个字符
*/
staticintlook_up_ean13_first(char*one_code)
{
typedefstruct{
charsymbol;
charbarcode[20];
}LOOKUP_ENTRY;
static