CoreImage系列二:人臉檢測

這是CoreImage系列的第二章抱环,主要有三點

1.對靜態(tài)圖片進(jìn)行人臉檢測與打馬賽克
2.對攝像頭錄像進(jìn)行人臉檢測與打馬賽克
3.將處理后的視頻數(shù)據(jù)存入本地

技術(shù)難點其實并沒有多少壳快,主要是記錄自己在這個過程中踩過的坑和API熟悉。


人臉檢測

CoreImage其實在iOS5的時候就推出了人臉檢測功能镇草,但是并不強(qiáng)大眶痰;僅僅做到能識別出人臉、五官等等梯啤,很多第三方SDK中的人臉檢測用到更底層的OpenCV竖伯,當(dāng)然這也更復(fù)雜,涉及到很多算法等等因宇。但就我們?nèi)粘5臋z測來說七婴,CoreImage提供的就已經(jīng)足夠了。

CIDetector

這個類就是CoreImage中進(jìn)行檢測的類察滑,它可以進(jìn)行很多檢測打厘,人臉只是其中的一種。
它的用法其實很簡單贺辰,就是輸入一張CoreImage户盯,它會自動檢測,輸入一個檢測到的數(shù)組饲化。

CIDetector *dectecor = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:nil];
NSArray<CIFeature *> *array =  [detector featuresInImage:image];

這個CIFeature里面就有檢測到的信息莽鸭。

@property (readonly, assign) CGRect bounds;
@property (readonly, assign) BOOL hasLeftEyePosition;
@property (readonly, assign) CGPoint leftEyePosition;
@property (readonly, assign) BOOL hasRightEyePosition;
@property (readonly, assign) CGPoint rightEyePosition;
@property (readonly, assign) BOOL hasMouthPosition;
@property (readonly, assign) CGPoint mouthPosition;

有檢測到的人臉位置,左眼滓侍、右眼蒋川、嘴的位置。但是撩笆,除了臉的位置捺球,其他的都不是特別準(zhǔn)確。

檢測到人臉之后就簡單了夕冲,我們先用一個框標(biāo)記出人臉位置氮兵。


檢測紅框.png

這是什么??,說好的檢測到了喃歹鱼。
其實這就是第一個坑泣栈,檢測到的這個人臉位置,并不是真正在imageview的位置,而是在這個圖片真實大小的位置南片。

/** A face feature found by a CIDetector.All positions are relative to the original image. */

圖片真實大小.png

因為這張圖片寬度為1366掺涛,在image中顯示是被按比例縮放了的,所以我們相應(yīng)的要對坐標(biāo)進(jìn)行縮放疼进,使之對應(yīng)到imageview的frame上薪缆。
縮小比列

CGFloat scale = imageView.bounds.size.height/imageView.image.size.height;
CGRect frame = CGRectMake(obj.bounds.origin.x * scale,obj.bounds.origin.y * scale, obj.bounds.size.width * scale, obj.bounds.size.height * scale)

你現(xiàn)在會想,這下好了吧伞广。


Snip20170803_3.png

Too young拣帽!蘋果爸爸會讓你這么容易就處理完成么。這個框為什么還是匹配不上敖莱<跏谩!G蟆拧粪!
因為在這個bounds的originPoint在左下角,而不是UIKit中的左上角沧侥,所以我們還需要對y進(jìn)行轉(zhuǎn)換既们。

y = self.imageView.bounds.size.height - obj.bounds.origin.y * scale - obj.bounds.size.height * scale
檢測成功.png

OK,現(xiàn)在終于檢測成功了正什。接下來我們上馬變騎兵喜鼓。


打馬賽克

CoreImage并沒有直接對某一塊進(jìn)行打碼處理的filter篙挽,我們需要換其他方式。

1.先將整張圖進(jìn)行打碼
2.將人臉的地方扣出來
3.將整張打碼的圖進(jìn)行人臉的地方mask许帐,類似于view的mask一樣
4.然后將mask出來的圖片覆蓋到原圖上去

看起來挺復(fù)雜的盾致,但是按著順序來一步一步走主经,還是挺簡單的。
1庭惜、首先罩驻,我們對整張圖片進(jìn)行模糊,

CIFilter *pixellateFilter = [CIFilter filterWithName:@"CIPixellate"];
[self.pixellateFilter setValue:image forKey:kCIInputImageKey];
[self.pixellateFilter setValue:@30 forKey:kCIInputScaleKey];
CIImage *pixelImage = pixellateFilter.outputImage;

這個參數(shù)30是模糊的程度护赊,可以自由設(shè)置惠遏。設(shè)置的越大,每塊馬賽克的大小越大骏啰。
2节吮、接下來我們將人臉的地方位置標(biāo)記出來,形成一個“模板”判耕。

CIFilter *radialGradientFileter = [CIFilter filterWithName:@"CIRadialGradient"];
[radialGradientFileter setValue:[CIColor colorWithRed:0 green:1 blue:0 alpha:1] forKey:@"inputColor0"];
[radialGradientFileter setValue:[CIColor colorWithRed:0 green:0 blue:0 alpha:0] forKey:@"inputColor1"];
[radialGradientFileter setValue:@(MIN(obj.bounds.size.width/2, obj.bounds.size.height/2)) forKey:@"inputRadius0"];
[radialGradientFileter setValue:@(MIN(obj.bounds.size.width/2, obj.bounds.size.height/2)+1) forKey:@"inputRadius1"];
CIVector *centerVector = [CIVector vectorWithX:obj.bounds.origin.x + obj.bounds.size.width/2 Y:obj.bounds.origin.y + obj.bounds.size.height/2];
[radialGradientFileter setValue:centerVector forKey:kCIInputCenterKey];

我們形成了一張無色背景透绩,在特定的地方生成了一個綠色的圈,這個圈有2層,一層是obj.bounds.size.width/2帚豪,一層是obj.bounds.size.width/2+1碳竟。通過設(shè)置kCIInputCenterKey來設(shè)置綠圈的位置。
因為我們這兒只有1個數(shù)據(jù)狸臣,只需要生成一個摳圖的地方就行莹桅,如果我們檢測多張臉的話,還需要用CISourceOverCompositing來將這些摳圖合并固棚,形成一張總的摳圖模板统翩。
3、mask

CIFilter *blendWithMaskFileter = [CIFilter filterWithName:@"CIBlendWithMask"];
[blendWithMaskFileter setValue:image forKey:kCIInputBackgroundImageKey];
[blendWithMaskFileter setValue:pixelImage forKey:kCIInputImageKey];
[blendWithMaskFileter setValue:radialGradientImage forKey:kCIInputMaskImageKey];
CIImage *endImage = [blendWithMaskFileter outputImage];

將這三張圖輸入到mask濾鏡中此洲,原圖是背景圖kCIInputBackgroundImageKey厂汗,打碼的圖是輸入圖kCIInputImageKey,摳圖是kCIInputMaskImageKey呜师。
這樣娶桦,最后輸出的就是將人臉打碼的圖片。


打碼圖.png

這樣我們就能將我們處理過的視頻直接寫入到本地了汁汗。Demo在這里衷畦。

本來準(zhǔn)備將攝像頭的也寫入這一篇,發(fā)現(xiàn)有點長了知牌,重新看一篇吧祈争。

參考文章

About Core Image

CIRadialGradient

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市角寸,隨后出現(xiàn)的幾起案子菩混,更是在濱河造成了極大的恐慌,老刑警劉巖扁藕,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沮峡,死亡現(xiàn)場離奇詭異,居然都是意外死亡亿柑,警方通過查閱死者的電腦和手機(jī)邢疙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來望薄,“玉大人疟游,你說我怎么就攤上這事∈浇茫” “怎么了乡摹?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長采转。 經(jīng)常有香客問我聪廉,道長瞬痘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任板熊,我火速辦了婚禮框全,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘干签。我一直安慰自己津辩,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布容劳。 她就那樣靜靜地躺著喘沿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪竭贩。 梳的紋絲不亂的頭發(fā)上蚜印,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音留量,去河邊找鬼窄赋。 笑死,一個胖子當(dāng)著我的面吹牛楼熄,可吹牛的內(nèi)容都是我干的忆绰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼可岂,長吁一口氣:“原來是場噩夢啊……” “哼错敢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缕粹,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伐债,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后致开,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡萎馅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年双戳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糜芳。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡飒货,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出峭竣,到底是詐尸還是另有隱情塘辅,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布皆撩,位于F島的核電站扣墩,受9級特大地震影響哲银,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呻惕,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一荆责、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亚脆,春花似錦做院、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柑营,卻和暖如春屈雄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背由境。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工棚亩, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虏杰。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓讥蟆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纺阔。 傳聞我的和親對象是個殘疾皇子瘸彤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容