代码地址如下:
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;
在查阅一些资料后,最终通过这些函数得到了如下的效果
对,没错,这就是通过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
大概有如下这么些
3、通过requestHandler
将request
联系起来,然后得到结果
[handler performRequests:@[requset] error:&error];
4、处理结果VNObservation
,在VNRequest
的results
数组中,包含了VNObservation
结果,VNObservation
也分很多种,这和你Request
的类型是相关联的
在完成上述步骤后,我们就可以根据结果来实现一些我们想要的效果
人脸矩形检测
这里我们需要用到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
轴和UIView
的y
轴是相反的。
最后就是通过返回的坐标进行矩形的绘制
+ (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