這是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)記出人臉位置氮兵。
這是什么??,說好的檢測到了喃歹鱼。
其實這就是第一個坑泣栈,檢測到的這個人臉位置,并不是真正在imageview的位置,而是在這個圖片真實大小的位置南片。
/** A face feature found by a CIDetector.All positions are relative to the original image. */
因為這張圖片寬度為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)在會想,這下好了吧伞广。
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
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呜师。
這樣娶桦,最后輸出的就是將人臉打碼的圖片。
這樣我們就能將我們處理過的視頻直接寫入到本地了汁汗。Demo在這里衷畦。
本來準(zhǔn)備將攝像頭的也寫入這一篇,發(fā)現(xiàn)有點長了知牌,重新看一篇吧祈争。