美文网首页iOS技术栈IOSIOS面试裤
选取图像 + 人脸识别

选取图像 + 人脸识别

作者: earthX | 来源:发表于2016-05-13 18:23 被阅读1847次

    今天无意翻到了人脸识别,突然想在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];
            }
    
        }
    
    监测成功.png 监测失败.jpg

    上述图像载入的时候,采用了一个用户头像上传的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 类来获取图片视频,大体分为以下几个步骤:

    1. 初始化UIImagePickerController 类;
    2. 设置UIImagePickerController 实例的数据来源类型;
    3. 设置设置代理;
    4. 如果需要做图片修改的话设置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,详细记录。

    附上传送门:https://github.com/earthX/EXFaceRecognition

    相关文章

      网友评论

        本文标题:选取图像 + 人脸识别

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