Core Image使用指南

简介

Core Image是一个图片处理及分析库,里面封装了非常易用的API,比如大量常用滤镜。因为它借助GPU或者CPU渲染,所以可以接近实时的速度处理静态图片和视频图片,图片可来自Core Graphics、Core Video以及I/O框架。

Core Image架构

功能列表

Core Image提供的能力包括:

  • 通过大量内置滤镜处理图片
  • 通过滤镜链自定义处理效果
  • 自动化图片增强
  • 特征检测,比如人脸、矩形、文字等
  • 创建自定义滤镜

基本概念

滤镜

一个滤镜在语义上表示某种能力,当作用在一张图片上时,可以经过某种变换从而得到另一张图片。

我们都知道,图片在计算机中是以像素为基本单位而保存的像素矩阵,通过图像处理单元GPU才能将其显示在屏幕上。在数学上,滤镜其实也是一个矩阵,也叫卷积核,通常比图片的像素矩阵维度小得多。在真正处理图片时,图片像素矩阵和卷积核做卷积运算,最终输出一个“新”图片。

滤镜的处理过程

滤镜链

顾名思义,滤镜链就是将多个滤镜链接在一起,前一个滤镜的输出作为下一个滤镜的输入,就像流水线一样,图片从第一个滤镜中进入,处理之后再进入下一个,一直到最后一个滤镜。通过这种方式,可以创建出更加如何需求的效果。

但实际上,Core Image的处理逻辑有点不同,它并不会让一张图片经过多次处理。为了性能考虑,Core Image会先将多个滤镜的卷积核合成为一个,然后一次性得出最终的结果。

图片处理

简单来说,图片处理就是将某张图片作用于某个滤镜的过程。

在Core Image中,图片为CIImage,滤镜为CIFilter,为滤镜设置参数要通过KVC实现。同时,还需要一个上下文对象CIContext,里面保存着所有相关的细节。因为这些细节非常多,所以最好在合适的时机创建一个可重复利用的CIContext对象。

单滤镜

最基本的用法就是只使用单个滤镜,如下所示。

- (void)blurImageWithRadius:(CGFloat)radius {    
    UIImage *originalImage = [UIImage imageNamed:@"blackboard.jpg"];
    CIImage *ciimage = [CIImage imageWithData: UIImageJPEGRepresentation(originalImage, .9)];
    
    CIFilter *gaussianBlur = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlur setValue:@(radius) forKey:@"inputRadius"];
    [gaussianBlur setValue:ciimage forKey:@"inputImage"];
    
    [self.processedImageView setImage:[UIImage imageWithCIImage:gaussianBlur.outputImage]];
}

在CoreImage中所有相关操作中只能使用CIImage这个格式,但是它并不能直接呈现给用户,因为CIImage只是一种用来生产图片的“配方”,其实就是一种操作流程,比如从URL读取图片文件,某个滤镜操作的输出等,只有在渲染或者输出时才会开始执行。总结下来,可以通过下面这些方法创建CIImage:

  • NSURL
  • NSData
  • UIImage
  • CGImageRef
  • CVImageBufferRef
  • CIImageProvider
- (void)createCIImageMethods {
    CIImage *ciimg;
    
    // 1. URL
    ciimg = [[CIImage alloc] initWithContentsOfURL:[NSURL URLWithString:@"some-url"]];
    
    // 2. bytes
    ciimg = [CIImage imageWithData:[NSData dataWithContentsOfFile:@"some-file-path"]];
    
    // 3. UIImage
    ciimg = [CIImage imageWithData:UIImageJPEGRepresentation([UIImage imageNamed:@"some-img-name"], .9)];
    ciimg = [CIImage imageWithData:UIImagePNGRepresentation([UIImage imageNamed:@"png-name"])];
    
    // 4. CGImageRef
    ciimg = [CIImage imageWithCGImage:[UIImage imageNamed:@"some-img"].CGImage];
    
    //...
}

滤镜分类

Core Image中有大量的滤镜,而且随着系统的不断升级,还在不断添加新的滤镜。系统将它们分为以下这些类别:

类别名称 说明 例子
CICategoryBlur 模糊 高斯模糊、降噪等
CICategoryColorAdjustment 颜色调整 色值、曝光度、明暗度调整,色温,色调曲线等
CICategoryColorEffect 颜色效果 色值转换、黑白效果、褪色等
CICategoryCompositeOperation 合成 叠加,颜色混合、差分、乘除,亮度、色度混合等等
CICategoryDistortionEffect 扭曲 隆起、线性隆起,德罗斯特效应,替换扭曲,玻璃扭曲等
CICategoryGenerator 生成器 生成条形码、二维码、星光、日光,纯色图片、随机图片等
CICategoryGeometryAdjustment 几何变换 仿射、透视变换,剪裁,兰索斯缩放
CICategoryGradient 渐变 高斯渐变、线性渐变、径向渐变等
CICategoryHalftoneEffect 网版效果 圆形网屏,点状网目板等
CICategoryReduction 不知道该如何翻译 区域平均值、最值,行、列平均值等
CICategorySharpen 锐化 亮度锐化、非锐化蒙版
CICategoryStylize 风格化 蒙版混合,软化边缘,喜剧效果,卷积,结晶,边缘检测等
CICategoryTileEffect 铺贴效果 以多种不同形式填充图案等
CICategoryTransition 过渡 条形过渡,溶剂过渡等

把这些功能组合在一起,基本可以实现一个Photoshop了。

滤镜链

前面说了,当要经过多个滤镜的处理时,CoreImage为了提高性能会将多个滤镜合成为一个,并在合适时机完成处理。

例如,如果分步处理,其流程如下:

分步处理滤镜链

但如果合成为一个Filter,则其流程如下:

将多个滤镜合成为一个
- (CIImage *)processWithImage:(CIImage *)image fileterName:(NSString *)name params:(NSDictionary *)params {
    CIFilter *filter = [CIFilter filterWithName:name];
    [filter setValue:image forKey:@"inputImage"];
    for (NSString *key in params.allKeys) {
        [filter setValue:params[key] forKey:key];
    }
    return filter.outputImage;
}

- (IBAction)startProcessWithChain:(UIButton *)sender {
    CIImage *blurImg, *bloomImg, *croppedImg;
    blurImg = [self processWithImage:self.inputImage
                         fileterName:@"CIGaussianBlur"
                              params:@{kCIInputRadiusKey: @(1.2)}];
    bloomImg = [self processWithImage:blurImg
                          fileterName:@"CIBloom"
                               params:@{kCIInputRadiusKey: @(8.0),
                                        kCIInputIntensityKey: @(1.0)}];
    croppedImg = [bloomImg imageByCroppingToRect:CGRectMake(50, 100, 300, 300)];
    
    [self.processedImageView setImage:[UIImage imageWithCIImage:croppedImg]];
}

常用操作

Core Image除过用CFilter来处理图片外,还可以通过一些预定义的方法直接处理图片,将更加简便。比如:

  • initWithColor: 纯色图片
  • imageByApplyingTransform: 给图片进行仿射变换
  • imageByCompositingOverImage: 叠加图片
  • imageByCroppingToRect: 剪裁图片
  • imageByClampingToRect: 扩展边界
  • imageByInsertingIntermediate 插值

检测

在图片识别处理中,如果要识别特定对象,一般都要先进行轮廓检测,然后再根据轮廓剪裁后识别物体,这样会更加高效准确。比如人脸、矩形等对象的识别。在Core Image中,提供了开箱即用的轮廓检测功能,其中只能进行三类操作:人脸、矩形、文字。下面看看人脸检测的使用方法:

- (void)detect:(UIBarButtonItem *)sender{
    CIImage *image = [CIImage imageWithData:UIImageJPEGRepresentation(self.image, .95)];
    NSLog(@"image size: %@", NSStringFromCGSize(self.image.size));
    CIContext *context = [CIContext context];
    NSDictionary *options = @{CIDetectorAccuracy: CIDetectorAccuracyHigh};
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:options];
    options = @{CIDetectorImageOrientation: [[image properties] valueForKey:(NSString *)kCGImagePropertyOrientation]};
    
    NSArray *features = [detector featuresInImage:image options:options];
    
    for (CIFaceFeature *feature in features) {
        NSLog(@"face bounds: %@", NSStringFromCGRect(feature.bounds));
        [self drawBorderWithFaceFeature:feature];
    }
}

- (void)drawBorderWithFaceFeature:(CIFaceFeature *)feature{
    CGRect frame = [self convertFaceBoundsToView:feature.bounds];
    NSLog(@"converted face bounds: %@", NSStringFromCGRect(frame));

    UILabel *label = [[UILabel alloc] initWithFrame:frame];
    label.backgroundColor = [UIColor clearColor];
    label.layer.borderColor = [UIColor redColor].CGColor;
    label.layer.borderWidth = 2.f;
    [self.imageView addSubview:label];
}

- (CGRect)convertFaceBoundsToView:(CGRect)bounds{
    CGFloat ratio = CGRectGetWidth(self.imageView.bounds)/self.image.size.width;
    return CGRectMake(CGRectGetMinX(bounds)*ratio, CGRectGetMinY(bounds)*ratio, CGRectGetWidth(bounds)*ratio, CGRectGetHeight(bounds)*ratio);
}

经过使用发现,只要当图片中含有少量人时结果比较准确,当图片清晰度降低、并且人较多时结果不一定准确。

注意点

为了提高应用程序的性能,在使用Core Image时尽可能注意以下细节:

  • 不要每次都创建CIContext,应尽可能复用;
  • 如果没有必要,避免动画和颜色空间管理;
  • 尽可能使用更小的图片、简单的滤镜;
  • 确保不要超过CPU或者GPU的限度等。

参考

  • Apple官方文档
  • CoreImage滤镜文档
  • ObjC中国期刊21-6

你可能感兴趣的:(Core Image使用指南)