基于Matlab制作一個不良圖片檢測系統(tǒng)
不良圖片檢測部分
看到博主碼猴小明用python PIL庫制作了一個不良圖片識別系統(tǒng),手癢,想用MATLAB也試試,畢竟矩陣運算也算是MATLAB的強項了,使用MATLAB寫可比用python寫簡潔太多了,總體流程如下:
- 檢查各個像素是否為膚色
- 將相鄰的膚色像素歸為一個皮膚區(qū)域,得到若干個皮膚區(qū)域,并剔除像素數(shù)量極少的皮膚區(qū)域
- 通過皮膚區(qū)域特點判定是否為不良圖片
part.0 圖片導(dǎo)入
imread讀取圖片后需要double一下,因為uint8格式的圖片數(shù)據(jù)會自動取整,沒法保留小數(shù)。
%?讀取圖片 if?nargin<1 ????path='test.jpg'; end picMat=imread(path); picMat=double(picMat);
本文使用的圖片如下:

part.1 檢查是否為膚色
這里懶得再去找了,直接使用大佬文中的判定條件,滿足以下條件的將其判定為膚色:
- RGB顏色模式第一種:r > 95 and g > 40 and g < 100 and b > 20 and max([r, g, b]) - min([r, g, b]) > 15 and abs(r - g) > 15 and r > g and r > b
- RGB顏色模式第二種:nr = r / (r + g + b), ng = g / (r + g + b), nb = b / (r +g + b) ,nr / ng > 1.185 and r * b / (r + g + b) ** 2 > 0.107 and r * g / (r + g + b) ** 2 > 0.112
- HSV顏色模式:h > 0 and h < 35 and s > 0.23 and s < 0.68
- YCbCr顏色模式:97.5 <= cb <= 142.5 and 134 <= cr <= 176
網(wǎng)上各種膚色相關(guān)公式能找到很多,但是光照亮度不同,燈光顏色不同,膚色不同,各種影響因素太多,不可能100%準(zhǔn)確:
%?可調(diào)節(jié)skinMethod為1/2/3/4 if?nargin<2 ????skinMethod=3; end skinBool=[]; switch?skinMethod ????case?1 ????????%?RGB顏色空間檢測方法1 ????????r=picMat(:,:,1); ????????g=picMat(:,:,2); ????????b=picMat(:,:,3); ????????skinBool=(r>95)&(g>40)&(g<100)&(b>20)&(max(picMat,[],3)-min(picMat,[],3)>15)&(abs(r-g)>15)&(r>g)&(r>b); ????case?2 ????????%?RGB顏色空間檢測方法2 ????????nrgb=sum(picMat,3); ????????r=picMat(:,:,1);nr=r./nrgb; ????????g=picMat(:,:,2);ng=g./nrgb; ????????b=picMat(:,:,3); ????????skinBool=(nr./ng>1.185)&(r.*b./(nrgb.^2)>0.107)&(r.*g./(nrgb.^2)>0.112); ????case?3 ????????%?HSV顏色空間檢測方法 ????????hsvMat=rgb2hsv(double(picMat)./255); ????????h=hsvMat(:,:,1); ????????s=hsvMat(:,:,2); ????????skinBool=(h>0)&(h<35/180)&(s>0.23)&(s<0.68); ????case?4 ????????%?YCbCr顏色空間檢測方法 ????????ycbcrMat=rgb2ycbcr(uint8(picMat)); ????????cb=ycbcrMat(:,:,2); ????????cr=ycbcrMat(:,:,3); ????????skinBool=(cb>=97.5)&(cb<=142.5)&(cr>=134)&(cr<=176); end figure(); imshow(uint8(skinBool.*255));
可以看出僅對于本圖片,HSV及YCbCr顏色空間檢測方法相對較好:

part.2 皮膚區(qū)域標(biāo)記
%?刪除面積過小的區(qū)域 skinBool=bwareaopen(skinBool,50); %?獲取每一個連通區(qū)域(皮膚區(qū)域) skinLabel=bwlabel(skinBool); skinLabel=sort(skinLabel(:))'; skinLabel(skinLabel==0)=[];
需要注意的是,此時skinLabel標(biāo)簽形式為:
1 1 1 1 2 2 2 3 3 3 3 3 3 4 4 4... ...
假如,1有4個說明被標(biāo)記為1的區(qū)域面積為4,對該序列進行逐項做差能找出每個數(shù)值標(biāo)簽第一次出現(xiàn)的位置:
0 0 0 1 0 0 1 0 0 0 0 0 1 0 0... ...
例如2第一次出現(xiàn)在4+1=5的位置,3第一次出現(xiàn)在7+1=8的位置,那么2便一共出現(xiàn)過8-5=3次,那么找到每個數(shù)字首次出現(xiàn)位置并再次做差即可獲取每種標(biāo)簽出現(xiàn)次數(shù)(面積),此方法舍去了for循環(huán),使用向量化編程有了更快的速度:
Lpos=find([diff(skinLabel),1]); Larea=diff([0,Lpos]);
Larea即為每個區(qū)域面積大小。
part.3 通過皮膚區(qū)域特點判定是否為不良圖片
我們定義非色情圖片的判定規(guī)則如下(滿足任意一個判斷為真):
- 皮膚區(qū)域的個數(shù)小于3個
- 皮膚區(qū)域的像素與圖像所有像素的比值小于15%
- 最大皮膚區(qū)域小于總皮膚面積的45%
- 皮膚區(qū)域數(shù)量超過60個
%?皮膚區(qū)域的個數(shù)小于3個 flag1=length(Larea)<3; %?皮膚區(qū)域的像素與圖像所有像素的比值小于15% flag2=sum(Larea)/numel(picMat(:,:,1))<0.15; %?最大皮膚區(qū)域小于總皮膚面積的45% flag3=max(Larea)/sum(Larea)<0.45; %?皮膚區(qū)域數(shù)量超過60個 flag4=length(Larea)>60; %?滿足任意一項輸出否 isBlue=~any([flag1,flag2,flag3,flag4]);
本文實例圖片計算結(jié)果為否,即非不良圖片!
完整代碼
總共只有短短七十行?。?/p>
function?isBlue=blueDetect(path,skinMethod) %?調(diào)用方式: %?blueDetect(test.jpg) %?返回值isBlue為邏輯值true/false %?讀取圖片 if?nargin<1 ????path='test.jpg'; end picMat=imread(path); picMat=double(picMat); %%?======================================================================== %?使用其他皮膚檢測方法 %?可調(diào)節(jié)skinMethod為1/2/3/4 if?nargin<2 ????skinMethod=3; end skinBool=[]; switch?skinMethod ????case?1 ????????%?RGB顏色空間檢測方法1 ????????r=picMat(:,:,1); ????????g=picMat(:,:,2); ????????b=picMat(:,:,3); ????????skinBool=(r>95)&(g>40)&(g<100)&(b>20)&(max(picMat,[],3)-min(picMat,[],3)>15)&(abs(r-g)>15)&(r>g)&(r>b); ????case?2 ????????%?RGB顏色空間檢測方法2 ????????nrgb=sum(picMat,3); ????????r=picMat(:,:,1);nr=r./nrgb; ????????g=picMat(:,:,2);ng=g./nrgb; ????????b=picMat(:,:,3); ????????skinBool=(nr./ng>1.185)&(r.*b./(nrgb.^2)>0.107)&(r.*g./(nrgb.^2)>0.112); ????case?3 ????????%?HSV顏色空間檢測方法 ????????hsvMat=rgb2hsv(double(picMat)./255); ????????h=hsvMat(:,:,1); ????????s=hsvMat(:,:,2); ????????skinBool=(h>0)&(h<35/180)&(s>0.23)&(s<0.68); ????case?4 ????????%?YCbCr顏色空間檢測方法 ????????ycbcrMat=rgb2ycbcr(uint8(picMat)); ????????cb=ycbcrMat(:,:,2); ????????cr=ycbcrMat(:,:,3); ????????skinBool=(cb>=97.5)&(cb<=142.5)&(cr>=134)&(cr<=176); end figure(); imshow(uint8(skinBool.*255)); %%?======================================================================== %?刪除面積過小的區(qū)域 skinBool=bwareaopen(skinBool,50); %?獲取每一個連通區(qū)域(皮膚區(qū)域) skinLabel=bwlabel(skinBool); skinLabel=sort(skinLabel(:))'; skinLabel(skinLabel==0)=[]; %?此時skinLabel標(biāo)簽形式為: %?1?1?1?1?2?2?2?3?3?3?3?3?3?4?4?4...?... %?假如,1有4個說明被標(biāo)記為1的區(qū)域面積為4 %?對該序列進行逐項做差能找出每個數(shù)值標(biāo)簽第一次出現(xiàn)的位置: %?0?0?0?1?0?0?1?0?0?0?0?0?1?0?0...?... %?進而可以獲取每種標(biāo)簽所含點數(shù)(面積) %?此方法舍去了for循環(huán)使用向量化編程有了更快的速度: Lpos=find([diff(skinLabel),1]); Larea=diff([0,Lpos]); %?皮膚區(qū)域的個數(shù)小于3個 flag1=length(Larea)<3; %?皮膚區(qū)域的像素與圖像所有像素的比值小于15% flag2=sum(Larea)/numel(picMat(:,:,1))<0.15; %?最大皮膚區(qū)域小于總皮膚面積的45% flag3=max(Larea)/sum(Larea)<0.45; %?皮膚區(qū)域數(shù)量超過60個 flag4=length(Larea)>60; %?滿足任意一項輸出否 isBlue=~any([flag1,flag2,flag3,flag4]); end
批量處理部分
那么我們能不能寫一段代碼,調(diào)用咱前面寫的函數(shù),檢測文件夾A內(nèi)的全部圖片,并將不良圖片保存到B文件夾方便我們?nèi)舆M回收箱,將正常圖片保存在C文件夾方便觀看呢?非常簡單:
oriPath='.\A\';%?文件夾名稱 BPath='.\B\';?%?放置不良圖片的路徑 nBPath='.\C\';%?放置正常圖片的路徑 %?若路徑下不存在文件夾則創(chuàng)建文件夾 if?~exist(BPath,'dir') ????mkdir(BPath) end if?~exist(nBPath,'dir') ????mkdir(nBPath) end files=dir(fullfile(oriPath,'*.jpg'));? picNum=size(files,1); %遍歷路徑下每一幅圖像 for?i=1:picNum ???fileName=strcat(oriPath,files(i).name);? ???isBlue=blueDetect(fileName,3); ???if?isBlue ???????copyfile(fileName,strcat(BPath,files(i).name)); ???else ???????copyfile(fileName,strcat(nBPath,files(i).name)); ???end end
那么我們來看看不良圖片文件夾的分類效果?:

哈哈哈哈事實證明了解檢測原理后構(gòu)造一張符合條件的圖實在是太容易,這種干擾情況過多的判斷環(huán)境還是得整機器學(xué)習(xí)。
以上就是基于Matlab制作一個不良圖片檢測系統(tǒng)的詳細內(nèi)容,更多關(guān)于Matlab不良圖片檢測系統(tǒng)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于C/C++中static關(guān)鍵字的作用總結(jié)
以下是對C/C++中static關(guān)鍵字的作用進行了總結(jié)介紹,需要的朋友可以過來參考下2013-09-09

