1、实验原理
Data Matrix二维码是二维码的一种,其由黑白相间的两种颜色组成的图形,每一个相同大小的黑色或白色方格称为一个数据单位。由于自身小的缘故可被广泛用于标示集成电路、药品等小件物品。
DM由寻边区和数据区组成,寻边区对二维码的边界进行识别,数据区则是二维码的数据编码部分。
上图中第二幅图又可分为L型实线和L型虚线。
此外DM采用了Reed -SoIomon 交织交插编码,编码时加入了纠错码, 使DM的纠错性能比较强。
直线型边缘在图像中较为常见,容易对二维码的定位造成干扰,在二维码区域加入其它特征,例如圆,可以辅助二维码定位。
哈夫变换可以查找图片中的圆和线,通过这些特征的查找可定位二维码,进而读取二维码的内容。
2、实验步骤
- 图片预处理
- 进行边缘像素查找
- 霍夫变换
- 查找图片中的圆
- 查找图片中的直线
- 获取位置
- 取圆心为二维码中心
- 获取二维码内容
- 通过直线的角度获取二维码偏转角(原点在左下角,向右为X轴,向上为Y轴,与X轴逆时针旋转角度为二维码角度)
- 将二维码转正
- 将二维码区域进行截取
- 将该子区域进行二值化
- 根据二维码方格数目(本实验二维码内容格子数目为10x10),获取二维码0、1内容矩阵。
- 示例图片
上代码:
clc
clear
img = imread('DM01.bmp');
%对图像进行边缘检测并进行膨胀操作
BW=edge(img,'canny',[0.04,0.1],3);
se = strel('line',10,150);
BW1 = imdilate(BW,se);
figure(1)
imshow(BW1);
%进行霍夫变换检测园
[HOUGH_SPACE,HOUGH_CIRCLE,PARA] = hough_circle(BW1,1,0.1,160,300,0.5);
hold off
%处理数据,根据得到的矩阵将圆心坐标半径求均值
m = length(PARA);
n = fix(m/2);
sum1 = sum(PARA(:,1:n),2);
sum2 = sum(PARA(:,n+1:m),2);
s1 = sum1/n;
s2 = sum2/(m-n);
y1=s1(1,1);
x1=s1(2,1);
r1=s1(3,1);
r2=s2(3,1);
%x1;y1;
[dm,dn]=size(BW1);
img1 = zeros(dm,dn);
for i = 1:dm
for j = 1:dn
if (i - y1).^2+(j - x1).^2 <= r1.^2
img1(i,j) = BW(i,j);
end
end
end
% BW2=edge(img1,'canny',[0.04,0.1],3);
% se = strel('line',10,150);
% BW3 = imdilate(BW2,se);
% figure(6)
% imshow(BW3)
[H,T,R] = hough(img1);%计算二值图像的标准霍夫变换,H为霍夫变换矩阵,I,R为计算霍夫变换的角度和半径值
figure(2)
imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit');%hough变换的图像
xlabel('\theta'), ylabel('\rho');
axis on,axis square,hold on;
P = houghpeaks(H,2);%提取2个极值点
% m = P(1,2);
q = P(2,2);
x2 = T(P(:,2));
y2 = R(P(:,1));
plot(x2,y2,'s','color','white');%标出极值点
lines=houghlines(img1,T,R,P);%提取线段
figure(3)
imshow(img), hold on;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');%画出线段
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');%起点
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');%终点
end
%根据上面得到的数据画出大圆小圆
rectangle('Position',[x1-r1,y1-r1,2*r1,2*r1], ...
'Curvature',[1,1],'EdgeColor','m','LineWidth',3)
rectangle('Position',[x1-r2,y1-r2,2*r2,2*r2], ...
'Curvature',[1,1],'EdgeColor','r','LineWidth',3)
%旋转图像
Theta = 90-q;
J = imrotate(img,-Theta,'bilinear','crop');
figure(4)
imshow(J);
%截图
img2 = f_Cut_for_circleMask(J,y1,x1,r2,1);
figure(5)
imshow(img2);
% %将图像二值化
% I = double(img2);
% thresh = graythresh(I); %自动确定二值化阈值
% I2 = im2bw(img2,thresh); %对图像二值化
% figure(6)
% imshow(I2);
x = (lines(1).point1(:,1))/2+(lines(2).point1(:,1))/2;%左上角x
y = lines(1).point1(:,2)/2+lines(2).point1(:,2)/2;%左上角y
a = (lines(2).point2(:,1)-x)/10;%边长
b1 = (lines(2).point2(:,2)-y)/11;%每行差的高度
xx = x+a*0.5;%第一个格子的坐标
b = (lines(1).point2(:,2)-y)/12;
a1 = (lines(1).point2(:,1)-x)/11;%每列差的宽度
yy = y+b*0.2;%第一个格子的坐标
%
code = zeros(11,11);
%
X = zeros(dm,dn);
for i=1:dm
for j=1:dn
if img(i,j)>60
X(i,j) = 1;
end
end
end
%
figure;
imshow(X);
hold on;
% % plot(round(xx),round(yy), 'r+');
% % plot(round(xx+2*a+2*a1),round(yy+2*b+2*b1), 'r+');
% % plot(round(xx+3*a+2*a1),round(yy+2*b+3*b1), 'r+');
% % plot(round(xx+4*a+2*a1),round(yy+2*b+4*b1), 'r+');
% % plot(round(xx+5*a+2*a1),round(yy+2*b+5*b1), 'r+');
%
n = 0;
for i = 1:11
for j = 1:11
sum(i,j) = 0;
for k = -1:1
for l = -1:1
m1 = xx+i*a+j*a1+k;
n1 = yy+j*b+i*b1+l;
aa = X(round(n1),round(m1));
sum(i,j) = sum(i,j)+aa;
end
end
if sum(i,j)>=5
code(i,j) = 1;
else
code(i,j) = 0;
end
if code(i,j) == 1
plot(round(xx+i*a+j*a1),round(yy+j*b+i*b1), 'b+'); %白格子
else
plot(round(xx+i*a+j*a1),round(yy+j*b+i*b1), 'r+'); %黑格子
end
end
end
%code = code';
figure;imshow(code);
效果展示