[Diving into WWDC 2017] Vision Framework: Building on Core ML

基于 Core ML 的计算机视觉框架

iOS 11 中集成了 Core ML 框架,即机器学习框架。提供给开发者一系列机器学习的 API,包括 Vison 计算机视觉、NLP 自然语言处理等 API。通过 Core ML 框架,开发者可以将训练好的机器学习模型集成到项应用中,并通过机器学习得到开发者想要的结果。Vision 是建立在 Core ML 基础上的处理计算机视觉相关的 Framework,通过 Vision 开发者可以做高性能的图片分析和用计算机视觉去识别人脸、检测容貌以及对图片和视频中的场景进行分类。

Core ML 介绍

Core ML 是特定框架功能的基础,支持用于用户图像分析的 Vision,用于自然语言处理的 Foundation (如 NSLinguisticTagger 类)和用于评估已经学习到的决策树 GamePlayKit。Core ML 本身构建于低层面的原语上,比如 Accelerate、BNNS、Metal Performance Shaders。

借助 Core ML,您可以将已训练好的机器学习模型,集成到自己的应用当中,Core ML 支持的操作系统:

  • iOS 11.0+Beta
  • macOS 10.13+Beta
  • tvOS 11.0+Beta
  • watchOS 4.0+Beta

训练好的模型:

模型的功能是基于新的输入数据进行预测。比如,如果一个模型在一个地区的历史房价数据上进行了训练,那么它就可能能够根据房子的卧室和浴室数量来预测房价。Core ML 支持大量机器学习模型,包括神经网络、树集成、支持向量机和广义的线性模型。

将训练好的模型转换成 Core ML

如果你的模型是使用支持的第三方机器学习工具创建和训练的,那么你可以使用 Core ML Tools 将其转换成 Core ML 模型格式。下表给出了支持的模型和第三方工具。

Core ML Tools 是一个 Python 包(coremltools),托管在 Python Package Index (PyPI) 上。要了解更多有关 Python 包的信息,请参阅:网址

Vision

Vision 是建立在 Core ML 上层的 Framework。类似 NLP 处理语言,Vision 专门用来处理视觉。Vison 可以进行多种应用场景的机器学习处理,具体如下:

应用场景

  • 人脸检测:支持检测笑脸、侧脸、局部遮挡脸部、戴眼镜和帽子等场景,可以标记出人脸的矩形区域
  • 人脸特征点:可以标记出人脸和眼睛、眉毛、鼻子、嘴、牙齿的轮廓,以及人脸的中轴线
  • 图像配准
  • 矩形检测
  • 二维码/条形码检测
  • 文字检测
  • 目标跟踪:脸部,矩形和通用模板

Vision 使用方法

Vision 将各种功能的 Request 提供给一个 RequestHandler,Handler 持有图片信息,并将处理结果分发给每个 Request 的 completion Block 中。可以从 results 属性中得到 Observation 数组,然后进行更新 UI 等操作。因为 completion Block 所执行的队列跟 perform request 的队列相同,所以更新 UI 时记得使用主队列。 Vision 操作流水线分为两类:分析图片和跟踪队列。可以使用图片检测出的物体或矩形结果(Observation)来作为跟踪队列请求(Request)的参数。

开发者可以使用 Vision 来做各种关于图像的 Machine Learning 处理,如人脸检测(Face Detection:Machine Learning 的人脸检测可以检测更多场景下的人脸,比如侧脸,戴眼镜都可以检测出)、人脸标记(Face Landmarks)、图像配准(Image registration)、矩形探测(Rectangle Detection),扫描二维码(Barcode Detection)、文字检测(Text Detection)、物体追踪(Object Tracking)等。更详细的应用请参加已公开文档:[文档] (https://developer.apple.com/documentation/vision)。

Vision 是一个高层次 API,为开发者封装了复杂的机器视觉实现,开发者不需要成为一个机器视觉的专家,只需要明白自己需要什么,就可以使用 Vision 轻易完成。记住两个关键 API:VNImageRequestHandlerVNSequnenceRequestHandler。一个处理单张图片,一个处理序列图片如摄像头实时捕捉的场景。使用两个Handler 发起对应的 Request 请求就可以获取到相关结果了,使用起来真的非常方便。如下图:


Vision 中涵盖的重要类

图像识别

  • VNImageRequestHandler: 处理单张图片的分析请求的类
  • VNSequenceRequestHandler: 处理一系列图片的分析请求的类

人脸检测和识别

  • VNDetectFaceRectanglesRequest: 图片中人脸的分析请求类
  • VNDetectFaceLandmarksRequest: 图片中人脸特征(眼睛、嘴)的分析请求类
  • VNFaceObservation: 通过图片分析请求得到的人脸信息

机器学习图片分析

  • VNCoreMLRequest: 使用 Core ML 处理图片生成的请求类
  • VNClassificationObservation: 图片分析请求获取的场景分类信息
  • VNPixelBufferObservation:Core ML图片分析请求输出的图片信息
  • VNCoreMLFeatureValueObservation: Core ML 图片分析请求获取的一系列 key-value 信息

二维码识别

  • VNDetectBarcodesRequest: 查找图片中二维码的请求
  • VNBarcodeObservation: 图片请求获取的二维码的信息

Image Alignment Analysis(从命名即可知道类的功能)

  • VNTranslationalImageRegistrationRequest
  • VNHomographicImageRegistrationRequest
  • VNImageRegistrationRequest
  • VNImageHomographicAlignmentObservation
  • VNImageTranslationAlignmentObservation
  • VNImageAlignmentObservation

文本检测

  • VNDetectHorizonRequest: 图片视角的分析请求
  • VNHorizonObservation: 图片视角信息

物体检测和追踪

  • VNDetectRectanglesRequest
  • VNTrackRectangleRequest
  • VNTrackObjectRequest
  • VNRectangleObservation
  • VNDetectedObjectObservation

Vision 支持的图片数据类型:

  • CVPixelBufferRef
  • CGImageRef
  • CIImage
  • NSURL
  • NSData

这几乎涵盖了 iOS 中图片相关的 API,很实用很强大。

Vision 有三种 resize 图片的方式,无需使用者再次裁切缩放

  • VNImageCropAndScaleOptionCenterCrop
  • VNImageCropAndScaleOptionScaleFit
  • VNImageCropAndScaleOptionScaleFill

另外性能方面,Vision 与 iOS 上其他几种带人脸检测功能框架的对比情况如下:

使用 Vision 探测人脸的 Demo

typedef void (^RequestBlock)(void);

@interface ViewController ()

@property (nonatomic, strong) UIImageView* imageView;
@property (nonatomic, strong) UILabel* label;
@property (nonatomic, copy)  RequestBlock block;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIImage* image = [UIImage imageNamed:@"face.png"];

    [self createImageView:image];

    VNDetectFaceRectanglesRequest* faceRequest = [[VNDetectFaceRectanglesRequest alloc] initWithCompletionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error) 
    {

        VNDetectFaceRectanglesRequest *faceRequest = (VNDetectFaceRectanglesRequest*)request;

        VNFaceObservation*firstObservation = [faceRequest.results firstObject];

        CGRect boundingBox = [firstObservation boundingBox];

        NSUInteger width =CGImageGetWidth(image.CGImage);

        NSUInteger height =CGImageGetHeight(image.CGImage);

        CGRect rect =VNImageRectForNormalizedRect(boundingBox,width,height);

        CGRect frame =  CGRectMake(rect.origin.x,  rect.origin.y, rect.size.width, rect.size.height);
        self.label.frame = [self.imageView convertRect:frame toView:self.view];

    }];

    VNImageRequestHandler*handler = [[VNImageRequestHandler alloc] initWithCGImage:image.CGImage options:@{}];
     [handler performRequests:@[faceRequest] error:nil];
    self.block = ^(void){
        [handler performRequests:@[faceRequest] error:nil];
    };


}


- (void)createImageView:(UIImage*)image
{
    self.imageView = [[UIImageView alloc] initWithImage:image];

    self.imageView.frame = CGRectMake(20, 50, CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
    [self.view addSubview:self.imageView];

    self.label = [[UILabel alloc] init];
    self.label.backgroundColor = [UIColor clearColor];
    self.label.layer.borderWidth = 0.5;
    self.label.layer.borderColor = [UIColor redColor].CGColor;
    [self.view addSubview:self.label];

}

- (void)moviewImageView
{
    CGRect frame = self.imageView.frame;
    frame = CGRectMake(frame.origin.x, frame.origin.y+100, frame.size.width, frame.size.height);
    [UIView animateWithDuration:3 animations:^{
        self.imageView.frame = frame;
    }];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch* touch = touches.anyObject;
    CGPoint point = [touch locationInView:self.view];
    self.imageView.center = point;
    self.block();
}

效果如下图所示