Core Image

概念

Core Image:一个OS X和iOS的图像处理框架,Core Image框架最早出现于iOS5,iOS6对这个框架进行了扩展。

滤镜:是一个对象,有很多输入和输出,并执行一些变换。例如,模糊滤镜可能需要输入图像和一个模糊半径来产生适当的模糊后的输出图像。

滤镜链:是一个链接在一起的滤镜网络,使得一个滤镜的输出可以是另一个滤镜的输入。当多个滤镜连接成一个滤镜链,Core Image便把滤镜内核串在一起来构建一个可在GPU上运行的高效程序。通常情况下,直到滤镜图表的最后一个滤镜的输出被请求之前都不会发生分配或处理。滤镜链相当于生成一个改进的滤镜,从而一次性的处理图像达到目标效果,而不是对同一个图像顺序地多次应用单个滤镜。为了完成工作,Core Image需要一个称为上下文的对象。

上下文(context):这个上下文是框架真正工作的地方,它需要分配必要的内存,并编译和运行滤镜内核来执行图像处理。在上下文创建的时候,我们需要给它设定为是基于GPU还是CPU。基于GPU的话,处理速度更快,因为利用了GPU硬件的并行优势。但是GPU受限于硬件纹理尺寸,而且如果你的程序在后台继续处理和保存图片的话,就需要使用CPU,因为当app切换到后台状态时GPU处理会被打断。建立一个上下文是非常昂贵的,所以会创建一个反复使用的上下文。

查询可用的滤镜样式

NSArray *filterNames = [CIFilter filterNamesInCategory:kCICategoryBuiltIn];

新建一个滤镜

CIFilter *vignetteFilter = [CIFilter filterWithName:@"CIVignette"];

设置滤镜参数,采用KVC方式

[vignetteFilter setValue:@(1.75) forKey:@"inputRadius"];
[vignetteFilter setValue:@(1.0) forKey:@"inputIntensity"];

也可以在新建滤镜时带入参数

CIFilter *vignetteFilter = [CIFilter filterWithName:@"CIVignette" withInputParameters:@{@"inputRadius":@(1.75), @"inputIntensity":@(1.0)}];

为了查看各种输入参数和输出参数,可以获取滤镜的inputKeys属性和outputKeys属性,并且,通过获取滤镜的attributes属性,可以查看每个输入参数的详细信息

NSArray *inputKeys = vignetteFilter.inputKeys;
NSArray *outputKeys = vignetteFilter.outputKeys;
NSDictionary *attr = vignetteFilter.attributes; 

vignetteFilter的inputKeys属性如下,可以看出除了inputImage,还有两个可以设置的参数


inputKeys

vignetteFilter的outputKeys属性如下,仅含有outputImage


outputKeys

vignetteFilter的attributes属性如下,可以发现其中含有inputKeys中所有的对应项
attr

其中inputRadius的展开如下,其中包含了该参数的数据类型、默认值、最大最小值等


item of attr

创建上下文

// 基于CPU
CIContext *context = [CIContext contextWithOption:@{kCIContextUseSoftwareRenderer:@YES}];
// 基于GPU
CIContext *context = [CIContext contextWithOption:nil];
// 使用OpenGL提高性能
EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
CIContext *context = [CIContext contextWithEAGLContext:eaglContext];

实战

  • UIImage和CIImage之间的转化
    将 UIImage 转化成 CIImage 需要借助中间的 CGImage
UIImage *uiImage = [UIImage imageNamed:@"dog.png"]; 
// 错误的方式,会得到nil
CIImage *ciImage1 = uiImage.CIImage;
// 正确的方式
CIImage *ciImage2 = [[CIImage alloc] initWithCGImage:uiImage.CGImage]; 

将 CIImage 转化成 UIImage 也需要借助中间的 CGImage
直接从一个 CIImage 创建 UIImage 也是可以的,但这种方法存在缺陷:如果你试图在一个 UIImageView 上显示这样的图像,其 contentMode 属性将被忽略;使用过渡的 CGImage 则需要一个额外的步骤,但可以修补这一缺陷

// 不建议使用的方式,生产默认的临时的上下文,具有缺陷
UIImage *image1 = [[UIImage alloc] initWithCIImage:ciImage];
// 建议使用的方式
UIImage *imagei2 = [self makeUIImageFromCIImage:ciImage];
// makeUIImageFromCIImage实现
 - (UIImage *)makeUIImageFromCIImage:(CIImage *)ciImage 
{   
EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
CIContext *context = [CIContext contextWithEAGLContext:eaglContext];   
CGImageRef cgImage = [context createCGImage:ciImage fromRect:[ciImage extent]];
UIImage* uiImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);   
return uiImage;
}

上面代码中,每次调用makeUIImageFromCIImage方法都会生成一个临时的上下文(CIContext),开销很大。可以保存为当前类的属性,进行复用

_glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 
if (!_glContext) { 
NSLog(@"Failed to create ES context"); 
} 
_context = [CIContext contextWithEAGLContext:_glContext];    
  • 自己定制一个滤镜链
 - (UIImage *)makeFilter:(UIImage *)originImage
{
// 根据传入的UIImage获得CIImage
CIImage *inputImage = [[CIImage alloc] initWithCGImage:originImage.CGImage]; 
// 第一个滤镜,黑白滤镜
CIColor *sepiaColor = [CIColor colorWithRed:0.76 green:0.65 blue:0.54];  
CIFilter *monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome" withInputParameters:@{@"inpu Color":sepiaColor, @"inputIntensity":@(1.0)}];  
[monochromeFilter setValue:inputImage forKey:@"inputImage"];
// 第二个滤镜,暗角滤镜   
CIFilter *vignetteFilter = [CIFilter filterWithName:@"CIVignette" withInputParameters:@{@"inputRadius":@(1.75), @"inputIntensity":@(1.0)}];  
[vignetteFilter setValue:monochromeFilter.outputImage forKey:@"inputImage"];
// 返回最后一个滤镜输出的CIImage转化成的UIImage    
return [self makeUIImageFromCIImage:vignetteFilter.outputImage];
}

效果图如下


滤镜处理前

滤镜处理后

人脸识别

判断图片中有没有人脸

 - (BOOL)hasFace:(UIImage *)image
{  
NSArray *features = [self featuresWithImage:image];
return !!features.count;
}
 - (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;
}

获取图片中所有左眼位置、右眼位置以及嘴部位置

// 获取图像中所有的左眼位置
// (hasLeftEyePosition, leftEyePosition) : (特征中是否有左眼位置, 左眼位置坐标)
// (hasRightEyePosition, rightEyePosition) : (特征中是否有右眼位置, 右眼位置坐标)
// (hasMouthPosition, mouthPosition) : (特征中是否有嘴部位置, 嘴部位置坐标)
 - (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; 
}

CIFaceFeature中还提供了是否有微笑、左右闭眼等。

附录

图像滤镜完整列表及用法示例
Core Image官方文档
对Core Image进行封装
Core Image与视频处理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容