http://www.cnblogs.com/blue-lg/archive/2011/12/07/2279879.html
環境:Windows XP+MATLAB 2010b
基本思路:
1)將基於彩色空間的RGB模型轉換為YCbCr模型(考慮到人臉的生理特征,只采取了Cr分量作為輔助)
2)閾值分割,根據多次實驗發現,正常黃種人的Cr分量大約在140~·160之間
3)濾波,本實驗采用性能較好的中值濾波
4)特征區域提取,利用matlab的bwlabel函數
5)對標記的特征區域利用高寬度之比和面積兩個指數來進一步簡化特征區域
具體實驗代碼及原理講解
1)rgb->ycbcr
%公式 Y = 0.2990*R + 0.5780*G + 0.1140*B + 0
%公式 Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
%公式 Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
(參見http://en.wikipedia.org/wiki/YCbCr)
本實驗直接采用mtalab自帶函數rgb2ycbcr()轉換就OK了。
I1=imread('blue_lg.jpg'); si=size(I1); m=si(1);n=si(2); img1=rgb2ycbcr(I1); cr1=img1(:,:,3);%大小為mxn的二維矩陣
2)閾值分割
cr3=cr1; for i=1:m for j=1:n if(cr3(i,j)>140&&cr3(i,j)<160)%140~160為本人實驗多次得到的合理值 cr3(i,j)=255; else cr3(i,j)=0; end end end
3)中值濾波器(本實驗采用的是5x5的子模板)
c_r=cr3; for i=3:m-2 for j=3:n-2; temp=cr3(i-2:i+2,j-2:j+2);%提取5x5區域 temp1=sort(temp);%排序 c_r(i,j)=temp1(13);%中值 end end
4)利用bwlabel進行特征區域提取
關於matlab函數bwlabel:[L, num] = bwlabel(BW, n);
根據領域的鏈接性質,將整個區域分為num個子區域,L為一矩陣,其中每個子區域在此矩陣中的值為子區域的序號。值得注意的是,序號為0的情況(我理解為背景,直接棄之不用)。n指的是領域性質,4鄰域or8鄰域。
舉個例子,
BW = logical ([1 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 1 1 1 0 1 1 0 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 1 1 0 1 1 1 0 0 0 0 0]);
3種背景顏色分別表示3個子區域,剩下的即為區域0,理解為背景吧。
對應生成的L矩陣即為
% L = bwlabel(BW,4);
L =
1 1 1 0 0 0 0 0
1 1 1 0 2 2 0 0
1 1 1 0 2 2 0 0
1 1 1 0 0 0 3 0
1 1 1 0 0 0 3 0
1 1 1 0 0 0 3 0
1 1 1 0 0 3 3 0
1 1 1 0 0 0 0 0
(參考mtlab自帶文檔)
我的做法是在當前路徑下重新定義了一個子函數findlimit()。
function [l,kk]=findlimit(I) %l為已分類有序矩陣 %kk為特征區域的序號 tt=size(size(I)); if tt(2)==3 %若I為3維矩陣,則需要轉換為灰度圖像 J=rgb2gray(I); else %I為3維矩陣 J=I; end %[m,n]=size(J); [l,num]=bwlabel(J,8); area=zeros(1,num+1);%面積 zhonghengbi=zeros(1,num+1);%比例 %re=zeros(num+1,4); re1=zeros(num+1,2); for k=0:num [r,c]= find(l==k); % re(k+1,1)=min(r); %垂直方向最小值(上) % re(k+1,2)=max(r); %垂直方向最大值(下) % re(k+1,3)=min(c); %水平方向最小值(左) % re(k+1,4)=max(c); %水平方向最大值(右) re1(k+1,1)=max(r)-min(r);%高度 re1(k+1,2)=max(c)-min(c);%寬度 zhonghengbi(k+1)=re1(k+1,1)/re1(k+1,2);%高寬比 if(re1(k+1,2)==0) zhonghengbi(k+1)=0;end%防止出現單條垂直線的情況 area(k+1)=re1(k+1,1)*re1(k+1,2); end j=1; for i=1:num+1 if zhonghengbi(i)>0.2&&zhonghengbi(i)<3.0&&area(i)>1000 %高寬比設置為0.2~3.0之間,面積認為大於1000,注意面積為隨機項,與圖片大小有很大的關系 kk(j)=i-1; j=j+1; end end
5)把特征區域整個提取出來
在此之前定義了一個判斷序號是否在提取出的特征區域內的isson()函數,如下:
function x=isson(y,I) x=0; z=size(I); for i=1:z(2) if(y==I(i)) x=1; break; end end
[l,kk]=findlimit(c_r); J=l; for i=1:m for j=1:n if(l(i,j)~=0&&isson(l(i,j),kk)==1) J(i,j)=255; else J(i,j)=0; end end end figure;imshow(J,[]);
然後就可以達到最後的人臉頭像了。
原始圖像:
處理後
2原始圖像
處理後:
到這裡,本文即將完結,但是可能大家都注意到,許多圖像之中,由於手臂的膚色與人臉一致,以及背景不可避免的顏色巧合,導致最終的效果不是特別理想。
這裡主要討論手與臉的區分問題(考慮使用類圓相似度來解決,可能在下一篇中解決,當然這是後話)。