今天无意翻到了人脸识别,突然想在ios设备上实现,这里我们主要用到了几个类:CIContext,CIDetector
CIContext
CIContext 是Core Image的一个对象,Core Image是一个OS X和iOS的图像处理框架。通过它Core Image可以绘制一个CIFilter产生的结果。一个Core Image Context可以基于CPU或GPU。
CIDetector
Core Image 已经提供了 CIDetector 类。用它来做人脸检测已经相当好了,并且它已经被优化过,使用起来也很容易:
CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];NSArray *faces = [faceDetector featuresInImage:image];
从该图片中检测到的每一张面孔都在数组 faces 中保存着一个 CIFaceFeature 实例。这个实例中保存着这张面孔的所处的位置和宽高,除此之外,眼睛和嘴的位置也是可选的。
@interface CIFaceFeature : CIFeature
{
CGRect bounds;
BOOL hasLeftEyePosition;
CGPoint leftEyePosition;
BOOL hasRightEyePosition;
CGPoint rightEyePosition;
BOOL hasMouthPosition;
CGPoint mouthPosition;
BOOL hasTrackingID;
int trackingID;
BOOL hasTrackingFrameCount;
int trackingFrameCount;
BOOL hasFaceAngle;
float faceAngle;
BOOL hasSmile;
BOOL leftEyeClosed;
BOOL rightEyeClosed;
}
人脸监测的步骤是:先获取图像,然后转成CIImage格式,利用CIFeature特征,使用探测器CIDetector拿到所有的人脸,然后在图中圈出,即可达到人脸识别的目的,关键代码如下:
//获取图片
UIImage *image = self.imageview.image;
//转成CIImage
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
//拿到所有的脸
NSArray <CIFeature *> *featureArray = [self.detector featuresInImage:ciImage];
if (featureArray.count == 0) {
NSLog(@"未检测到人脸");
//初始化提示框;
UIAlertController *alert1 = [UIAlertController alertControllerWithTitle:@"提示" message:@"未检测到人脸" preferredStyle: UIAlertControllerStyleAlert];
[alert1 addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
//点击按钮的响应事件;
}]];
//弹出提示框;
[self presentViewController:alert1 animated:true completion:nil];
}else{
//遍历
for (CIFeature *feature in featureArray){
//将image沿y轴对称
CGAffineTransform transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, -1);
//将image往上移动
CGFloat imageH = ciImage.extent.size.height;
transform = CGAffineTransformTranslate(transform, 0, -imageH);
//在image上画出方框
CGRect feaRect = feature.bounds;
//调整后的坐标
CGRect newFeaRect = CGRectApplyAffineTransform(feaRect, transform);
//调整imageView的frame
CGFloat imageViewW = self.imageview.bounds.size.width;
CGFloat imageViewH = self.imageview.bounds.size.height;
CGFloat imageW = ciImage.extent.size.width;
//显示
CGFloat scale = MIN(imageViewH / imageH, imageViewW / imageW);
//缩放
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scale, scale);
//修正
newFeaRect = CGRectApplyAffineTransform(newFeaRect, scaleTransform);
newFeaRect.origin.x += (imageViewW - imageW * scale ) / 2;
newFeaRect.origin.y += (imageViewH - imageH * scale ) / 2;
NSLog(@"xxx:%f",newFeaRect.origin.x);
//绘画
UIView *breageView = [[UIView alloc] initWithFrame:newFeaRect];
breageView.layer.borderColor = [UIColor redColor].CGColor;
breageView.layer.borderWidth = 2;
[self.imageview addSubview:breageView];
}
}
上述图像载入的时候,采用了一个用户头像上传的demo,顺道一起研究了,选取图像可以选择两种途径,第一种是拍照识别,第二种从个人相册中载入,并且将载入后的图像写入沙盒中。
选取图像
@property(nonatomic,strong) UIPopoverController *imagePickerPopover; //
需要注意的是 UIPopoverController ,是iPad开发中常见的一种控制器(在iPhone上不允许使用)
跟其他控制器不一样的是,它直接继承自NSObject,并非继承自UIViewController
它只占用部分屏幕空间来呈现信息,而且显示在屏幕的最前面,但是在IOS9的时候已经被废除。
可以选用IOS8提供的新特性 UIPresentationController,UIPresentationController是提供高级视图切换的类。它让管理present ViewController的过程变得简单。
在iPad的设置页面,可以通过popOver弹出一个UIViewController,这个弹出的,可以和用户交互的Controller叫做PresentedViewController,而后面那个被部分遮挡的UIViewController叫做PresentingViewController,而在UIPresentationController中,PresentedViewController是presentation的content,而PresentingViewController叫做Chrome。
UIPopoverPresentationController
它在iOS8中替代了UIPopoverController,它在功能上与旧的controller完全等同,并且新增了一些内置的适配特性,可以自动适配iPad与iPhone。以下是新版与旧版接口的比较:UIPopoverController使用方法:
UIViewController *contentController = [[UIViewController alloc] init];
UIPopoverController *poc = [UIPopoverController alloc] initWithContentViewController:contentController];
[poc presentPopoverFromBarButtonItem:item permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
但是这个是ipad的类,如果要创建一个在iPad与iPhone上通用的方法,那么需要以下的代码:
UIViewController *contentController = [[UIViewController alloc] init];
if([[UIDevice currentDevice] userInterfaceIdim] == UIUserInterfaceIdiomPad){
UIPopoverController *poc = [UIPopoverController alloc] initWithContentViewController:contentController];
[poc presentPopoverFromBarButtonItem:item permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:contentController animated:YES completion:nil];
}
然而我们如果使用UIPopoverPresentationController,那么就不再需要判断设备,例如:
UIViewController *contentController = [[UIViewController alloc] init];
UIPopoverPresentationController *popVC = contentController.popoverPresentationController;
popVC.barButtonItem = item;
popVC.permittedArrowDirections = UIPopoverArrowDirectionAny;
popVC.delegate = self;
[self presentViewController:contentController animated:YES completion:nil];
- 将UIViewController的modalPresentationStyle设置成UIModalPresentationPopover,这个值用来实现popover效果,并且各个平台自动适应。第二行中,通过popoverPresentationController属性来获取它的popoverPresentationController,而不是创建一个新的。然后设置它的一些界面属性,最后调用presentViewController方法来显示这个controller。这样就可以在iPad与iPhone显示自动适应的popover效果了。
其中,iPhone上的自适应是在delegate中实现的:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresemtatopmController:(UIPresentationController * controller)
{
return UIModalPresentationFullScreen;
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style
{
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller.presentedViewController];
return navController;
}
-
UIImagePickerController
UIImagePickerController 是系统提供的用来获取图片和视频的接口,用UIImagePickerController 类来获取图片视频,大体分为以下几个步骤:
- 初始化UIImagePickerController 类;
- 设置UIImagePickerController 实例的数据来源类型;
- 设置设置代理;
- 如果需要做图片修改的话设置allowsEditing =yes。
数据来源类型一共有三种:
enum {
UIImagePickerControllerSourceTypePhotoLibrary ,//来自图库
UIImagePickerControllerSourceTypeCamera ,//来自相机
UIImagePickerControllerSourceTypeSavedPhotosAlbum //来自相册
};
在用这些来源的时候最好检测以下设备是否支持;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
NSLog(@"支持相机");
}
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
NSLog(@"支持图库");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
{
NSLog(@"支持相片库");
}
调用摄像头来获取资源
- (void)viewDidLoad {
[super viewDidLoad];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker = [[UIImagePickerController alloc]init];
picker.view.backgroundColor = [UIColor orangeColor];
UIImagePickerControllerSourceType sourcheType = UIImagePickerControllerSourceTypeCamera;
picker.sourceType = sourcheType;
picker.delegate = self;
picker.allowsEditing = YES;
}
上面只是实例了UIImagePickerController及其属性 在需要获取图片的时候需要弹出窗口调用
[self presentViewController:picker animated:YES completion:nil];
完整的选取相册代码如下:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"请选择打开方式" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:@"打开相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
//创建UIPopoverController对象前先检查当前设备是不是ipad
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
self.imagePickerPopover.delegate = self;
[self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:imagePicker animated:YES completion:nil];
}
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"我的相册" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
//创建UIPopoverController对象前先检查当前设备是不是ipad
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
self.imagePickerPopover.delegate = self;
[self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:imagePicker animated:YES completion:nil];
}
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *_Nonnull action){
//取消
}]];
//弹出提示框
[self presentViewController:alert animated:YES completion:nil];
本文从人脸识别出发,记录了ios设备进行人脸识别时,使用的CIDetector类,顺带温习了一下拉起相册的相关知识,由UIPopoverController到UIPresentationController,详细记录。