1.軟體版本
matlab2013b
2.算法流程概述
通過形态學處理獲得二維碼部分的圖像區域及邊界;
采用凸包算法來計算邊界上的點集;
然後根據點集來尋找二維碼的四個頂點,
然後透視變換矯正,二維碼分割得到每個格子中的點。
進行二維碼圖像歸一化。完成二維碼修正。
然後做實驗比較與其他采用邊緣檢測加hough變換進行矯正後圖像的識别率。
在二值化操作之前進行光照增強,采用同态濾波和直方圖均衡化結合的方式來做,然後采用ostu法進行二值化。
通過定位二維碼三個角點的位置,然後通過膨脹處理,并進行連通區域。将不是這三個探測圖元所在的連通區域删除,然後将剩下的連通區域腐蝕,進行邊緣檢測,将得到的邊緣上的點集用凸包法進行連接配接,
大緻确定二維碼的邊界,然後使用到四條外界直線距離最短的方式來确定四個頂點。
3.部分源碼
clc;
clear all;
close all;
warning off;
addpath 'func\'
%filename ='1.jpg';
%filename ='2.jpg';
%filename ='3.jpg';
filename ='4.jpg';
X = imread(filename);
%擷取圖像相關資訊
[R,C,K] = size(X);
if K == 3
f = rgb2gray(X);
else
f = X;
end
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%使用小波濾波+中值濾波的改進濾波方案
figure
subplot(141);
imshow(f);
title('原始圖像');
f = imadjust(f,[0.1 0.8],[]);
f = func_wavelet_filter(f);
subplot(142);
imshow(f);
title('小波濾波和光線增強後圖像');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%基于OSTU方法的二值提取
G = f;
f = func_ostu(f);
f =~f;
subplot(143);
imshow(f);
title('ostu二值化處理圖像');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%形态學膨脹
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SE = strel('disk',8);
I = imdilate(f,SE);
%删除小的區域
I = bwareaopen(I,20000);
%求取整幅圖的重心
subplot(144);
imshow(I);
title('形态學膨脹圖像');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%标記連通域
[L,num]=bwlabel(I,8);
figure
subplot(141);
imshow(L);
%剔除無關連通域,這裡改進了剔除措施,之前的方法很多測試圖檔沒法正确處理
[R,C,K] = size(I);
L2 = zeros(R,C);
for i=1:num
[r,c]=find(L==i); %計算坐标
if isempty(r) == 0 & isempty(c) == 0
a2(i) = min(r); %計算坐标
a1(i) = max(r); %計算坐标
b2(i) = min(c); %計算坐标
b1(i) = max(c); %計算坐标
%根據面積進行判斷是否是正确的區域
Lss = a1(i) - a2(i);
Wss = b1(i) - b2(i);
if (Lss>=0.9*Wss & Lss<=1.1*Wss) | (Wss>=0.9*Lss & Wss<=1.1*Lss)
for j = 1:length(r)
L2(r(j),c(j)) = L(r(j),c(j));
end
end
end
end
SE = strel('disk',8);
T=imerode(L2,SE);
T=imfill(T,'holes');
subplot(142);
imshow(T);
title('形态學腐蝕');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%提取邊緣
T2=edge(T,'prewitt');
subplot(143);
imshow(T2);
title('提取邊緣');
%待判斷凸包的點集,這個部分做了改進,原來的方法存在殘缺問題,會無法檢測邊緣的問題
[y,x] = find(T2==1);
img = ones(size(T2));
p = [];
for i=1:length(x)
img(y(i),x(i))=0;
p=[p;x(i),y(i)];
end
subplot(144);
imshow(img);
%下面計算凸包
[t,index] = max(p(:,2));
%找到y最大的點
tmp_p = p(index,:);
%設一個和y最大的點平行的點
tmp_heng =[tmp_p(1)+100,tmp_p(2)];
for i=1:length(p)
%求每個點和y最大的點的夾角,自己和自己夾角NAN
Ang(i) = func_angle(tmp_heng,p(i,:),tmp_p);
end
Ang = Ang';
p =[p,Ang];
%按第三列排序,第三列是夾角度數
p = sortrows(p,3);
%re相當于棧
re{1} = p(length(p),1:2);
re{2} = p(1,1:2);
re{3} = p(2,1:2);
top = 3;
for i=3:length(p)-1
while func_multi(p(i,1:2),re{top-1},re{top})>=eps
top=top-1;
if top<=1
break;
end
end
top=top+1;
re{top}=p(i,1:2);
end
%下面是把找到的凸包上的點連線
for i=2:top
imgs = drawline(img,re{i-1}(1),re{i-1}(2),re{i}(1),re{i}(2));
end
imgs = drawline(img,re{1}(1),re{1}(2),re{top}(1),re{top}(2));
figure
subplot(231);
imshow(imgs)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%計算四個頂點
jiaodian2 = func_cal_point(imgs);
%這裡使用相似度比對措施對初始頂點進行頂點修正
[jiaodian3,jiaodian4] = func_cal_point_adjust(jiaodian2,G);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%校正
Z=func_adjust(jiaodian4,G);
subplot(232);
imshow(uint8(G))
hold on
for i = 1:4
plot(jiaodian2(i,2),jiaodian2(i,1),'g.');
hold on;
text(jiaodian2(i,2),jiaodian2(i,1),num2str(i));
end
subplot(233);
imshow(uint8(G))
hold on
for i = 1:4
plot(jiaodian4(i,2),jiaodian4(i,1),'r.');
hold on;
plot(jiaodian3(i,2),jiaodian3(i,1),'g.');
hold on;
end
subplot(234);
imshow(uint8(G))
hold on
for i = 1:3
line([jiaodian4(i,2),jiaodian4(i+1,2)],[jiaodian4(i,1),jiaodian4(i+1,1)],'Color',[0 1 0]);
hold on;
end
line([jiaodian4(end,2),jiaodian4(1,2)],[jiaodian4(end,1),jiaodian4(1,1)],'Color',[0 1 0]);
subplot(235);
Z2 = histeq(uint8(Z));
imshow(Z2);
subplot(236);
thresh=graythresh(Z2);
f = im2bw(Z2,thresh);
imshow(f);
%%
%對最後的結果進行分割
[R,C] = size(Z2);
Z3 = edge(Z2,'canny');
%行掃描
tmp1 = 0;
tmp2 = 0;
for i = 2:R
tmp1 = f(i-1,:);
tmp2 = f(i,:);
diff1(i) = abs(mean(tmp1 - tmp2));
end
%搜尋最小值
[pks1,locs1]=findpeaks(-1*diff1,'minpeakdistance',3); % Find peaks
%列掃描
tmp1 = 0;
tmp2 = 0;
for i = 2:C
tmp1 = f(:,i-1);
tmp2 = f(:,i);
diff2(i) = abs(mean(tmp1 - tmp2));
end
%搜尋最小值
[pks2,locs2]=findpeaks(-1*diff2,'minpeakdistance',3); % Find peaks
locs1 = [locs1];
locs2 = [locs2];
%獲得歸一化二維碼
QRcode = zeros(length(locs1),length(locs2));
for i = 1:length(locs1)
for j = 1:length(locs2)
QRcode(i,j) = f(locs1(i),locs2(j));
end
end
%補償
QRcode = QRcode;
figure;
subplot(3,2,1);
imshow(Z2);
subplot(3,2,2);
imshow(Z3);
subplot(3,2,3);
plot(diff1);
hold on;
plot(locs1,diff1(locs1),'k^','markerfacecolor',[1 0 0]);
title('水準邊緣投影');
subplot(3,2,4);
plot(diff2);
hold on;
plot(locs2,diff2(locs2),'k^','markerfacecolor',[1 0 0]);
title('垂直邊緣投影');
subplot(3,2,5);
imshow(Z2,[]);
title('透視糾正後圖像');
subplot(3,2,6);
imshow(QRcode,[]);
title('歸一化二維碼');