CoreImage的使用及常见滤镜工具(一)


概述:

CoreImage是一个图像框架,它基于OpenGL顶层创建,底层则用着色器来处理图像,这意味着它利用了GPU基于硬件加速来处理图像。CoreImage中有很多滤镜,它们能够一次给予一张图像或者视频帧多种视觉效果。而且滤镜可以连接起来组成一个滤镜链,把滤镜效果叠加起来处理图像。

CoreImage框架最早出现于iOS5,iOS6也对这个框架进行了扩展,这篇博客的Demo是基于iOS7的。


CoreImage框架最常用的类:


* CIImage

保存图像数据的类,可以通过UIImage,图像文件或者像素数据来创建,包括未处理的像素数据如:

- imageWithCVPixelBuffer:

- imageWithData:

方法等等。

也可以通过图像数据类比如UIImage,CGImageRef等等。


* CIFilter

滤镜类,这个框架中对图片属性进行细节处理的类。它对所有的像素进行操作,用一些键-值设置来决定具体操作的程度。


* CIContext

上下文类,如CoreGraphics以及CoreData中的上下文用于处理绘制渲染以及处理托管对象一样,CoreImage的上下文也是实现对图像处理的具体对象。

这里需要注意的是在Context创建的时候,我们需要给它设定为是基于GPU还是CPU。(这里使用GPU)

基于GPU的话,处理速度更快,因为利用了GPU硬件的并行优势。但是GPU受限于硬件纹理尺寸,而且如果你的程序在后台继续处理和保存图片的话,那么需要使用CPU,因为当app切换到后台状态时GPU处理会被打断。


简单使用:

简介完三个类之后,介绍下简单使用步骤:

实例化一个CIImage,

创建一个你需要的CIFilter滤镜并给滤镜设置属性,

创建CIContext上下文来初始化一个CGImageRef对象,

再将其赋给UIImage对象进行显示。


这篇文章采用工具类的方法来进行滤镜处理。


下面是一个简单的棕色滤镜的使用:

    NSURL *url = [NSURL fileURLWithPath:path];
    CIImage *coreImage = [CIImage imageWithContentsOfURL:url];
    
    CIFilter *sepiaFilter = [CIFilter filterWithName:kSepiaFilterName];
    [sepiaFilter setValue:coreImage forKey:kCIInputImageKey];
    [sepiaFilter setValue:@(intensity) forKey:@"inputIntensity"];
    
    CIImage *output = [sepiaFilter outputImage];
    
    CGImageRef cgimg = [_context createCGImage:output fromRect:[output extent]];
    
    UIImage *image = [UIImage imageWithCGImage:cgimg];
    
    CGImageRelease(cgimg);


传入一个图片的path,生成CIImage对象,然后通过SepiaTone滤镜经过处理,强度自定义即可(范围:0~1之间)。

UIImage不是有个类方法直接通过CIImage对象生成UIImage吗?但是那样每一次都要创建一个CIContext对象,对于频繁调用时会很消耗性能。

所以,这里的context在工具类初始化的时候已经初始化了。

        //initialize contexts
        _glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        if (!_glContext) {
            NSLog(@"Failed to create ES context");
        }
        _context = [CIContext contextWithEAGLContext:_glContext];


这里使用GPU来进行图片渲染的处理。上面已经提到过,这样速度会更快些。

如果想用CPU,则可以调用[CIContext contextWithOptions:]传入一个字典,将CPU作为渲染键值。


工具类里提供了4个方法能够快速的使用该滤镜渲染。


下面继续介绍其他的滤镜

仿射变换滤镜

还是通过两种传入途径,一个路径,一个图片


- (UIImage *)transImageWithCIImage:(CIImage *)image transform:(CGAffineTransform)trans
{
    if (!image) return nil;
    
    CIFilter *transFilter = [CIFilter filterWithName:@"CIAffineTransform"];
    [transFilter setValue:image forKey:kCIInputImageKey];
    [transFilter setValue:[NSValue valueWithCGAffineTransform:trans] forKey:@"inputTransform"];
    CIImage *output = transFilter.outputImage;
    
    CGImageRef cgimg = [_context createCGImage:output fromRect:[output extent]];
    UIImage *uiimage = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    
    return uiimage;
}

- (UIImage *)transImageWithPath:(NSString *)path transform:(CGAffineTransform)trans
{
    NSURL *url = [NSURL fileURLWithPath:path];
    CIImage *ciimg = [CIImage imageWithContentsOfURL:url];
    
    return [self transImageWithCIImage:ciimg transform:trans];
}


现在我们已经使用了两个滤镜。那么可不可以把两个滤镜连起来用呢?

答案是可以的,这就是一般所说的滤镜链,我们可以获得上一个滤镜的输出图片作为下一个滤镜的输入,然后进行渲染处理,而处理的次数怎么处理则我们由我们自己需求而随意更改。


于是我把上面两个滤镜连接起来使用。

CIImage *ciimg = [_tool transOutputWithPath:path transform:CGAffineTransformMakeRotation(M_PI)];
_image = [_tool sepiaImageWithCIImage:ciimg intensity:1.0];

_imageView.image = _image;

经过两个工具方法处理后,我们得到了经过滤镜链处理的图像,如下:




混合滤镜


如果你的图片的透明通道为YES想在下方添加一个底层的图片的话,可以用CISourceAtopCompositing滤镜。


- (UIImage *)atopCompsitingWithTop:(UIImage *)top andBack:(UIImage *)back
{
    if (!top || !back) return nil;
    
    CIImage *topInput = [CIImage imageWithCGImage:top.CGImage];
    CIImage *bottom = [CIImage imageWithCGImage:back.CGImage];
    
    CIFilter *filter = [CIFilter filterWithName:@"CISourceAtopCompositing"];
    [filter setValue:topInput forKey:kCIInputImageKey];
    [filter setValue:bottom forKey:@"inputBackgroundImage"];
    
    return [self imageWithCoreImage:[filter outputImage]];
}

- (UIImage *)imageWithCoreImage:(CIImage *)image
{
    CGImageRef cgimg = [_context createCGImage:image fromRect:[image extent]];
    UIImage *uiimage = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    
    return uiimage;
}


拉直滤镜


如果你的图片由于拍摄时稍微倾斜或者抖动,可以使用这个滤镜并传入一个旋转角度参数来修正图片。


- (UIImage *)straightenImageWithImage:(UIImage *)image andAngle:(CGFloat)angle
{
    if (!image || angle < 0) return nil;
    
    CIImage *input = [CIImage imageWithCGImage:image.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIStraightenFilter"];
    [filter setValue:input forKey:kCIInputImageKey];
    [filter setValue:@(angle) forKey:kCIInputAngleKey];
    
    return [self imageWithCoreImage:[filter outputImage]];
}


色彩控制滤镜


可以传入颜色的亮度,对比度和饱和度来给图片过滤。


- (UIImage *)colorControlWithImage:(UIImage *)image brightness:(CGFloat)bright contrast:(CGFloat)contrast saturation:(CGFloat)saturation
{
    if (!image) return nil;
    
    CIImage *input = [CIImage imageWithCGImage:image.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:input forKey:kCIInputImageKey];
    [filter setValue:@(bright) forKey:@"inputBrightness"];
    [filter setValue:@(contrast) forKey:@"inputContrast"];
    [filter setValue:@(saturation) forKey:@"inputSaturation"];
    
    return [self imageWithCoreImage:[filter outputImage]];
}


反转颜色滤镜


给图片使用反色。


- (UIImage *)colorInvertWithImage:(UIImage *)image
{
    if (!image) return nil;
    
    CIImage *input = [CIImage imageWithCGImage:image.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"];
    [filter setValue:input forKey:kCIInputImageKey];
    
    return [self imageWithCoreImage:[filter outputImage]];
}



面部检测初步


CoreImage类中提供了一个CIDectetor类来给我们提供两种类型的检测器。

其中一种即是面部检测。


- (BOOL)hasFace:(UIImage *)image
{
    NSArray *features = [self featuresWithImage:image];
    return features.count?YES:NO;
}

- (NSArray *)featuresWithImage:(UIImage *)image
{
    CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace
                                                  context:nil
                                                  options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
    CIImage *ciimg = [CIImage imageWithCGImage:image.CGImage];
    NSArray *features = [faceDetector featuresInImage:ciimg];
    return features;
}

创建检测器时传入Type参数指定为面部即可,options中可以传入一个检测精度。


下面是返回图片中所有左眼位置、右眼位置以及嘴部位置的方法。


左眼:

- (NSArray *)leftEyePositionsWithImage:(UIImage *)image
{
    if (![self hasFace:image]) return nil;
    
    NSArray *features = [self featuresWithImage:image];
    NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasLeftEyePosition) [arrM addObject:[NSValue valueWithCGPoint:f.leftEyePosition]];
    }
    return arrM;
}

右眼:

- (NSArray *)rightEyePositionsWithImage:(UIImage *)image
{
    if (![self hasFace:image]) return nil;
    
    NSArray *features = [self featuresWithImage:image];
    NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasRightEyePosition) [arrM addObject:[NSValue valueWithCGPoint:f.rightEyePosition]];
    }
    return arrM;
}

嘴部:

- (NSArray *)mouthPositionsWithImage:(UIImage *)image
{
    if (![self hasFace:image]) return nil;
    
    NSArray *features = [self featuresWithImage:image];
    NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasMouthPosition) [arrM addObject:[NSValue valueWithCGPoint:f.mouthPosition]];
    }
    return arrM;
}


这篇博客介绍了CoreImage出现以来最基本的几个滤镜。

之后会对这个滤镜处理工具继续进行扩充。


Demo下载

CSDN资源:点击打开链接

GitHub仓库:点击打开链接



以上就是本篇博客的全部内容,欢迎指正和交流~转载注明出处~


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
如果不想使用CoreImage框架,也可以使用ZBarSDK来获取图片中二维码的定位。 1. 导入ZBarSDK: 在项目中导入ZBarSDK,并在需要使用的文件中引入头文件: ``` #import "ZBarSDK.h" ``` 2. 加载图片: ``` UIImage *image = [UIImage imageNamed:@"image.png"]; CGImageRef imageRef = image.CGImage; ``` 3. 创建ZBarImageScanner并设置识别类型: ``` ZBarImageScanner *scanner = [[ZBarImageScanner alloc] init]; [scanner setSymbology: ZBAR_QRCODE config: ZBAR_CFG_ENABLE to: 1]; ``` 4. 将图片转换为ZBarImage对象: ``` ZBarImage *zbarImage = [[ZBarImage alloc] initWithCGImage:imageRef]; ``` 5. 扫描二维码: ``` [scanner scanImage:zbarImage]; ``` 6. 遍历扫描结果,获取二维码定位: ``` for (ZBarSymbol *symbol in scanner.results) { NSArray *corners = symbol.bounds; // 获取定位四个角的坐标 // 在图像上绘制定位 UIGraphicsBeginImageContext(imageSize); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor); CGContextSetLineWidth(context, 2.0); CGContextMoveToPoint(context, corners[0].x, corners[0].y); CGContextAddLineToPoint(context, corners[1].x, corners[1].y); CGContextAddLineToPoint(context, corners[2].x, corners[2].y); CGContextAddLineToPoint(context, corners[3].x, corners[3].y); CGContextAddLineToPoint(context, corners[0].x, corners[0].y); CGContextStrokePath(context); UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } ``` 这样就可以在原图上绘制出二维码的定位了。需要注意的是,ZBarSDK是第三方框架,需要先在官网注册并获取授权才能使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值