zoukankan      html  css  js  c++  java
  • 图像处理

    你可能用过UIImage,用过CGImage。但是有没有用过CIImage呢???

    我也是第一次用这个CIImage,查看一下苹果的官方API可以看到:它是CoreImage中的一个类目。So,问题来了,什么是CoreImage呢?

    CoreImage苹果官方给的一句话是:

    Perform image processing and video image manipulation with the Core Image framework.

    就这没了??也太简单了。不过说的言简意赅:用中文翻译一下就是:

    使用Core Image框架:执行图像加工和视频图像处理。

    ------------------------开始啰嗦CoreImage了------------------------

    第一个类:CIColor。

    这个不多讲解,你可把它和UIColor做一个对比,内容几乎一样,所以如果你会用UIColor就会用CIColor。但是对类本身介绍一下把。

    CIColor包括了那些可用颜色值的颜色值和颜色空间。你会和其他Core Image框架中的其他类混合使用,例如CIFilter,CIContext和CIImage在操作图片是来创建滤镜。

    其他的类还有:
    CIContext/CIDetector/CIFeature/CIFilter等几个。不多,有时间可以看看看。下面的内容中会涉及一些,到那个时候再解释解释把。

    ------------------------就啰嗦到这里把------------------------

    下面开始讲解对图像的处理:具体包括拍照、读取图库内容、高斯模糊、旧色调,还有比较NB的人脸识别。

    1、拍照和读取图库内容

    这两个功能的核心就是UIImagePickerViewController。

    该类可以读取iOS设备中的图片以及视频。还可以拍照。接下来就讲解一下如何实现吧。

    首先我们需要在自定义的ViewController中设置代理

    @interface ViewController : UIViewController<UIImagePickerControllerDelegate,UINavigationControllerDelegate>

    也就是说我们如果想用这个类,首先我们需要添加UIImagePickerControllerDelegate和UINavigationControllerDelegate协议。这样才能使用

    然后看如何调取相机吧:

    - (IBAction)takePhotoAction:(id)sender {
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
            _imagePicker = [[UIImagePickerController alloc] init];
            _imagePicker.delegate = self;
            _imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
            
            [self presentViewController:_imagePicker animated:YES completion:nil];
        }else {
            NSLog(@"相机不可用");
            
        }
    }

    我通过点击一个按钮触发该事件,然后可以看一下怎么实现的。这个不难,好好看看

    首先我们需要用UIImagePickerViewController的类方法isSourceTypeAvailable:方法去判断一下相机是否可用。

    其中的UIImagePickerControllerSourceTYpeCamera其实是一个枚举:里面定义了如下的内容:

    typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
        UIImagePickerControllerSourceTypePhotoLibrary,
        UIImagePickerControllerSourceTypeCamera,
        UIImagePickerControllerSourceTypeSavedPhotosAlbum
    };

    这是苹果API中的东西。我可没有更改。可以看到里面有三个枚举类:

    第一个指的是图库,第二个指的是相机,第三个指的是保存相薄。

    下面的就不用说了。不对,还有一个更重要的呢。

    sourceType:你设置的这个souceType就是你调用的类型:包括相机,图库和相薄。

    既然都代理了,那把代理方法也写上去把。

    #pragma mark - UIImagePickerViewDelegate
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
        UIImage *originImage;
        if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            originImage = (UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage];
        }else if (picker.sourceType==UIImagePickerControllerSourceTypePhotoLibrary)
        {
            originImage = (UIImage *)[info objectForKey:UIImagePickerControllerEditedImage];
    
        }
        self.imageView.image = originImage;
        self.imageView.contentMode = UIViewContentModeScaleAspectFit;
        _imagePicker.delegate = nil;
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
        _imagePicker.delegate = nil;
        [self dismissViewControllerAnimated:YES completion:nil];
    }

    当我们点击相机的时候,我们进入一个拍照界面:(图片就不贴出来了)

    里面有一个Cancel按钮,也就是当我点击Cancel按钮时会触发代理方法

    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
        _imagePicker.delegate = nil;
        [self dismissViewControllerAnimated:YES completion:nil];
    }

    这里我们把代理置空,然后让该ImagePicketView消失。这样才能返回按钮页面。

    另一个代理方法就是用来当拍照后点击使用图片那个按钮触发的代理方法。里面有个info。这个东西太有用了,里面都是信息:什么UIImagePickerControllerMediaType、UIImagePickerControllerOriginalImage,还有UIImagePickerControllerMediaMetadata。他们都是键值,然后里面有好多东西,你可以自己试一下里面有啥。我这里通过

    UIImagePickerControllerOriginalImage得到的拍的照片。拿到照片之后我们就可以对他进行处理了。这里还要记得让pickerView消失并且把代理置空。

    OK,这会拍照会用了吧。就这么简单。

    2、读取图库内容:直接看代码。

    - (IBAction)catPhotoFromLibraryAction:(id)sender {
        if(_imagePicker==nil) {
            _imagePicker = [[UIImagePickerController alloc] init];
            _imagePicker.delegate = self;
            _imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;   //提供数据来源
            _imagePicker.allowsEditing = YES;   //允许编辑
            [self presentViewController:_imagePicker animated:YES completion:nil];
        }
    }

    这里就是读取图库内容。我们可以发现。只是sourceType改了一下。

    (其中的allowsEditing设置为yes就意味着你选取的图片可以编辑,默认是No。)

    这个方法也不用多说了,应该都能看懂。

    --------------------------------------------------高端的旧色调和高斯模糊来啦--------------------------------------------------

    3、旧色调

    什么是旧色调,旧色调就是把一个图片的颜色变旧。暂时这样理解把。一会出来效果可以对比一下。

    在这里我们就用到了CIContext、CIImage、CIFilter了。这几个都是CoreImage框架中的类。其中起关键作用的还是CIFilter,他是滤镜。它的简单介绍如下:

    他是生产CIImage对象的,典型的就是,你可以通过它进行加工图片。让我们看一下操作旧色调的方法把。

    //操作旧色调的方法
    - (void)filterSepicTone {
        CIContext *context = [CIContext contextWithOptions:nil];   //创建CIContext对象,它规定了各种选项,包括颜色格式以及内容是否运行在CPU或是GPU上。
        CIImage *cImage = [CIImage imageWithCGImage:_imageView.image.CGImage];
        CIImage *result;
    
        //创建旧色滤镜
        sepiaTone= [CIFilter filterWithName:@"CISepiaTone"];
        
        [sepiaTone setValue:cImage forKey:@"inputImage"];
        
        double value = [_mySlider value];    //获取滑块的值。
        
        NSString *text = [[NSString alloc] initWithFormat:@"旧色调:%.2f",value];
        _myLabel.text =text;
        
        [sepiaTone setValue:[NSNumber numberWithFloat:value] forKey:@"inputIntensity"]; //设置旧色滤镜色调强度
    
        
        result = [sepiaTone valueForKey:@"outputImage"];   //取得滤镜之后的图像
        
        CGImageRef imageRef = [context createCGImage:result fromRect:CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height)];
        
        UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];   //
        _imageView.image = image;
        
        CFRelease(imageRef);    //释放CGImageRef
        flag = 0;
    }

    这里的_mySlider只是我的一个调值工具。先看看效果把。

    左边是原图,右边是旧色调的图。(这是我最喜欢的一个女明星。可惜因为因为白血病与2015年去世了。伤心。你永远活在我的心里。)

    简单看一代码:里面有一句很重要:

    //创建旧色滤镜
        sepiaTone= [CIFilter filterWithName:@"CISepiaTone"];

    创建旧色滤镜。其中的CISepiaTone是不能改变的。还有下边用到的inputImage/outputImage。要问为什么?应该是那个类中定义的属性吧。不能通过方法调用,只能通过KVC调用了。(不知道对不对,知道的大神请告诉我一下

    然后去设置滤镜的色调强度,然后通过outputImage将处理后的图片输出到result。再然后通过

        CGImageRef imageRef = [context createCGImage:result fromRect:CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height)];
        
        UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];   //

    获得了处理后的图片。

    --------------------------------------------------------说真的,具体我还不太理解,只能先记录了慢慢了解,因为刚刚接触CoreImage--------------------------------------------------------

    4、高斯模糊

    - (void)gaosiMohu {
        CIContext *context = [CIContext contextWithOptions:nil];
        CIImage *cImage = [CIImage imageWithCGImage:_imageView.image.CGImage];
        CIImage *result;
        
        gaussianBlur = [CIFilter filterWithName:@"CIGaussianBlur"];
        [gaussianBlur setValue:cImage forKey:@"inputImage"];
        double value = [_mySlider value];
        value = value*10;
        
        NSString *text = [[NSString alloc] initWithFormat:@"高斯模糊Radius:%.2f",value];
        _myLabel.text = text;
        
        [gaussianBlur setValue:[NSNumber numberWithFloat:value] forKey:@"inputRadius"];
        result = [gaussianBlur valueForKey:@"outputImage"];
    //    result = [gaussianBlur outputImage]
        CGImageRef imagRef = [context createCGImage:result fromRect:CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height)];
    
        UIImage *image = [[UIImage alloc] initWithCGImage:imagRef];
        _imageView.image = image;
        CFRelease(imagRef);
        flag = 1;
       
    }

    其实它和上边的旧色调差不多,只不过换了一下滤镜而已。,让我们看一下效果图:

    高斯模糊的结果如图所示。具体的实现我也不介绍了,等用到的时候在认真看看吧。

    5、接下来就是人脸识别了:

    人脸识别需要三个步骤:

     1、首先建立人脸的面纹数据库

     2、获取当前人脸面像图片

     3、用当前的面纹编码与数据库中的面纹编码进行比对。

     CIDetectorCoreImage中的一个特征识别滤镜。它可以找到图片中的人脸,但是是谁无法判断,需要数据库。要想识别可以看OpenCVFace.com。

    我们看一下实现代码:(据utide讲解我也没太深入,就不介绍了)

    - (IBAction)faceAction:(id)sender {
        CIContext *context = [CIContext contextWithOptions:nil];
        UIImage *imageInput = _inputImageView.image;
        CIImage *image = [CIImage imageWithCGImage:imageInput.CGImage];
        //设置识别参数; Accuracy代表的是经度。
        NSDictionary *parm = [NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy];   //设置识别率高点
        //声明一个CIDetector,并设定识别器类型
        CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:parm];
        
        //取得识别结果
        NSArray *detectResult = [faceDetector featuresInImage:image];
        
        UIView *resulteView = [[UIView alloc] initWithFrame:_inputImageView.frame];
    //    resulteView.backgroundColor = [UIColor redColor];
        [self.view addSubview:resulteView];
        for (CIFaceFeature *faceFeature in detectResult) {
            //脸部
            UIView *faceView = [[UIView alloc] initWithFrame:faceFeature.bounds];
            faceView.layer.borderWidth = 1;
            faceView.layer.borderColor = [UIColor orangeColor].CGColor;
            [resulteView addSubview:faceView];
            //左眼
            if (faceFeature.hasLeftEyePosition) {
                UIView *leftEyeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
                [leftEyeView setCenter:faceFeature.leftEyePosition];
                leftEyeView.layer.borderWidth = 1;
                leftEyeView.layer.borderColor = [UIColor redColor].CGColor;
                [resulteView addSubview:leftEyeView];
            }
            
            //右眼
                if (faceFeature.hasRightEyePosition) {
                    UIView *rightEyeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
                    [rightEyeView setCenter:faceFeature.rightEyePosition];
                    rightEyeView.layer.borderWidth = 1;
                    rightEyeView.layer.borderColor = [UIColor redColor].CGColor;
                    [resulteView addSubview:rightEyeView];
                }
                //嘴巴
                if (faceFeature.hasMouthPosition) {
                    UIView *mouseView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
                    [mouseView setCenter:faceFeature.mouthPosition];
                    mouseView.layer.borderWidth = 1;
                    mouseView.layer.borderColor = [UIColor redColor].CGColor;
                    [resulteView addSubview:mouseView];
                }
            
        }
        [resulteView setTransform:CGAffineTransformMakeScale(1, -1)];
        
        if ([detectResult count]>0) {
            CIImage *faceImage = [image imageByCroppingToRect:[[detectResult objectAtIndex:0] bounds]];
            
            UIImage *face = [UIImage imageWithCGImage:[context createCGImage:faceImage fromRect:faceImage.extent]];
            
            self.faceImageView.image = face;
            
            [self.faceButton setTitle:[NSString stringWithFormat:@"识别人脸数:%lu",(unsigned long)[detectResult count]] forState:UIControlStateNormal];
        }
    //    resulteView.backgroundColor = [UIColor redColor];
    }

    当我点击按钮时可以识别出人脸的位置,然后标记出脸,嘴和眼睛的位置。

    我这边没有处理好原图的标记,其实处理好的话可以刚好比对五官。

    --------------------------------------------------图像处理就讲这么多吧--------------------------------------------------

    说实话上面的东西平时用到的有的不是太多,所以我只是了解了一下,如果有用到的时候再深入学习一下。希望可以让大家对图像处理有所了解。

    --------------------------------------------------结束了--------------------------------------------------

     等一下,还有源码下载地址呢:http://pan.baidu.com/s/1eQg1qLG

     

  • 相关阅读:
    利用DTrace实时检测MySQl
    改进MySQL Order By Rand()的低效率
    RDS for MySQL查询缓存 (Query Cache) 的设置和使用
    RDS For MySQL 字符集相关说明
    RDS for MySQL 通过 mysqlbinlog 查看 binlog 乱码
    RDS for MySQL Mysqldump 常见问题和处理
    RDS for MySQL Online DDL 使用
    RDS MySQL 表上 Metadata lock 的产生和处理
    RDS for MySQL 如何使用 Percona Toolkit
    北京已成为投融资诈骗重灾区:存好骗子公司黑名单,谨防上当!
  • 原文地址:https://www.cnblogs.com/zhanggui/p/4743128.html
Copyright © 2011-2022 走看看