[轉載] http://www.cnblogs.com/tiandsp/archive/2012/12/06/2804922.html
我幾乎完全就是照着WIKI百科上的算法實現的,不過是用Matlab而已。使用了兩步法進行標記,一步法我還沒怎麼看。兩步法中第二步是比較麻煩的,其中用到了不相交集合的一些理論,尤其是不相交集合森林,我這裏的find_set函數就是參考《算法導論》311頁的算法寫的。如果用c++寫,也許需要自己構造數據結構。
好吧,下面是我理解的算法過程:
1.首先要確定是標記8鄰域連通還是4鄰域連通,如果是8鄰域連通,就用的模板,如果是4鄰域連通,就用的模板。我這裏用了是8連通。
2.用模板變量圖像,類似卷積,不過不計算,只比較。比較當前像素和鄰域4個或2個像素,如果都不相等,那麼標記號加一,並且把這個標記號賦值給另一個標記空間中相同位置的像素,因爲不能破壞當前圖像的像素。如果有一個相等,那麼就把這4個或2個像素中非背景像素中的最小值賦給另一個標記空間相同位置的像素,並且把這4個或2個像素同有相同當前位置像素值的集合取並集(ps:這個真的好難解釋--!!)。遍歷完會得到標記圖像和有標記號那麼多個的標記集合。
3.遍歷標記圖像,按標記圖像的像素值索引標記集合,找到標記集合中代表當前集合最小的值賦值給原圖像當前位置的像素(ps:這裏最好看《算法導論》或這裏)。
還是看代碼吧,運行一下更好:
clear all;
close all;
clc;
img=imread('liantong.bmp');
imgn=img>128;
s=uint8(1-imgn);
%{
s=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0; %這個矩陣是維基百科中的矩陣
1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0;
0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0;
0 1 1 1 1 0 0 0 1 1 1 0 0 1 1 0;
1 1 1 0 0 1 1 0 0 0 1 1 1 0 0 0;
0 1 1 0 0 0 0 0 1 1 0 0 0 1 1 0;
0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
%}
imshow(mat2gray(s));
[m n]=size(s);
tmp=zeros(m,n);
label=1; %第一遍遍歷時標記的標籤數量
for i=2:m
for j=2:n-1
up_left=s(i-1,j-1); %原圖像當前像素周圍四個像素
up=s(i-1,j);
up_right=s(i-1,j+1);
left=s(i,j-1);
cur=s(i,j);
if cur==1
if cur~=up_left && cur~=up &&cur~=up_right &&cur~=left %當前和四周的都不一樣,加新標籤
tmp(i,j)=label;
link{label}=[];
label=label+1;
else
t=sort([tmp(i,j-1) tmp(i-1,j-1) tmp(i-1,j) tmp(i-1,j+1)]); %標籤圖像當前像素周圍四個像素並排序
for k=1:4 %尋找周圍四個像素非零的最小值賦值給標籤圖像
if t(k)~=0
tmp(i,j)=t(k);
for w=k:4
link{t(w)}=union(t(k:4),link{t(w)}); %設置不相交集合
end
break;
end
end
end
end
end
end
for i=1:m
for j=1:n
if s(i,j) ~=0
s(i,j)=find_set(link,tmp(i,j));
end
end
end
figure,imshow(mat2gray(s))
下面是運行的結果:
原圖
結果圖
效果還不錯吧。