一维条码是一种能用于信息编码和信息自动识别的标准符号,是由一组宽度不同的黑白符号按一定规则交替排列编码组成的图形符号可用于表示一定的信息。
它是对物品进行代号标识需要依赖数据库或通讯网络才能发挥最大的作用。常见的码制(条码符号类型)有EAN-13码,EAN-8码,UPC码,交叉25码。
EAN-13解码:
EAN-13码结构
解码流程:
一维条码解码matlab代码
function [code]=one_dimensional_codeself(img)
%% 图片的读取
f=imread(img);% read figure
g=rgb2gray(f); %turn to gray figure
figure(1);
imshow(g);title('原图像');
[M,N]=size(g);
%% 图片的处理
T=graythresh(g)*255; %get threshold
g= Thresholding(g,T); %二值化
%% 噪声过滤
g=medfilt2(g); %filter
figure(2);
imshow(g);title('滤波后的图像');
im_edge=edge(g,'canny'); %边缘检测
figure(3);
imshow(im_edge);title('边缘检测后的图像');
A=line_detection(im_edge);
g=~g; %黑白像素翻转
%% 图片旋转
g=imrotate(g,A*180/pi,'nearest'); %旋转图像
g=~g;
figure(4)
imshow(g);title('旋转后的图像1');
is=is_upsize(g); %判读是否是正向水平
if is==1
g=imrotate(g,180,'nearest');
end
figure(5)
imshow(g);title('旋转后的图像2');
bar_width=bar_width_F(g);%获取条空的宽度
decode=dedecode_f(bar_width);%条空换做0,1表示
%% 一维码破解
if check_1(decode)
code=decode_f(decode);
end
Thresholding.m
%% 图像二值化 T为阀值
function [g]= Thresholding(g,T)
[M,N]=size(g);
for i=1:1:M
for j=1:1:N
if g(i,j)
line_detection.m
%% 霍夫直线检测
function A=line_detection(im_edge)
[row,col]=size(im_edge); %图像大小
p_max=floor(sqrt((row)^2+(col)^2))+1; %原点到直线最远的距离,就是到图像右上角的距离
accumulation=zeros(p_max,180);
theta=[0:pi/180:pi];%角度
max_num=0;
A=0;
%遍历图像,统计映射的(P,theta),选取最大的统计量对应的角度
for n=1:row
for m=1:col
if(im_edge(n,m)==1)
for k=1:180
p=(m*cos(theta(k)))+(n*sin(theta(k)));
p_int=round(p/2+p_max/2);
accumulation(p_int,k)=accumulation(p_int,k)+1;
if accumulation(p_int,k)>max_num
max_num=accumulation(p_int,k);
A=theta(k);
end
end
end
end
end
is_upsize.m
%% 判读是否是正向水平- 通过将一维码区两边的像素点相加,像素和大的一边为底
function is=is_upsize(g)
row=0;
[m,n]=size(g);
kk=size(m);%kk记录每一行的像素和
for i=1:m
kk(i)=1;
for j=1:n-1
if g(i,j)~=g(i,j+1)
kk(i)=kk(i)+1;
end
end
end
left_sum=0;
for i=1:m
if(kk(i)==61) %61为标准条码区
for j=1:10
left_sum=left_sum+kk(i-j);%与标准条码区相邻10行的像素和
end
break;
end
end
right_sum=0;
for i=m:-1:1
if(kk(i)==61)
for j=1:10
right_sum=right_sum+kk(i+j);%同上
end
break;
end
end
if left_sum>right_sum %上面像素的大于下面像素和说明倒了
is=1;
else
is=0;
end
bar_width_F.m
%% 获得条空比-判断相邻像素的值,不同就是边界,再求得条宽,与单位条宽相比,得到条空比。
function [bar_width]=bar_width_F(g)
[M,N]=size(g);
bar_y=zeros(M,N);%记录边界的列值,bar_y(M,1)记录是不是标准条码区 2-61位为边界列
l=1;
k=2;
for i=1:M
for j=1:N-1
if g(i,j)~=g(i,j+1)
bar_y(l,k)=j;
k=k+1;
end
end
if k==62
bar_y(l,1)=1;
else
bar_y(l,1)=0;
end
l=l+1;
k=2;
end
%对于每一列求平均值得到,边界列的最终值
bar_width_num=zeros(60);
for i=2:61
sum=0;
row=0;
for j=1:l-1
if bar_y(j,1)==1
row=row+1;
sum=sum+bar_y(j,i);
end
end
bar_width_num(i-1)=sum/row;
end
%相邻的列相减得到宽度
bar_width=zeros(59);
for i=1:59
bar_width(i)=bar_width_num(i+1)-bar_width_num(i);
end
sum=0;
for i=1:59
sum=sum+bar_width(i);
end
%得到单位条宽
module_width=sum/95;
%得到条空比
for i=1:59%% 条空换做0,1表示
function [decode]=dedecode_f(bar_width)
index=1;
for i=1:59
if mod(i,2)==1
for j=1:1:bar_width(i)
decode(index)=1;
index=index+1;
end
else
for j=1:1:bar_width(i)
decode(index)=0;
index=index+1;
end
end
end
check_1.m
function is=check_1(decode)
if decode(1)&&~decode(2)&&decode(3)&&~decode(46)&&decode(47)&&~decode(48)&&decode(49)&&~decode(50)&&decode(95)&&~decode(94)&&decode(93)
is=1;
fprintf('起始符,中间分隔符,终止符正确\n')
else
fprintf('起始符,中间分隔符,终止符错误,译码失败\n');
end
%% 条空换做0,1表示
function [decode]=dedecode_f(bar_width)
index=1;
for i=1:59
if mod(i,2)==1
for j=1:1:bar_width(i)
decode(index)=1;
index=index+1;
end
else
for j=1:1:bar_width(i)
decode(index)=0;
index=index+1;
end
end
end
decode_f.m
%% 一维码解码
function code=decode_f(decode)
left_num=size(6);
i=4;
%二进制转化为10进制得到前六个数
for index=1:6
sum=0;
for j=1:7
sum=sum*2+decode(i);
i=i+1;
end
left_num(index)=sum;
end
%得到后六个数
right_num=size(6);
i=51;
for index=1:6
sum=0;
for j=1:7
sum=sum*2+decode(i);
i=i+1;
end
right_num(index)=sum;
end
A=[13,25,19,61,35,49,47,59,55,11];
B=[39,51,27,33,29,57,5,17,9,23];
C=[114,102,108,66,92,78,80,68,72,116];
first_num=[63,52,50,49,44,38,35,42,41,37];
ahead=0;%前置符
%根据前6个十进制的到前置符
dec_left_num=size(6);
index=1;
for i=1:6
isA=0;
for j=1:10
if A(j)==left_num(i)
dec_left_num(index)=j-1;
isA=1;
break;
end
end
if isA==0
for j=1:10
if B(j)==left_num(i)
dec_left_num(index)=j-1;
break;
end
end
end
ahead=ahead*2+isA;
index=index+1;
end
for i=1:10
if ahead==first_num(i)
ahead=i-1;
break;
end
end
dec_right_num=size(6);
index=1;
for i=1:6
for j=1:10
if C(j)==right_num(i)
dec_right_num(index)=j-1;
index=index+1;
break;
end
end
end
%检验位
a=ahead+dec_left_num(2)+dec_left_num(4)+dec_left_num(6)+dec_right_num(2)+dec_right_num(4);
b=dec_left_num(1)+dec_left_num(3)+dec_left_num(5)+dec_right_num(1)+dec_right_num(3)+dec_right_num(5);
c=a+3*b;
c=mod(c,10);
if c~=0
c=10-c;
end
if c==dec_right_num(6)
fprintf('校验位正确,译码成功\n');
else
fprintf('校验位错误,译码失败\n');
end
code=size(13);%译码结果
code(1)=ahead;
for i=1:6
code(i+1)=dec_left_num(i);
code(i+7)=dec_right_num(i);
end