iOS 11之Vision人脸检测

本文详细介绍了在iOS 11中如何使用Vision框架进行人脸检测和面部特征识别,包括静态和动态场景下的人脸检测,以及处理坐标转换的问题。文中还提到了在实际应用中可能遇到的内存和性能挑战,以及图片方向的要求。
摘要由CSDN通过智能技术生成

代码地址如下:
http://www.demodashi.com/demo/11783.html

大道如青天,我独不得出

前言

在上一篇iOS Core ML与Vision初识中,初步了解到了vision的作用,并在文章最后留了个疑问,就是类似下面的一些函数有什么用

- (instancetype)initWithCIImage:(CIImage *)image options:(NSDictionary<VNImageOption, id> *)options;

- (instancetype)initWithCVPixelBuffer:(CVPixelBufferRef)pixelBuffer options:(NSDictionary<VNImageOption, id> *)options;

在查阅一些资料后,最终通过这些函数得到了如下的效果

face.gif
对,没错,这就是通过initWithCVPixelBuffer函数来实现的。当然vision的作用远不于此,还有如下的效果
1、图像匹配(上篇文章中的效果)
2、矩形检测
3、二维码、条码检测
4、目标跟踪
5、文字检测
6、人脸检测
7、人脸面部特征检测
由于对人脸识别比较感兴趣,所以这里就主要简单了解了下人脸部分,下面就针对人脸检测和面部检测写写

Vision支持的图片类型

通过查看VNRequestHandler.h文件,我们可以看到里面的所有初始化函数,通过这些初始化函数,我们可以了解到支持的类型有:
1、CVPixelBufferRef
2、CGImageRef
3、CIImage
4、NSURL
5、NSData

Vision使用

在使用vision的时候,我们首先需要明确自己需要什么效果,然后根据想要的效果来选择不同的类,最后实现自己的效果
1、需要一个RequestHandler,在创建RequestHandler的时候,需要一个合适的输入源,及图片类型
2、需要一个Request,在创建Request的时候,也需要根据实际情况来选择,Request大概有如下这么些

request.jpeg
3、通过requestHandlerrequest联系起来,然后得到结果

[handler performRequests:@[requset] error:&error];

4、处理结果VNObservation,在VNRequestresults数组中,包含了VNObservation结果,VNObservation也分很多种,这和你Request的类型是相关联的

Vision结果继承关系.png

在完成上述步骤后,我们就可以根据结果来实现一些我们想要的效果

人脸矩形检测

这里我们需要用到VNDetectFaceRectanglesRequest

requset = [[VNDetectFaceRectanglesRequest alloc] initWithCompletionHandler:completionHandler];

在得到结果后,我们需要处理下坐标

    for (VNFaceObservation *faceObservation in observations) {
        //boundingBox
        CGRect transFrame = [self convertRect:faceObservation.boundingBox imageSize:image.size];
        [rects addObject:[NSValue valueWithCGRect:transFrame]];
    }
// 转换Rect
- (CGRect)convertRect:(CGRect)boundingBox imageSize:(CGSize)imageSize{
    CGFloat w = boundingBox.size.width * imageSize.width;
    CGFloat h = boundingBox.size.height * imageSize.height;
    CGFloat x = boundingBox.origin.x * imageSize.width;
    CGFloat y = imageSize.height * (1 - boundingBox.origin.y - boundingBox.size.height);//- (boundingBox.origin.y * imageSize.height) - h;
    return CGRectMake(x, y, w, h);
}

在返回结果中的boundingBox中的坐标,我们并不能立即使用,而是需要进行转换,因为这里是相对于image的一个比例,这里需要注意的是y坐标的转换,因为坐标系的y轴和UIViewy轴是相反的。
最后就是通过返回的坐标进行矩形的绘制

+ (UIImage *)gl_drawImage:(UIImage *)image withRects:(NSArray *)rects
{
    UIImage *newImage = nil;
    UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineCap(context,kCGLineCapRound); //边缘样式
    CGContextSetLineJoin(context, kCGLineJoinRound);
    CGContextSetLineWidth(context,2); //线宽
    CGContextSetAllowsAntialiasing(context,YES); //打开抗锯齿
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);

    //绘制图片
    [image drawInRect:CGRectMake(0, 0,image.size.width, image.size.height)];
    CGContextBeginPath(context);
    for (int i = 0; i < rects.count; i ++) {
   
        CGRect rect = [rects[i] CGRectValue];
        CGPoint sPoints[4];//坐标点
        sPoints[0] = CGPointMake(rect.origin.x, rect.origin.y);//坐标1
        sPoints[1] = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y);//坐标2
        sPoints[2] = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);//坐标3
        sPoints[3] = CGPointMake(rect.origin.x , rect.origin.y + rect.size.height);

        CGContextAddLines(context, sPoints, 4);//添加线
        CGContextClosePath(context); //封闭
    }
    CGContextDrawPath(context, kCGPathFillStroke); //根据坐标绘制路径

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值