一、获取代码的方式
我的资源已上传到完整代码: 基于条形码识别matlab条含条形码识别系统Matlab源码 096期】 (https://download.csdn.net/download/TIQCmatlab/62925370) 点击上面蓝色字体,直接付费下载,即可。
付费专栏图像处理(Matlab)
点击蓝色字体付费栏图像处理(Matlab),扫描上面的二维码,付费299.9元订阅海神光博客,私信博主凭支付凭证可免费获得上传本博客CSDN资源代码(订阅日起三天内有效); 点击CSDN资源下载链接:上传本博客CSDN资源代码
二、二维条码识别简介
二维条码采用数字图像处理技术识别, 是二维条码识别中常用的方法, 它具有光电识别方法方面具有无与伦比的优势。此外,图像识别方法对识别角度的要求不如光电识别方法严格, 一些二维条形码 (如QR Code码) 可以从任何角度识别。
在图像条形码识别过程中, 采集二维条形码图像首先采用图像采集设备, 然后利用图像处理技术去除和分割条形码图像, 最后,调用条码特征读取算法, 读取条码值并显示识别结果, 图3是图像条形码识别过程, 各模块的功能如下:
(1) 图像采集。通过数码相机、扫描仪或特殊图像传感器, 如CCD图像传感器或CMOS图像传感器等设备采集条形码图像。
(2) 图像预处理。图像预处理过程主要包括图像降噪、背景分离、图像校正等。由采集系统或其他原因引起的噪声, 采集的图像有些模糊或黑白孤立, 这对条码图像的进一步处理极为不利, 因此,根据条码图像噪声是否严重, 选择一个或多个滤波器进行滤波, 去除噪声。目前,中值滤波法应用较多。背景分离是将条码区与背景分离, 避免在没有有效信息的区域提取特征, 提高后续处理速度。标准差阈值跟踪法一般用于背景分离, 图像条码部分由黑白条块组成, 灰度变化大, 因此,标准差较大;背景灰度分布相对平坦, 标准差小。将条码图像分块, 如果每个小块的标准差大于某个阈值, 小块中的所有像素点都是有效的;否则是背景。由于收集到的图像总是倾斜和偏移产生几何畸变, 条难快速正确地识别条码, 因此,必须进行图像校正, 一般方法是:利用行差运算和Hough变换相结合, 快速准确地找到条码图像边界线, 计算倾斜角度, 条码图像通过双线插值校正。 图1 图像条形码识别过程 (3) 二值化处理。条码识别是基于二值图像, 图像二值化算法很多, 条码图像直方图具有良好的双峰特性, 大津阈值法[4]可以很好地分割条码图像。图像二值化后, 二值图像中的1像素代表黑条, 0像素代表白条。
(4) 边缘检测。条码识别的本质是边缘检测, 传统的条导数零交叉,传统的条码识别算法是检测条码边缘[2,6]。
(5) 条码读取。根据确定的条码边缘确定条码黑白模块宽度, 编制相应的译码程序,使用不同的条码编码规则, 确定条码字符值, 这个算法很成熟。
(6) 显示和处理结果。条码识别的结果通常由计算机显示, 实际应用中可根据结果进行处理。
在图像条形码识别过程中, 若能知道条码条的空宽值, 条码符号值由不同条码的算法决定。因此,在图像条码识别过程中, 图像处理部分的算法非常重要, 不同的图像处理方法将影响后续的条码识别结果。图像处理过程中的技术难点如下:
(1) 图像模糊问题。由于条码印刷质量差、光照弱、摄像设备质量等原因, 采集的条形码图像模糊, 黑白条块之间的边缘不清楚, 甚至黑白条的边缘也几乎融合在一起。针对这个问题, 目前国内一些处理方法采用各种经典滤波技术对条码图像进行除噪, 中值滤波技术应用广泛。当图像采集非常模糊时, 这种处理方法有一定的局限性, 有时甚至会导致条码无法识别。
(2) 边缘检测问题。在传统算法中,条码边缘通常根据二阶导数零交叉进行检测。在图像采集和图像滤波过程中,条形码图像边缘会有一定程度的模糊。由于条码图像去噪, 大多选用经典的中值滤波算法, 该算法对椒盐噪声有明显的去噪效果, 但对高斯噪声的去噪效果较差。在实际应用中, 图像采集产生的模糊基本上是高斯噪声, 中值滤波法无法有效去除噪声。采用二阶导数零交叉检测条码边缘会有1~2个像素的偏差, 这将影响条码条空宽度的确定, 从而影响识别。因此,边缘模糊是影响条形码识别的重要因素。
要解决边缘模糊问题, 噪声必须分析。我们知道平滑图像主要集中在中低频部分, 噪声信息或边缘信息主要集中在高频段。通常的滤波方法是不加区别地过滤高频信息, 边缘信息不可避免地会被过滤掉, 导致图像边缘模糊。文献[6]提出了一种基于边缘检测的小波去噪方法, 该方法利用小波变换良好的时频特性, 只需沿梯度方向检测小波变换系数模值的局部极大值, 即可得到图像的边缘点, 但小波系数的模值也可能与噪声点相对应。因此,在检测到小波系数的极大值后, 还需要去除与噪声点对应的小波系数。噪声的Lipschitz指数为负, 信号的Lipschitz指数为正, 随着规模的增加,信号系数逐渐增大, 噪声系数逐渐降低。根据这一特点可除去噪声造成的虚假边缘, 将非噪声点的模值连接到图像的边缘。该方法既能达到去噪目的,又能保持图像边缘, 这去噪与边缘检测相结合的新思路,在一定程度上解决了去噪造成图像边缘模糊的问题。
三、部分源代码
clc;clear;close all; ImageSrc=BinaryImage(imread('..\Pic\3.bmp')); ImageSrc=BinaryImage(imread('..\Pic\Demo12.bmp')); ImageSrc=BinaryImage(imread('..\Pic\Demo1211.bmp')); ImageSrc=BinaryImage(imread('..\Pic\李梦1.bmp'));
ImageSrc=BinaryImage(imread('..\Pic\未1命名.bmp'));
ImageSrc=BinaryImage(imread('..\Pic\新978.bmp'));
[ImageHeight,ImageWidth]=size(ImageSrc);
ImageArray=ones(size(ImageSrc));
ImageArray(find(ImageSrc>=160))=0;
subplot(211);imshow(flipud(ImageSrc));
subplot(212);imshow(flipud(ImageArray),[]);
arPixelH=sum(ImageArray,1);
arPixelV=sum(ImageArray,2);%左右方向投影
tempMax = max(arPixelV);
arMark=zeros(size(ImageArray,1));
arDifference=arPixelV(2:end)-arPixelV(1:end-1);
% 如果该行像素足够多且变化不大,标记为true
% 相当于与的关系abs(arDifference)<20 && (arPixelV[i]>(0.75*tempMax)
arMark(find(abs(arDifference)<20))=1;
arMark(find(arPixelV<=0.75*tempMax))=0;
% 确定包含条码的行
iLengthThrehold=40;
for i=1:ImageHeight-iLengthThrehold+1
iCount=length(find (arMark(i:i+iLengthThrehold-1)==1 ) );
if(iCount >= 37)
ImageTop = i+10; %确定顶部
break;
end
end
for i=ImageHeight:-1:iLengthThrehold
iCount=length(find (arMark(i:-1:i-iLengthThrehold+1)==1 ) );
if(iCount >= 37)
ImageBottom = i-10; %确定顶部
break;
end
end
arLeftEdge=zeros(ImageHeight,1);
arLeftEdge1=arLeftEdge;
arDelta=arLeftEdge;
% 寻找左边缘,为了保证鲁棒性,在已经确定的上下边界内全局搜索
for i=ImageTop:ImageBottom
for j=21:ImageWidth
if( (ImageArray(i,j-1)==0) && (ImageArray(i,j)==1) )
arLeftEdge(i) = j;
break;
end
end
end
[tempMax,iMax]=max(arLeftEdge);
% 倾斜度不能大于1/10
iCount = 0;
for i=ImageTop:ImageBottom
if( abs(tempMax-arLeftEdge(i)) < abs(i-iMax)/6+1 )
iCount=iCount+1;
end
end
if( (iCount/(ImageBottom-ImageTop))<0.6 )
display('failure1!');
return;
end
for n=0:28
for i=ImageTop:ImageBottom
for j=arLeftEdge(i)+1:ImageWidth
if( (ImageArray(i,j-1)==1) && (ImageArray(i,j)==0) )
arLeftEdge1(i) = j; break;
end
end
arDelta(i) = arLeftEdge1(i) - arLeftEdge(i);
end
tempArray=arDelta;
%排序
for i=ImageTop:ImageBottom-1
for j=ImageBottom:-1:i+1
if(tempArray(j)< tempArray(j-1))
tempSwap = tempArray(j);
tempArray(j)= tempArray(j-1);
tempArray(j-1) = tempSwap;
end
end
end
t0=floor(ImageTop+(ImageBottom-ImageTop)/2);
t1=t0+2;
t2=t0-2;
if(tempArray(t1)-tempArray(t2)>1) display('failure1!'); return;
else arWidth(2*n+1) = tempArray(t0);
end
%调整下一列边缘
for i=ImageTop:ImageBottom
if(abs(arDelta(i) - arWidth(2*n+1))>2)
arLeftEdge1(i) = arLeftEdge(i) + arWidth(2*n+1);
end
arLeftEdge(i)= arLeftEdge1(i);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 搜索空的右边缘
for i=ImageTop:ImageBottom
for j = arLeftEdge(i)+1:ImageWidth
if (ImageArray(i,j-1)==0) && (ImageArray(i,j)==1)
arLeftEdge1(i) = j;
break;
end
end
arDelta(i) = arLeftEdge1(i) - arLeftEdge(i);
end
tempArray = arDelta;
for i=ImageTop:ImageBottom-1
for j=ImageBottom:-1:i+1
if(tempArray(j)< tempArray(j-1))
tempSwap = tempArray(j);
tempArray(j)= tempArray(j-1);
tempArray(j-1) = tempSwap;
end
end
end
t0=floor(ImageTop+(ImageBottom-ImageTop)/2);
t1=t0+2;
t2=t0-2;
if(tempArray(t1)-tempArray(t2)>1) display('failure1!'); return;
else arWidth(2*n+2) = tempArray(t0);
end
%调整下一列边缘
for i=ImageTop:ImageBottom
if(abs(arDelta(i) - arWidth(2*n+2))>2)
arLeftEdge1(i) = arLeftEdge(i) + arWidth(2*n+2);
end
arLeftEdge(i)= arLeftEdge1(i);
end;
end
%% 搜索最后一个条的右边缘
for i=ImageTop:ImageBottom
for j = arLeftEdge(i)+1:ImageWidth
if (ImageArray(i,j-1)==1) && (ImageArray(i,j)==0)
arLeftEdge1(i) = j;
break;
end
end
arDelta(i) = arLeftEdge1(i) - arLeftEdge(i);
end
tempArray=arDelta;
%排序
for i=ImageTop:ImageBottom-1
for j=ImageBottom:-1:i+1
if(tempArray(j)< tempArray(j-1))
tempSwap = tempArray(j);
tempArray(j)= tempArray(j-1);
tempArray(j-1) = tempSwap;
end
end
end
t0=floor(ImageTop+(ImageBottom-ImageTop)/2);
t1=t0+2;
t2=t0-2;
n=29;
if(tempArray(t1)-tempArray(t2)>1) display('failure1!'); return;
else arWidth(2*n+1) = tempArray(t0);
end
% %调整下一列边缘 此段程序不需要
% for i=ImageTop:ImageBottom
% if(abs(arDelta(i) - arWidth(2*n+1))>2)
% arLeftEdge1(i) = arLeftEdge(i) + arWidth(2*n+1);
% end
% arLeftEdge(i)= arLeftEdge1(i);
% end
barnumber=[9,BarRecognize(arWidth)];
if( checkcode(barnumber)==1)
display(['二维码识别结果:',num2str(barnumber)]);
else display('识别错误!');
end
四、运行结果
五、matlab版本及参考文献
2014a
[1] 蔡利梅.MATLAB图像处理——理论、算法与实例分析[M].清华大学出版社,2020. [2]杨丹,赵海滨,龙哲.MATLAB图像处理实例详解[M].清华大学出版社,2013. [3]周品.MATLAB图像处理与图形用户界面设计[M].清华大学出版社,2013. [4]刘成龙.精通MATLAB图像处理[M].清华大学出版社,2015. [5]赵群礼,周秋平.基于图像的二维条形码识别技术研究[J].合肥师范学院学报. 2010,28(06)