基于Matlab制作一個(gè)不良圖片檢測(cè)系統(tǒng)
不良圖片檢測(cè)部分
看到博主碼猴小明用python PIL
庫(kù)制作了一個(gè)不良圖片識(shí)別系統(tǒng),手癢,想用MATLAB也試試,畢竟矩陣運(yùn)算也算是MATLAB的強(qiáng)項(xiàng)了,使用MATLAB寫可比用python寫簡(jiǎn)潔太多了,總體流程如下:
- 檢查各個(gè)像素是否為膚色
- 將相鄰的膚色像素歸為一個(gè)皮膚區(qū)域,得到若干個(gè)皮膚區(qū)域,并剔除像素?cái)?shù)量極少的皮膚區(qū)域
- 通過皮膚區(qū)域特點(diǎn)判定是否為不良圖片
part.0 圖片導(dǎo)入
imread
讀取圖片后需要double
一下,因?yàn)?code>uint8格式的圖片數(shù)據(jù)會(huì)自動(dòng)取整,沒法保留小數(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顏色空間檢測(cè)方法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顏色空間檢測(cè)方法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顏色空間檢測(cè)方法 ????????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顏色空間檢測(cè)方法 ????????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));
可以看出僅對(duì)于本圖片,HSV及YCbCr顏色空間檢測(cè)方法相對(duì)較好:
part.2 皮膚區(qū)域標(biāo)記
%?刪除面積過小的區(qū)域 skinBool=bwareaopen(skinBool,50); %?獲取每一個(gè)連通區(qū)域(皮膚區(qū)域) skinLabel=bwlabel(skinBool); skinLabel=sort(skinLabel(:))'; skinLabel(skinLabel==0)=[];
需要注意的是,此時(shí)skinLabel
標(biāo)簽形式為:
1 1 1 1 2 2 2 3 3 3 3 3 3 4 4 4... ...
假如,1有4個(gè)說明被標(biāo)記為1的區(qū)域面積為4,對(duì)該序列進(jìn)行逐項(xiàng)做差能找出每個(gè)數(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次,那么找到每個(gè)數(shù)字首次出現(xiàn)位置并再次做差即可獲取每種標(biāo)簽出現(xiàn)次數(shù)(面積),此方法舍去了for循環(huán),使用向量化編程有了更快的速度:
Lpos=find([diff(skinLabel),1]); Larea=diff([0,Lpos]);
Larea
即為每個(gè)區(qū)域面積大小。
part.3 通過皮膚區(qū)域特點(diǎn)判定是否為不良圖片
我們定義非色情圖片的判定規(guī)則如下(滿足任意一個(gè)判斷為真):
- 皮膚區(qū)域的個(gè)數(shù)小于3個(gè)
- 皮膚區(qū)域的像素與圖像所有像素的比值小于15%
- 最大皮膚區(qū)域小于總皮膚面積的45%
- 皮膚區(qū)域數(shù)量超過60個(gè)
%?皮膚區(qū)域的個(gè)數(shù)小于3個(gè) 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個(gè) flag4=length(Larea)>60; %?滿足任意一項(xiàng)輸出否 isBlue=~any([flag1,flag2,flag3,flag4]);
本文實(shí)例圖片計(jì)算結(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); %%?======================================================================== %?使用其他皮膚檢測(cè)方法 %?可調(diào)節(jié)skinMethod為1/2/3/4 if?nargin<2 ????skinMethod=3; end skinBool=[]; switch?skinMethod ????case?1 ????????%?RGB顏色空間檢測(cè)方法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顏色空間檢測(cè)方法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顏色空間檢測(cè)方法 ????????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顏色空間檢測(cè)方法 ????????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); %?獲取每一個(gè)連通區(qū)域(皮膚區(qū)域) skinLabel=bwlabel(skinBool); skinLabel=sort(skinLabel(:))'; skinLabel(skinLabel==0)=[]; %?此時(shí)skinLabel標(biāo)簽形式為: %?1?1?1?1?2?2?2?3?3?3?3?3?3?4?4?4...?... %?假如,1有4個(gè)說明被標(biāo)記為1的區(qū)域面積為4 %?對(duì)該序列進(jìn)行逐項(xiàng)做差能找出每個(gè)數(shù)值標(biāo)簽第一次出現(xiàn)的位置: %?0?0?0?1?0?0?1?0?0?0?0?0?1?0?0...?... %?進(jìn)而可以獲取每種標(biāo)簽所含點(diǎn)數(shù)(面積) %?此方法舍去了for循環(huán)使用向量化編程有了更快的速度: Lpos=find([diff(skinLabel),1]); Larea=diff([0,Lpos]); %?皮膚區(qū)域的個(gè)數(shù)小于3個(gè) 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個(gè) flag4=length(Larea)>60; %?滿足任意一項(xiàng)輸出否 isBlue=~any([flag1,flag2,flag3,flag4]); end
批量處理部分
那么我們能不能寫一段代碼,調(diào)用咱前面寫的函數(shù),檢測(cè)文件夾A
內(nèi)的全部圖片,并將不良圖片保存到B
文件夾方便我們?nèi)舆M(jìn)回收箱,將正常圖片保存在C
文件夾方便觀看呢?非常簡(jiǎn)單:
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
那么我們來看看不良圖片文件夾的分類效果?:
哈哈哈哈事實(shí)證明了解檢測(cè)原理后構(gòu)造一張符合條件的圖實(shí)在是太容易,這種干擾情況過多的判斷環(huán)境還是得整機(jī)器學(xué)習(xí)。
以上就是基于Matlab制作一個(gè)不良圖片檢測(cè)系統(tǒng)的詳細(xì)內(nèi)容,更多關(guān)于Matlab不良圖片檢測(cè)系統(tǒng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++小知識(shí):C/C++中不要按值傳遞數(shù)組
今天小編就為大家分享一篇關(guān)于C++小知識(shí):C/C++中不要按值傳遞數(shù)組,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式)
這篇文章主要介紹了C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-06-06C++實(shí)現(xiàn)LeetCode(65.驗(yàn)證數(shù)字)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(65.驗(yàn)證數(shù)字),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07利用C++的基本算法實(shí)現(xiàn)十個(gè)數(shù)排序
以下是對(duì)利用C++的基本算法實(shí)現(xiàn)十個(gè)數(shù)排序的代碼進(jìn)行了介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-10-10C語言光標(biāo)信息CONSOLE_CURSOR_INFO類型詳解
本文詳細(xì)講解了C語言光標(biāo)信息CONSOLE_CURSOR_INFO類型,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12C/C++ 中const關(guān)鍵字的用法小結(jié)
C++中的const關(guān)鍵字的用法非常靈活,而使用const將大大改善程序的健壯性。這篇文章主要介紹了C/C++ 中const關(guān)鍵字的用法,需要的朋友可以參考下2020-02-02