灰度影象形狀的識別分類演算法實現matlab
摘 要: 針對已經給出的影象,在分類之前,因為存在噪聲和光照的不同,所以要先進行影象增強,並統一將影象轉為二值影象。對影象進行邊緣檢測,可以很容易算出各個影象面積與周長二次方的比值關係,對影象進行直線檢測, 可以獲得影象中直線的特徵,結合影象的以上兩種特種對形狀進行分類。
演算法設計和推導:
1. 影象預處理部分,通過 9X9 均值濾波器,先對影象進行去噪,然後二值化影象。
2. 各個形狀的面積和周長存在一定的特徵關係,可據此對影象進行分類。
(令各形狀的面積為S,周長為L,計算)
(1)圓形(半徑為r1):S/L2 =(π*r12) / (2*π*r1)2
(2)正方形(邊長為r2):S/L2 = r22 / (4*r2)2
(3) 矩形(不包含正方形) S/L2 < 1/16 = 0.0652
(4) 橢圓(不包含原) S/L2 < 1 / 4*π= 0.0796
據此方法,可對圓和正方形進行分類,將圓和正方形與另外兩種形狀區分開來,但無法對橢圓和矩形進行恰當分類。
3. 用霍夫變換對形狀進行直線檢測,獲得直線特徵(直線數量,直線長度),
若檢測到直線數量不等於四條,可直接判斷為圓或橢圓,計算直線長度,找出相等的直線對,若四條直線相等,可判斷為正方形,若有兩對相等的直線,可判斷為矩形。
結合以上兩種判斷方法,對形狀進行識別並分類。
實驗設計和結果
1.預處理部分,對影象進行增強並二值化,實現程式碼如下:
function K2 = quzao(I)
K1=filter2(fspecial('average',[9,9]),I)/255;
thresh = graythresh(I);
K2 = im2bw(K1,thresh);
end
實現效果:
原影象 處理過的影象
原影象 處理過的影象
原影象 處理過的影象
原影象 處理過的影象
2.為了計算S/L2,需要獲得影象中各形狀對應的面積和周長,對二值化後的影象進行邊緣提取,來獲得形狀的邊界(以圓為例)
兩張影象大小一樣,分別計算每張影象值為1 的畫素數量,計算比率,實現程式碼如下:
function r = Ratio(K,E)
[r1,c1] = size(K);
% [r2,c2] = size(E);
area = 0;
perimeter = 0;
for i = 1:r1
for j = 1:c1
if(K(i,j)==1)
area = area+1;
end
if(E(i,j)==1)
perimeter = perimeter+1;
end
end
end
r = area/(perimeter*perimeter);
end
每個形狀各選擇50張影象進行測試,檢視各個不同形狀所計算出的比率的分佈情況,結果如下:
圓 正方形
長方形 橢圓
觀察實驗結果發現,圓和正方形的S/L2比值並未像預期那樣為定值,但圓形的比值基本分佈在0.085和 0.09之間,而其他形狀算出的比值均未超過0.085,可據此將圓形與其他三個形狀區分開來。
3.對影象進行直線檢測
利用霍夫變換進行直線檢測 ,可通過分析直線特徵,根據獲得的直線數量,計算出的直線長度來進行比較,具體實現如下
直線檢測並進行正方形和長方形的判斷並寫入相應資料夾:
BW=edge(K,'canny'); %邊緣檢測
[H,T,R]=hough(BW); %霍夫變換進行直線檢測
P=houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
lines=houghlines(BW,T,R,P,'FillGap',30,'MinLength',60); %獲得檢測到的直線
[num1,num2] = size(lines); %獲得直線的數量num2
if(num2 == 4) %若檢測到為四條直線,逐一計算各條直線長度,存入l
for count=1:4
lines(count).long = sqrt((lines(count).point1(1)-lines(count).point2(1))^2 + (lines(count).point1(2)-lines(count).point2(2))^2);
l(count) = lines(count).long;
end
num = lineCompare(l); %比較直線長度,判斷是否為矩形或正方形形
end
if(num==4 && num2 == 4) %判斷為正方形
path = strcat('square\',int2str(index1));
imwrite(K,strcat(path,'.jpg'));
index1 = index1+1;
elseif(num==2 && num2 == 4) %判斷為矩形
path = strcat('rectangle\',int2str(index2));
imwrite(K,strcat(path,'.jpg'));
index2 = index2+1;
通過直線的長度比較來進行判斷,lineCompare函式程式碼如下
function num = lineCompare(l)
num = 0;
diff(12) = abs(l(1)-l(2)); %第一條直線與各直線進行比較,計算與其他直線的差值diff
diff(13) = abs(l(1)-l(3));
diff(14) = abs(l(1)-l(4));
if(diff(12)<5.5 || diff(13)<5.5 || diff(14)<5.5)
if(diff(12)<5.5 && diff(13)<5.5 && diff(14)<5.5) %若四條直線相等(即直線長度差值小於5.5),即判斷為正方形
num = 4;
elseif(diff(12) < 5.5) %四條直線不相等,但直線1,2相等,判斷直線3,4是否相等,若相等,即為矩形
diff(34) = abs(l(3) - l(4));
if(diff(34) < 5.5)
num = 2;
end
elseif(diff(13) < 5.5)
diff(24) = abs(l(2) - l(4));
if(diff(24) < 5.5)
num = 2;
end
elseif(diff(14) < 5.5)
diff(23) = abs(l(2)-l(3));
if(diff(23) < 5.5)
num = 2;
end
end
end
end
最終確定的程式執行步驟為,先進行直線檢測將影象分為正方形和長方形,圓形和橢圓兩類,正方形和長方形通過直線長度比較進一步分類,圓形和橢圓通過計算S/L2進一步劃分。將每一張影象進行形狀分類後寫入對應的資料夾
4. 將最終程式用於形狀的劃分,統計分到每個問價下的各形狀數量效能統計如下
資料夾\形狀 |
圓 |
正方形 |
長方形 |
橢圓 |
circle |
276 |
2 |
3 |
60 |
square |
0 |
188 |
0 |
2 |
rectangle |
0 |
14 |
156 |
2 |
ellipse |
3 |
75 |
120 |
215 |
合計 |
279 |
279 |
279 |
279 |
正確率 |
98.9% |
67.4% |
56.0% |
77.1% |
完整實現程式碼:
影象預處理:
function K2 = quzao(I)
K1=filter2(fspecial('average',9),I)/255;
thresh = graythresh(I);
K2 = im2bw(K1,thresh);
end
周長面積比率:
function r = Ratio(K,E)
[r1,c1] = size(K);
% [r2,c2] = size(E);
area = 0;
perimeter = 0;
for i = 1:r1
for j = 1:c1
if(K(i,j)==1)
area = area+1;
end
if(E(i,j)==1)
perimeter = perimeter+1;
end
end
end
r = area/(perimeter*perimeter);
end
開始分類:
function split(file_path)
%file_path = 'test1\';% 影象資料夾路徑
img_path_list = dir(strcat(file_path,'*.jpg'));%獲取該資料夾中所有jpg格式的影象
img_num = length(img_path_list);%獲取影象總數量
index1 = 1;
index2 = 1;
index3 = 1;
index4 = 1;
num = 0;
if img_num > 0 %有滿足條件的影象
for j = 1:img_num %逐一讀取影象
image_name = img_path_list(j).name;% 影象名
image = imread(strcat(file_path,image_name));
fprintf('%d %d %s\n',i,j,strcat(file_path,image_name));% 顯示正在處理的影象名
K = quzao(image); % 呼叫去噪函式進行去噪
BW=edge(K,'canny'); %邊緣檢測
[H,T,R]=hough(BW); %霍夫變換進行直線檢測
P=houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
lines=houghlines(BW,T,R,P,'FillGap',30,'MinLength',60); %獲得檢測到的直線
[num1,num2] = size(lines); %獲得直線的數量num2
if(num2 == 4) %若檢測到為四條直線,逐一計算各條直線長度,存入l
for count=1:4
lines(count).long = sqrt((lines(count).point1(1)-lines(count).point2(1))^2 + (lines(count).point1(2)-lines(count).point2(2))^2);
l(count) = lines(count).long;
end
num = lineCompare(l); %比較直線長度,判斷是否為矩形或正方形形
end
if(num==4 && num2 == 4) %判斷為正方形
path = strcat('square\',int2str(index1));
imwrite(K,strcat(path,'.jpg'));
index1 = index1+1;
elseif(num==2 && num2 == 4) %判斷為矩形
path = strcat('rectangle\',int2str(index2));
imwrite(K,strcat(path,'.jpg'));
index2 = index2+1;
else
E = edge(K);
r = Ratio(K,E);
if(r>0.086) %判斷為圓
path = strcat('circle\',int2str(index3));
imwrite(K,strcat(path,'.jpg'));
index3 = index3+1;
else %判斷為橢圓
path = strcat('ellipse\',int2str(index4));
imwrite(K,strcat(path,'.jpg'));
index4 = index4+1;
end
end
end
%影象處理過程 省略
else
fprintf('資料夾不存在!');% 顯示正在處理的影象名
end
end
function num = lineCompare(l)
num = 0;
diff(12) = abs(l(1)-l(2)); %第一條直線與各直線進行比較,計算與其他直線的差值diff
diff(13) = abs(l(1)-l(3));
diff(14) = abs(l(1)-l(4));
if(diff(12)<5.5 || diff(13)<5.5 || diff(14)<5.5)
if(diff(12)<5.5 && diff(13)<5.5 && diff(14)<5.5) %若四條直線相等(即直線長度差值小於5.5),即判斷為正方形
num = 4;
elseif(diff(12) < 5.5) %四條直線不相等,但直線1,2相等,判斷直線3,4是否相等,若相等,即為矩形
diff(34) = abs(l(3) - l(4));
if(diff(34) < 5.5)
num = 2;
end
elseif(diff(13) < 5.5)
diff(24) = abs(l(2) - l(4));
if(diff(24) < 5.5)
num = 2;
end
elseif(diff(14) < 5.5)
diff(23) = abs(l(2)-l(3));
if(diff(23) < 5.5)
num = 2;
end
end
end
end