美文网首页iOS Developer
CoreImage系列二:人脸检测

CoreImage系列二:人脸检测

作者: 鐵甲陳小寶 | 来源:发表于2017-08-03 16:02 被阅读168次

    这是CoreImage系列的第二章,主要有三点

    1.对静态图片进行人脸检测与打马赛克
    2.对摄像头录像进行人脸检测与打马赛克
    3.将处理后的视频数据存入本地

    技术难点其实并没有多少,主要是记录自己在这个过程中踩过的坑和API熟悉。


    人脸检测

    CoreImage其实在iOS5的时候就推出了人脸检测功能,但是并不强大;仅仅做到能识别出人脸、五官等等,很多第三方SDK中的人脸检测用到更底层的OpenCV,当然这也更复杂,涉及到很多算法等等。但就我们日常的检测来说,CoreImage提供的就已经足够了。

    CIDetector

    这个类就是CoreImage中进行检测的类,它可以进行很多检测,人脸只是其中的一种。
    它的用法其实很简单,就是输入一张CoreImage,它会自动检测,输入一个检测到的数组。

    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;
    

    有检测到的人脸位置,左眼、右眼、嘴的位置。但是,除了脸的位置,其他的都不是特别准确。

    检测到人脸之后就简单了,我们先用一个框标记出人脸位置。


    检测红框.png

    这是什么👻,说好的检测到了喃。
    其实这就是第一个坑,检测到的这个人脸位置,并不是真正在imageview的位置,而是在这个图片真实大小的位置。

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

    图片真实大小.png

    因为这张图片宽度为1366,在image中显示是被按比例缩放了的,所以我们相应的要对坐标进行缩放,使之对应到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)
    

    你现在会想,这下好了吧。


    Snip20170803_3.png

    Too young!苹果爸爸会让你这么容易就处理完成么。这个框为什么还是匹配不上啊!!!!
    因为在这个bounds的originPoint在左下角,而不是UIKit中的左上角,所以我们还需要对y进行转换。

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

    OK,现在终于检测成功了。接下来我们上马变骑兵。


    打马赛克

    CoreImage并没有直接对某一块进行打码处理的filter,我们需要换其他方式。

    1.先将整张图进行打码
    2.将人脸的地方扣出来
    3.将整张打码的图进行人脸的地方mask,类似于view的mask一样
    4.然后将mask出来的图片覆盖到原图上去

    看起来挺复杂的,但是按着顺序来一步一步走,还是挺简单的。
    1、首先,我们对整张图片进行模糊,

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

    这个参数30是模糊的程度,可以自由设置。设置的越大,每块马赛克的大小越大。
    2、接下来我们将人脸的地方位置标记出来,形成一个“模板”。

    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。通过设置kCIInputCenterKey来设置绿圈的位置。
    因为我们这儿只有1个数据,只需要生成一个抠图的地方就行,如果我们检测多张脸的话,还需要用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在这里。

    本来准备将摄像头的也写入这一篇,发现有点长了,重新看一篇吧。

    参考文章

    About Core Image

    CIRadialGradient

    相关文章

      网友评论

        本文标题:CoreImage系列二:人脸检测

        本文链接:https://www.haomeiwen.com/subject/qnxylxtx.html