博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS之CoreImage图像处理框架
阅读量:4290 次
发布时间:2019-05-27

本文共 6742 字,大约阅读时间需要 22 分钟。

 

iOS为应用程序开发提供了许多可使用的框架,并构成IOS操作系统的层次,分为四层,从上到下依次为:Cocoa Touch Layer(触摸UI层)、MediaLayer(媒体层)、Core Services Layer(核心服务层)、Core OS Layer(核心OS层)。

 

 

 

 

 

 

 

 

========================================

 

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

Core Image 是苹果官方提供的图像处理框架,通过丰富的 built-in(内置)或自定义 Filter(过滤器)高效处理静态图片、动态图片或视频。开发者还可以通过构造 Filter 链或自定义 Core Image Kernel 来实现更丰富的效果。

在 WWDC20 中,苹果官方针对 Core Image 技术在以下三方面做了优化:Core Image 对视频 / 动图的支持、基于 Metal 构建 Core Image (CI) Kernel 以及 Core Image 的 Debug 支持。

 

CoreImage图像处理框架

 

 

主要分为三部分:

1)定义部分:CoreImage 何CoreImageDefines。见名思义,代表了CoreImage 这个框架和它的定义。

2)操作部分:

滤镜(CIFliter):CIFilter 产生一个CIImage。典型的,接受一到多的图片作为输入,经过一些过滤操作,产生指定输出的图片。

检测(CIDetector):CIDetector 检测处理图片的特性,如使用来检测图片中人脸的眼睛、嘴巴、等等。

特征(CIFeature):CIFeature 代表由 detector处理后产生的特征。 

3)图像部分:

画布(CIContext):画布类可被用与处理Quartz 2D 或者   OpenGL。可以用它来关联CoreImage类。如滤镜、颜色等渲染处理。

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

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

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

 

颜色(CIColor):   图片的关联与画布、图片像素颜色的处理。

向量(CIVector): 图片的坐标向量等几何方法处理。

图片(CIImage): 代表一个图像,可代表关联后输出的图像。 

 

 

查看所有内置滤镜

-(void)showAllFilters{  

NSArray *filterNames=[CIFilter filterNamesInCategory:kCICategoryBuiltIn]; 

  for (NSString *filterName in filterNames) {     

  CIFilter *filter=[CIFilter filterWithName:filterName];      

NSLog(@"\rfilter:%@\rattributes:%@",filterName,[filter attributes]); 

  }}

调用[CIFilter attributes]会返回filter详细信息,

 

***使用Core Image框架创建滤镜效果一般分为以下几步:

 

1.创建图像上下文CIContext

//创建基于CPU的图像上下文

//    NSNumber *number=[NSNumber numberWithBool:YES];

//    NSDictionary *option=[NSDictionary dictionaryWithObject:number forKey:kCIContextUseSoftwareRenderer];

//    _context=[CIContext contextWithOptions:option];

//使用GPU渲染,推荐,但注意GPU的CIContext无法跨应用访问,例如直接在UIImagePickerController的完成方法中调用上下文处理就会自动降级为CPU渲染,所以推荐现在完成方法中保存图像,然后在主程序中调用

_context=[CIContext contextWithOptions:nil];

//    EAGLContext *eaglContext=[[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES1];

//    _context=[CIContext contextWithEAGLContext:eaglContext];//OpenGL优化过的图像上下文

 

2.创建滤镜CIFilter

CIFilter用来表示CoreImage提供的各种滤镜。滤镜使用键-值来设置输入值,一旦这些值设置好,CIFilter就可以用来生成新的CIImage输出图像了。记住,这里的输出的图像不会进行实际的图像渲染,他只包含一个对输入图像的引用以及需要应用与数据上的滤镜链。IOS永远在最佳的时间选择渲染图像。

  1. CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"];   //设置滤镜
  2. [filter setValue:inputImage forKey:@"inputImage"];  //设置从输入的图片
  3. [filter setValue:[NSNumber numberWithFloat:0.8] forKey:@"inputIntensity"];  //设置滤镜参数

3.创建过滤原图片CIImage

         CIImage是CoreImage框架中最基本代表图像的对象,他不仅包含元图像数据,还包含作用在原图像上的滤镜链。这里我想特别强调的是CIImage和其他图像是不同的,在CIImage被CIContext渲染出来之前,他是依赖于滤镜链的,滤镜是不会更改CIImage中的图像数据。这个需要正确理解,不然会给你的程序造成错误。说到了CIImage的不同,就必须得提一下如何创建CIImage了,CIImage是不能直接有UIImage转化而来的,有以下几种创建CIImage的类方法:

 
 
  1. 1.CIImage*image=[CIImage imageWithContentsOfURL:myURL];  
  2. 2.CIImage*image=[CIImage imageWithData:myData];  
  3. 3.CIImage*image=[CIImage imageWithCGImage:myCgimage];  
  4. 4.CIImage*image=[CIImage imageWithCVPixelBuffer:CVBuffer]

 

4.调用CIFilter的setValue: forKey:方法为滤镜指定源图片

5.设置滤镜参数【可选】

6.取得输出图片显示或保存

  1. CIContext *context = [CIContext context];  
  2.   
  3. // Get outputImage from the last filter in chain  
  4.   CIImage *ciimage = [filter outputImage];  
  5.   
  6. // Render the CIImage into a CGImageRef  
  7.   CGImageRef cgimg = [context createCGImage:ciimage fromRect:[ciimage extent]];  
  8.   
  9. // Create a UIImage from the CGImageRef  
  10. UIImage *uiimage = [UIImage imageWithCGImage:cgimg scale:1.0f  
  11. orientation:ui_orientation([ciimage properties])];  
  12. CGImageRelease(cgimg);  
  13. // Use the UIImage in an UIImageView  
  14. imageView.image = uiimage;  

 

7.CIDetector和CIFeature

         CIDetector用来分析CIImage,得到CIFeature。每个CIDetector都要用一个探测器来初始化,这个类型高数探测器要在图像中寻找什么特征。

         当一个CIDetector分析一张图片时,返回一个探测到的CIFeature的数组,如果CIDetector 被初始化为寻找面孔,那么返回的数组会被填上CIFaceFeature对象,每个CIFaceFeature都包含一个面部的CGrect引用(按照图像的坐标系),以及检测到的面孔的左眼,右眼,嘴部位置的CGPoint;

 
  1. CIDetector *faceDetector = [CIDetector   
  2.                                     detectorOfType:CIDetectorTypeFace  
  3.                                     context:self.imageContext   
  4.                                     options:options];                
  5. NSArray *faces = [faceDetector featuresInImage:coreImage  
  6.                                                options:nil];  
  7. for(CIFaceFeature *face in faces){  
  8.             coreImage = [CIFilter filterWithName:@"CISourceOverCompositing"  
  9.                                    keysAndValues:kCIInputImageKey, [self makeBoxForFace:face],  
  10.                          kCIInputBackgroundImageKey, coreImage, nil].outputImage;  
  11.         }  
  12.  

======================

大家都知道在美图秀秀中有一个“增强”功能,利用它可以调整照片的饱和度、亮度、对比度,其实在Core Image中也有这样一款滤镜

 

1.

//创建基于CPU的图像上下文

//    NSNumber *number=[NSNumber numberWithBool:YES];

//    NSDictionary *option=[NSDictionary dictionaryWithObject:number forKey:kCIContextUseSoftwareRenderer];

//    _context=[CIContext contextWithOptions:option];

//使用GPU渲染,推荐,但注意GPU的CIContext无法跨应用访问,例如直接在UIImagePickerController的完成方法中调用上下文处理就会自动降级为CPU渲染,所以推荐现在完成方法中保存图像,然后在主程序中调用

_context=[CIContext contextWithOptions:nil];

//    EAGLContext *eaglContext=[[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES1];

//    _context=[CIContext contextWithEAGLContext:eaglContext];//OpenGL优化过的图像上下文

 

2._colorControlsFilter=[CIFilter filterWithName:@"CIColorControls"];//设置滤镜
3.[_colorControlsFilter setValue:_image forKey:@"inputImage"];//设置滤镜的输入图片

4.[_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputSaturation"];//设置滤镜参数(饱和度)

[_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputBrightness"];//设置滤镜参数(明度)

[_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputContrast"];//设置滤镜参数(对比度)

5.

CIImage *outputImage= [_colorControlsFilter outputImage];//取得输出图像

CGImageRef temp=[_context createCGImage:outputImage fromRect:[outputImage extent]];

self.imgView.image=[UIImage imageWithCGImage:temp];//转化为CGImage显示在界面中

CGImageRelease(temp);//释放CGImage对象

===============================

 

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);

 

=============================

使用中的注意事项:

1.为了防止阻塞主线程,用GCD异步执行滤镜与渲染操作,在获取渲染后的照片以后,返回主线程进行界面的更新。

2 不要重复应用滤镜,即使是同一个滤镜也不要应用两次,因为滤镜后输出照片包含滤镜链,在进行照片渲染是会将滤镜链效果叠加到原始数据上,这时会造成问题。比如,有一个CIImage,上面配置了强度为0.5的棕色滤镜,现在通过滑块将强度改为0.6,这个滤镜应该用在新的CIImage上,如果不是新的CIImage上,那么原来的CIImage中将包含强度为0.5和0.6的棕色滤镜,而我们只想0.6的棕色滤镜,这样就造成错误,这一点在编写程序的时候一定要切忌。

3 app中应用的滤镜太多,改变速率太快,如果是根据滑块来产生事件的话,一定要注意在使用滑条值前要首先判断更改的滤镜当前是否正在起作用,如果该滤镜正在生成新的渲染图片,则应该这次滑块的更新。这一点也是很重要的,弄的不好常常导致程序崩溃,出现内存泄露问题。

========================

 

你可能感兴趣的文章
安装完 MySQL 后必须调整的 10 项配置
查看>>
开发者必备的 12 个 JavaScript 库
查看>>
http错误码
查看>>
python 多线程
查看>>
sipp命令 各参数含义
查看>>
搜集的动植物分类、检索网站
查看>>
ffmpeg源码分析之媒体打开过程
查看>>
Ubuntu/centos/redhat/SUSE sipp安装(带rtp支持,3.5.1版本)
查看>>
周鸿祎:很多程序员聪明,但我一看就知道他不会成功
查看>>
编译程序遇到问题 relocation R_X86_64_32 against `.rodata' can not be used when making a shared object;
查看>>
Const指针 、 指向const的指针 、引用、指针
查看>>
GDB调试命令
查看>>
常见数据类型的字节数
查看>>
gcc/g++ 编译常见问题
查看>>
【设计模式】 工厂模式实例 C++ , 利用工厂模式写一个计算器
查看>>
opencv
查看>>
【图像处理】 一、OSTU分割
查看>>
Android常用的框架有哪些
查看>>
SSL 证书创建与部署
查看>>
学习搭建人工智能环境遇到的问题
查看>>