CoreImage

来源:互联网 发布:淘宝钻位展示 编辑:程序博客网 时间:2024/05/21 18:40

1.coreImage的介绍

         coreImage是IOS5中新加入的一个Objective-c的框架,提供了强大高效的图像处理功能,用来对基于像素的图像进行操作与分析。IOS提供了很多强大的滤镜(Filter),其中IOS5中有48种,而到了最新的IOS6 Filter已经增加到了93种之多,并且这一数字会继续增加。这些Filter提供了各种各样的效果,并且还可以通过滤镜链将各种效果的Filter叠加起来,形成强大的自定义效果,如果你对该效果很满意,还可以子类化滤镜。

        

2.coreImage框架中的对象

 

2.1 CIImage

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

[cpp] view plaincopy
  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];  

2.2 CIFilter

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

         CIFilter提供了一个简单的方法查询可用的滤镜种类:[CIFilterfilterNamesInCategory:kCICategoryBuiltIn];//搜索属于 kCICategoryBuiltIn类别的所有滤镜名字,返回一个数组;

[CIFilterfilterNamesInCategories];//搜索所有可用的滤镜名称;

调用[CIFilter attributes]会返回filter详细信息,下面我们以一个具体列子来看看他返回的信息。

      下面是我程序返回的一个叫做CISepiaTone滤镜返回的详细信息:

[cpp] view plaincopy
  1. 2012-09-18 16:17:09.155 SZFYKJHomeWorkVersion1[2836:f803] {  
  2.     CIAttributeFilterCategories =     (//滤镜所示种类,通常一个滤镜可以属于几种  
  3.         CICategoryColorEffect,       //总类,这只是根据滤镜效果,作用来分类的  
  4.         CICategoryVideo,             //可以用种类名来搜索Fileter;  
  5.         CICategoryInterlaced,  
  6.         CICategoryNonSquarePixels,  
  7.         CICategoryStillImage,  
  8.         CICategoryBuiltIn  
  9.     );  
  10.     CIAttributeFilterDisplayName = "Sepia Tone";  
  11.     CIAttributeFilterName = CISepiaTone;        //滤镜的名称,通过该名称来  
  12.                                     //调用滤镜,具体见下面实例  
  13.   
  14.  inputImage =     {                 //滤镜使用需要输入的参数,该  
  15.         CIAttributeClass = CIImage;     //参数类型为CIImage。  
  16.         CIAttributeType = CIAttributeTypeImage;  
  17.     };  
  18.     inputIntensity =     {              //输入强度,参数的名称  
  19.         CIAttributeClass = NSNumber;        //类型  
  20.         CIAttributeDefault = 1;         //默认值  
  21.         CIAttributeIdentity = 0;              
  22.         CIAttributeMax = 1;             //最大值  
  23.         CIAttributeMin = 0;             //最小值  
  24.         CIAttributeSliderMax = 1;  
  25.         CIAttributeSliderMin = 0;  
  26.         CIAttributeType = CIAttributeTypeScalar;  
  27.     };  
  28. }  
  29. 程序中使用CISepiaTone的代码为:CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"];   
  30. [filter setValue:inputImage forKey:@"inputImage"];  
  31. [filter setValue:[NSNumber numberWithFloat:0.8] forKey:@"inputIntensity"];  

大家可以 [CIFilterfilterNamesInCategories]返回所有的滤镜,并查看他们的参数来熟悉各个滤镜的使用方法。

 

2.3 CIContext

      CIContext用来渲染CIImage,将作用在CIImage上的滤镜链应用到原始的图片数据中。CIContext可以是基于CPU的,也可以是基于GPU的,这两种渲染的区别是:使用CPU渲染的IOS会采用GCD来对图像进行渲染,这保证了CPU渲染在大部分情况下更可靠,比CPU渲染更容易使用,他可以在后台实现渲染过程;而GPU渲染方式使用OpenGL ES2.0来渲染图像,这种方式CPU完全没有负担,应用程序的运行循环不会受到图像渲染的影响,而且他渲染比CPU渲染更快但是GPU渲染无法在后台运行。

      对于如何选择更好的渲染方式,我认为应该视具体情况而定:对于复杂的图像滤镜使用GPU更好,但是如果在处理视频并保存文件,或保存照片到照片库中时为避免程序退出对图片保存造成影响,这时应该使用CPU进行渲染。默认情况是用CPU渲染的。
[cpp] view plaincopy
  1. CIContext *context = [CIContext contextWithOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];//CPU渲染  

渲染后的图片使用:

1.imageView中使用:

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

2.将图片保存到photoLibrary

[cpp] view plaincopy
  1. // Create a CGImage from the CIImage  
  2.  CIImage *outputImage = [filter outputImage];  
  3.  CGImageRef cgimage = [cpu_context createCGImage:outputImage  
  4.                              fromRect:[outputImage extent]];  
  5.  // Add the CGImage to the photo library  
  6.  ALAssetsLibrary *library = [ALAssetsLibrary new];  
  7.  [library writeImageToSavedPhotosAlbum:cgimage  
  8.                               metadata:[outputImage properties]  
  9.       completionBlock:^(NSURL *assetURL NSError *error) {  
  10.         CGImageRelease(cgimg);  
  11. }];  

2.4 CIDetector和CIFeature

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

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

[cpp] view plaincopy
  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.         }  

3 注意事项

 

1 CoreImage在IOS上有很高的效率,但是滤镜和渲染操作也会对主线程造成影响。应该将CoreImage滤镜渲染操作放在后台线程执行,当这些操作介绍后在返回主线程进行界面的更新。

[cpp] view plaincopy
  1. dispatch_async(  
  2.        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),  
  3.        ^(void){  
  4.              
  5.            //CGImageRef cgImage = [self autoAdjustImage];  
  6.            NSArray *filters;  
  7.            // Create Core Image  
  8.            CGImageRef cgImg = self.imageView.image.CGImage;  
  9.            CIImage *coreImage = [CIImage imageWithCGImage:cgImg];  
  10.              
  11.            // Iterate through all of our filters and apply  
  12.            // them to the CIImage  
  13.            for(CIFilter *filter in filters){  
  14.                [filter setValue:coreImage forKey:kCIInputImageKey];  
  15.                coreImage = filter.outputImage;  
  16.            }  
  17.              
  18.            // Create a new CGImageRef by rendering through CIContext  
  19.            // This won't slow down main thread since we're in a background  
  20.            // dispatch queue  
  21.            CGImageRef newImg = [self.imageContext createCGImage:coreImage   
  22.                                                        fromRect:[coreImage extent]];  
  23.              
  24.            dispatch_async(dispatch_get_main_queue(), ^(void){  
  25.                // Update our image view on the main thread  
  26.                // You can also perform any other UI updates needed  
  27.                // here such as hidding activity spinners  
  28.                self.imageView.image = [UIImage imageWithCGImage:newImg];  
  29.                [self.adjustSpinner stopAnimating];  
  30.                [sender setEnabled:YES];  
  31.            });  
  32.        });  

上面这段代码,就是为了防止阻塞主线程,用GCD异步执行滤镜与渲染操作,在获取渲染后的照片以后,返回主线程进行界面的更新。(完整的程序见本文末连接)

 

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

 

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

 

这些问题常常会导致程序的崩溃.

 

4 总结

CoreImage处理图像的流程:

1:创建一个新的CIImage;

2:创建一个行的CIFIlter,并通过键-值设置各种输入值,这些值有些是有默认值的,有些没有默认值,需要编程者的设置;

3:冲CIFilter中生成输出图像,如果存在滤镜链则将输出图像作为输入参数传入到下一个滤镜,跳回步骤2继续进行,如果到达滤镜末,则调用CIContext渲染CIImage对象。这个context可以是基于CPU或GPU的,基于CPU的产出CGImageRef对象,基于GPU的调用OpenGL ES在屏幕上画出结果,默认是基于CPU的。

 

在使用CoreImage时,一定要记住CIImage对象在开始时不会操作图像数据,知道使用CIContext渲染图片是才会这么做。还要记住最好在后台执行图像处理的操作,然后在主线程中修改界面。


大家有机会可以参考一下IOS5核心框架中的CoreImage章节和AVFoundation章节,下面在贴一个书本中的列子的连接,我认为很有助理解。http://ioscoreframeworks.com/download/

CIAdditionCompositing     //影像合成

CIAffineTransform           //仿射变换

CICheckerboardGenerator       //棋盘发生器

CIColorBlendMode              //CIColor混合模式

CIColorBurnBlendMode          //CIColor燃烧混合模式

CIColorControls 

CIColorCube                   //立方体

CIColorDodgeBlendMode         //CIColor避免混合模式

CIColorInvert                 //CIColor反相

CIColorMatrix                 //CIColor矩阵

CIColorMonochrome             //黑白照

CIConstantColorGenerator      //恒定颜色发生器

CICrop                        //裁剪

CIDarkenBlendMode             //亮度混合模式

CIDifferenceBlendMode         //差分混合模式

CIExclusionBlendMode          //互斥混合模式

CIExposureAdjust              //曝光调节

CIFalseColor                  //伪造颜色

CIGammaAdjust                 //灰度系数调节

CIGaussianGradient            //高斯梯度

CIHardLightBlendMode          //强光混合模式

CIHighlightShadowAdjust       //高亮阴影调节

CIHueAdjust                   //饱和度调节

CIHueBlendMode                //饱和度混合模式

CILightenBlendMode            

CILinearGradient              //线性梯度

CILuminosityBlendMode         //亮度混合模式

CIMaximumCompositing          //最大合成

CIMinimumCompositing          //最小合成

CIMultiplyBlendMode           //多层混合模式

CIMultiplyCompositing         //多层合成

CIOverlayBlendMode            //覆盖叠加混合模式

CIRadialGradient              //半径梯度

CISaturationBlendMode         //饱和度混合模式

CIScreenBlendMode             //全屏混合模式

CISepiaTone                   //棕黑色调

CISoftLightBlendMode          //弱光混合模式

CISourceAtopCompositing       

CISourceInCompositing 

CISourceOutCompositing 

CISourceOverCompositing 

CIStraightenFilter            //拉直过滤器

CIStripesGenerator            //条纹发生器

CITemperatureAndTint          //色温

CIToneCurve                   //色调曲线

CIVibrance                    //振动

CIVignette                    //印花

CIWhitePointAdjust            //白平衡调节

CIAreaAverage   - 返回一个单像素图像,其中包含一块颜色区内的平均颜色。

CIAreaMaximum   - 返回一个单像素图像,其中包含一块颜色区内最大的颜色成分。

CIAreaMaximumAlpha  - 返回一个单像素图像,其中包含颜色区中最大透明度的颜色矢量。

CIBoxBlur- 在一个矩形内使得图像模糊化。

CICircularWrap  - 用一个透明的圆圈环绕图像。

CICMYKHalftone   - 创建一个颜色,使得源图像呈半色调,在白色页面中使用使用青色,品红色,黄色和墨色。

CIColumnAverage - 返回一个高为1像素的图像,包含每个扫描列的平均颜色。

CIComicEffect - 像漫画书一样勾勒(图像)边缘,并应用半色调效果。

CIConvolution7X7  - 用一个7x7旋转矩阵来调整像素值。

CICrystallize - 通过汇集源像素的颜色值,创建多边形色块。

CIDepthOfField - 模拟一个场景深入的效果。

CIDiscBlur - 在一个圆盘形状内模糊化图像。

CIDisplacementDistortion - 将第二图像的灰度值应用到第一图像。

CIDroste - 用类似M.C.埃舍尔绘图方式递归地绘制图像的一部分。

CIEdges- 用颜色显示图像的边缘。

CIEdgeWork  - 产生一个黑白风格的类似木块切口的图像。

CIGlassLozenge - 创建一个菱形滤镜,并扭曲滤镜位置的图像。

CIHeightFieldFromMask- 产生一个连续的三维物体,一个阁楼形的灰场。

CIHexagonalPixellate - 用所替换的像素映射彩色六边形的图像。

CIKaleidoscope- 从源图像中通过将12路对称,产生一个五颜六色的图象

CILenticularHaloGenerator - 模拟闪光灯效果。

CILineOverlay - 创建草图,用黑色勾勒出图像的边缘。

CIMedianFilter- 计算一组邻近像素的平均数,然后用平均数替代每个像素的值。

CINoiseReduction - 通过降低噪声的限定值来降低噪音。

CIOpTile - 先分割图像,施加一些指定的缩放和旋转,然后拼接图像,形成的艺术化的表现。

CIPageCurlTransition - 使用翻页效果从一个图像转换到另一个图像,翻卷后显示新的图像。

CIPageCurlWithShadowTransition- 使用翻页效果从一个图像转换到另一个图像,翻卷后显示新的图像。

CIParallelogramTile - 展示一个在平行四边形内的图像。

CIPointillize - 呈现一个pointillistic风格的源图像。

CIRippleTransition - 图像创建一个圆形波从中心点向外扩大,在波形里显示新图像。

CIRowAverage- 返回1个像素高的图像,其中包含每行扫描的平均颜色。

CIShadedMaterial- 从一个高度场产生一个阴影图像。

CISpotColor- 用色点替换颜色范围。

CISpotLight- 图像使用一个方向聚光灯效果呈现。

CIStretchCrop- 图像通过拉伸和或裁剪以适合目标尺寸。

CISunbeamsGenerator - 图像呈现阳光照射的效果。

CITorusLensDistortion- 创建环形滤镜,并扭曲透镜位置的图像。

CITriangleTile- 截取图像的一个三角形部分映射到一个三角形区域,然后平铺展示.

有关每个滤镜的更多信息,请访问苹果的Apple's Core Image Filter Reference


0 0
原创粉丝点击