您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Matlab處理圖像后如何實現人臉檢測,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
整體思路是尋找圖片中最大的連通域,將其認定為人臉。
第一個環節均值濾波,是為了減弱圖像的相關細節部分,以免毛刺影響后期連通域的形成,二值化方便形態學處理,減少運算量。考慮到人臉有黑人和白人黃種人,黑人膚色較深,在二值化之后面部區域不容易形成較大的連通域,如果采取形態學邊界提取的辦法,就可以避免這個問題,形態學邊界提取,只要結構元素夠大,也可以形成較大的封閉連通域。
然后就是縱向閉合操作,這一步我選擇采用豎向長條狀的結構元素進行閉合運算,因為人的臉部和頸部以及頭發和衣物等等都是縱向分布的,在進行形態學邊界提取的時候,容易將這些靠近的成分割裂開來,這對連通域的判斷極為不利,所以用豎向長條狀的結構元素在在縱向進行閉合運算,將臉部上下部的區域重新連接起來。
緊接著我又用橫向長條狀結構元素進行橫向腐蝕運算,這是因為,人的頭部以下的身體部分存在有大量連通域的時候,容易對最大連通域的判決產生干擾,又因為下半部分,多半呈縱向分布,通過橫向腐蝕可以將這些大塊的連通域割裂開來,但是要注意的是,割裂程度不應太大,否則會使得上一步閉合操作喪失意義。
接著,由于背景雜物等因素,同樣也會產生大量連通域,這會對最后結果的判決產生干擾,因此要予以剔除。
進行了層層篩選之后,在剩下的連通域里面挑一個最大的連通域,并且尺寸形狀滿足要求的用矩形框框起來作為人臉檢測結果。
h = ones(9)/81; I = uint8(conv2(I,h)); figure,imshow(I),title('線性均值濾波')
采用9x9模板進行線性均值濾波,因為后面調用gpuArray()函數轉換對輸入數據有要求,所以在進行了二維卷積之后重新將數據格式轉換成8位無符號整形數據。
BW = imbinarize(I); figure,imshow(BW),title('二值化')
直接調用imbinarize對圖像進行二值化
B = ones(21);%結構元素 BW = -imerode(BW,B) + BW; figure,imshow(BW),title('形態學邊界提取') BW = bwmorph(BW,'thicken'); figure,imshow(BW),title('加粗邊界') BW = not(bwareaopen(not(BW), 300)); figure,imshow(BW),title('把空洞填了')
結構元素采用21x21大小的全1矩陣,先調用imrode()進行腐蝕,再用原圖減去腐蝕結果,得到邊界。為了讓邊界更加明顯,調用bmworph函數,傳入'thicken'參數,意在將邊界加粗加厚。最后為了把空洞就是連續的小黑色塊填滿,調用bwareaopen()函數,該函數是去除面積小于300的白塊,為了去除黑塊,先調用not(BW)給原來的二值圖像取反,去掉取反后面積小于300的白塊,再次取反,達到去掉面積小于300的黑塊的目的。
%進行形態學運算 B = strel('line',50,90); BW = imdilate(BW,B); BW = imerode(BW,B); figure,imshow(BW),title('再閉操作之后') B = strel('line',10,0); BW = imerode(BW,B); figure,imshow(BW),title('閉操作之后再腐蝕') BW = gpuArray(BW);
調用strel()函數生成特定的結構元素,第一步調用strel(‘line',50,90),意思是調用直線型結構元素,長度為50,角度90度,也就是豎直的長條形結構元素。接著利用B調用imdilate和imerode,先進行膨脹再進行腐蝕完成閉操作運算。下一步,繼續生成橫向長條形結構元素,進行腐蝕操作,注意這里的結構元素不宜面積太大,長度太長,否則會過度影響上一步的結果
最后為了循環過程中提升運算速度,將數據類型更改為gpuArray(),可以在GPU上進行計算,節省時間。
%最小化背景 %細分 div = 10; r = floor(n1/div);%分成10塊 行 c = floor(n2/div);%分成10塊 列 x1 = 1;x2 = r;%對應行初始化 s = r*c;%塊面積 %判斷人臉是否處于圖片四周,如果不是就全部弄黑 %figure for i=1:div y1 = 1;y2 = c;%對應列初始化 for j=1:div loc = find(BW(x1:x2,y1:y2)==0);%統計這一塊黑色像素的位置 num = length(loc); rate = num*100/s;%統計黑色像素占比 if (y2<=0.2*div*c||y2>=0.8*div*c)||(x1<=r||x2>=r*div) if rate <=100 BW(x1:x2,y1:y2) = 0; end %imshow(BW) else if rate <=25 BW(x1:x2,y1:y2) = 1; end %imshow(BW) end%下一列 y1 = y1 + c; y2 = y2 + c; end%下一行 x1 = x1 + r; x2 = x2 + r; end
對于周圍多余的雜物產生的連通域,我選擇先將整幅圖像劃分為很多小塊,對一部分在圖像邊緣的小塊全部置成黑色,對不在邊緣的通過計算其中黑色像素比例來判定是否應該全部給成白色。因為圖片中央可能還會存在一些細小空洞,這些空洞在每一小塊占比不是很大但有可能影響連通性,如果一個小塊里面大部分是白色就全部給成白色,方便后期判定最大連通域。
Div是均分比例,我這里設置成10,也就是將整個圖像劃分成100個小塊。r就是在行方向上一個小塊占多少像素,c就是在列方向上一個小塊有多少像素。用兩層循環來遍歷每個小塊,通過find(x1:x2,y1:y2)==0返回所有滿足要求的像素的索引,索引長度就是黑色像素的個數。
通過條件判斷是否在邊界。
figure subplot(1,2,1) imshow(BW) title('最終處理') L = bwlabel(BW,8);%利用belabel函數對8連通域區間進行標號 BB = regionprops(L,'BoundingBox');%得到矩形框,框柱每一個連通域 BB = cell2mat(struct2cell(BB)); [s1,s2] = size(BB); BB = reshape(BB,4,s1*s2/4)'; pickshape = BB(:,3)./BB(:,4);% shapeind = BB(0.3<pickshape&pickshape<3,:);%篩選掉尺寸比例不合格 [~,arealind] = max(shapeind(:,3).*shapeind(:,4)); subplot(1,2,2) imshow(rgb) hold on rectangle('Position',[shapeind(arealind,1),shapeind(arealind,2),shapeind(arealind,3),shapeind(arealind,3)],... 'EdgeColor','g','Linewidth',2) title('人臉檢測')
經過消除邊界多余連通域后得到的BW中剩下的連通域內存在著我們需要的那個對應人臉的連通域。一般情況下,對應人臉的那個連通域會是最大的連通域。
調用bwlabel(BW,8)函數給所有連通域標記,其中鄰域規則采用8鄰域,返回一個被標記過連通域的圖像,第k個被標記的連通域所有像素值為k。
調用regionprops(L,'BoundingBox')函數,傳入參數L和'BoundingBox',該函數用于獲取圖像的各種屬性,傳入'BoundingBox'返回的是一個結構體,每一個結構體內都包含了一個能框柱其對應連通域的最小方框。一個方框,用一個序列來描述[x,y,width,height],這個序列包含了方框左上角像素的坐標以及長和寬。
這三條語句,第一條用來將結構體轉換成矩陣向量,方便計算。第二行獲取這個矩陣的維度。由于BB剛轉換成向量的時候,是一個行向量,每4個元素1組對應一個方框。為了后續計算方便,使用reshape()函數,將BB重構成一個矩陣,這個矩陣有4列,每一列對應方框的一個參數,比如坐標,長寬等等。每一行對應一個方框。
第一行計算長寬比,得到的pickshape向量的每一行對應每個方框的長寬比。由于有的方框明顯過于扁平或者過于狹長,這種方框應該是要扔掉的。
所以第二行,通過邏輯表達式從BB內篩選出尺寸比例合格的方框,存在shapeind里面。
剩下的尺寸符合要求的方框里面要選出面積最大的那個,最后一行,得到面積最大的方框對應的索引。
把方框畫出來。
圖 15rgb圖像轉換成灰度圖像 圖 16線性均值濾波結果
可以看到,均值濾波使得圖像變模糊了細節減少
圖 17二值化結果 圖 18形態學邊界提取結果
以看到邊界被成功提取了出來,在人臉部形成了一個比較大的連通域
可以看到,進行邊界加粗和空洞添補之后,眼睛部分的黑塊被消除了,這使得臉部連通域更大了
注意觀察圖片左邊的相分離的白塊,在縱向閉操作之后連在了一起,同時臉部連通域進一步擴大,然后橫向腐蝕在盡量維持臉部連通域大小的情況下減小了圖片下方連通域。
可以看到效果還可以。還有其他的測試結果
圖 24測試樣例
圖 25測試樣例
圖 26測試樣例
圖 27測試樣例
圖 28測試樣例
圖 29測試樣例
圖 30測試樣例
這里注意到,黑人同樣也被檢測到了
---%%%完整代碼 rgb = imread('f.jpg'); I = rgb2gray(rgb); [n1,n2] = size(I); %灰度圖 figure,imshow(I),title('灰度圖') tic h = ones(9)/81; I = uint8(conv2(I,h)); figure,imshow(I),title('線性均值濾波') BW = imbinarize(I); figure,imshow(BW),title('二值化') B = ones(21);%結構元素 BW = -imerode(BW,B) + BW; figure,imshow(BW),title('形態學邊界提取') BW = bwmorph(BW,'thicken'); figure,imshow(BW),title('加粗邊界') BW = not(bwareaopen(not(BW), 300)); figure,imshow(BW),title('把空洞填了') %進行形態學運算 B = strel('line',50,90); BW = imdilate(BW,B); BW = imerode(BW,B); figure,imshow(BW),title('再閉操作之后') B = strel('line',10,0); BW = imerode(BW,B); figure,imshow(BW),title('閉操作之后再腐蝕') BW = gpuArray(BW); %最小化背景 %細分 div = 10; r = floor(n1/div);%分成10塊 行 c = floor(n2/div);%分成10塊 列 x1 = 1;x2 = r;%對應行初始化 s = r*c;%塊面積 %判斷人臉是否處于圖片四周,如果不是就全部弄黑 %figure for i=1:div y1 = 1;y2 = c;%對應列初始化 for j=1:div loc = find(BW(x1:x2,y1:y2)==0);%統計這一塊黑色像素的位置 num = length(loc); rate = num*100/s;%統計黑色像素占比 if (y2<=0.2*div*c||y2>=0.8*div*c)||(x1<=r||x2>=r*div) if rate <=100 BW(x1:x2,y1:y2) = 0; end %imshow(BW) else if rate <=25 BW(x1:x2,y1:y2) = 1; end %imshow(BW) end%下一列 y1 = y1 + c; y2 = y2 + c; end%下一行 x1 = x1 + r; x2 = x2 + r; end figure subplot(1,2,1) imshow(BW) title('最終處理') L = bwlabel(BW,8);%利用belabel函數對8連通域區間進行標號 BB = regionprops(L,'BoundingBox');%得到矩形框,框柱每一個連通域 BB = cell2mat(struct2cell(BB)); [s1,s2] = size(BB); BB = reshape(BB,4,s1*s2/4)'; pickshape = BB(:,3)./BB(:,4);% shapeind = BB(0.3<pickshape&pickshape<3,:);%篩選掉尺寸比例不合格 [~,arealind] = max(shapeind(:,3).*shapeind(:,4)); subplot(1,2,2) imshow(rgb) hold on rectangle('Position',[shapeind(arealind,1),shapeind(arealind,2),shapeind(arealind,3),shapeind(arealind,3)],... 'EdgeColor','g','Linewidth',2) title('人臉檢測') toc
關于“Matlab處理圖像后如何實現人臉檢測”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。