基于CoreImage框架实现图片滤镜、亮度、对比度、饱和度

效果图:

CoreImage.gif

一直想研究一下图片滤镜怎么实现的,抽空研究了一下,下面是实现部分,代码都有注释,灰常的详细,希望可以帮到正在开发滤镜 图片处理相关的码友_,先把demo地址放出来 ,如果比较着急的可以直接看demo:

demo地址
https://github.com/wxh794708907/YJYYImageFilter.git
代码实践
//
//  ViewController.m
//  YJYYImageFilter
//
//  Created by 遇见远洋 on 17/2/17.
//  Copyright © 2017年 遇见远洋. All rights reserved.
//

#import "ViewController.h"

#define ScreenWidth [self.view bounds].size.width
#define ScreenHeight [self.view bounds].size.height

@interface ViewController ()<UIPickerViewDelegate,UIPickerViewDataSource>
/** 数据源 */
@property(nonatomic,strong) NSArray *dataArray;
/** 显示数据 */
@property(nonatomic,strong) NSArray *pickerData;
/** 展示图 */
@property(nonatomic,strong) UIImageView *showImageV;
/** 原始图片 */
@property(nonatomic,strong) UIImage *originalImage;
/** pickView */
@property(nonatomic,strong) UIPickerView *pickView;
/** 亮度inputBrightness */
@property(nonatomic,strong) NSMutableArray *inputBrightness;
/** 饱和度inputSaturation */
@property(nonatomic,strong) NSMutableArray *inputSaturation;
/** 对比度inputContrast */
@property(nonatomic,strong) NSMutableArray *inputContrast;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //展示视图
    [self.view addSubview:self.showImageV];
    
    //pickView
    [self.view addSubview:self.pickView];
}


#pragma  mark -  pickView数据源以及代理方法
#pragma  mark -
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 4;
}

//返回每个组件上的行数
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
    switch (component) {
        case 0:
            return self.dataArray.count;
            break;
        case 1:
            return self.inputBrightness.count;
            break;
        case 2:
            return self.inputContrast.count;
            break;
        case 3:
            return self.inputSaturation.count;
            break;
        default:
            return 0;
            break;
    }
}

//设置每行显示的内容
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    switch (component) {
        case 0:
            return [self.pickerData objectAtIndex:row];
            break;
        case 1:
          return  [NSString stringWithFormat:@"%@",self.inputBrightness[row]];
            break;
        case 2:
            return  [NSString stringWithFormat:@"%@",self.inputContrast[row]];
            break;
        case 3:
            return  [NSString stringWithFormat:@"%@",self.inputSaturation[row]];
            break;
        default:
            return nil;
            break;
    }
}

//选中某一行时调用
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    switch (component) {
        case 0://滤镜
            [self filterImageWithfilterName:self.dataArray[row]];
            break;
        case 1://亮度
            [self colorControlsWithSaturation:1.f brightness:[self.inputBrightness[row] floatValue] contrast:1.f];
            break;
        case 2://对比度
            [self colorControlsWithSaturation:1.f brightness:0 contrast:[self.inputContrast[row] floatValue]];
            break;
        case 3://饱和度
            [self colorControlsWithSaturation:[self.inputSaturation[row] floatValue] brightness:0 contrast:1.f];
            break;
        default:
            break;
    }
}


#pragma  mark -  对图片进行滤镜处理
#pragma  mark -
// 怀旧 --> CIPhotoEffectInstant
// 单色 --> CIPhotoEffectMono
// 黑白 --> CIPhotoEffectNoir
// 褪色 --> CIPhotoEffectFade
// 色调 --> CIPhotoEffectTonal
// 冲印 --> CIPhotoEffectProcess
// 岁月 --> CIPhotoEffectTransfer
// 铬黄 --> CIPhotoEffectChrome
- (void )filterImageWithfilterName:(NSString *)name{
    if ([name isEqualToString:@"OriginalImage"]) {//原图
        self.showImageV.image = [UIImage imageNamed:@"original"];
        return;
    }
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //将UIImage转换成CIImage
        CIImage *ciImage = [[CIImage alloc] initWithImage:self.originalImage];
        
        //创建滤镜
        CIFilter *filter = [CIFilter filterWithName:name keysAndValues:kCIInputImageKey, ciImage, nil];
        
        //已有的值不改变,其他的设为默认值
        [filter setDefaults];
        
        //获取绘制上下文
        CIContext *context = [CIContext contextWithOptions:nil];
        
        //渲染并输出CIImage
        CIImage *outputImage = [filter outputImage];
        
        //创建CGImage句柄
        CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
        
        //获取图片
        UIImage *image = [UIImage imageWithCGImage:cgImage];
        
        //释放CGImage句柄
        CGImageRelease(cgImage);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.showImageV.image = image;
        });
    });
}

/**
 *  调整图片饱和度, 亮度, 对比度
 *  @param saturation 饱和度 默认为1
 *  @param brightness 亮度: -1.0 ~ 1.0 默认是0
 *  @param contrast   对比度 默认为1
 *
 */- (void)colorControlsWithSaturation:(CGFloat)saturation
                            brightness:(CGFloat)brightness
                              contrast:(CGFloat)contrast{
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
         CIContext *context = [CIContext contextWithOptions:nil];
         CIImage *inputImage = [[CIImage alloc] initWithImage:self.originalImage];
         CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
         [filter setValue:inputImage forKey:kCIInputImageKey];
         
         [filter setValue:@(saturation) forKey:@"inputSaturation"];
         [filter setValue:@(brightness) forKey:@"inputBrightness"];
         [filter setValue:@(contrast) forKey:@"inputContrast"];
         
         CIImage *result = [filter valueForKey:kCIOutputImageKey];
         CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
         UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
         CGImageRelease(cgImage);
         
         dispatch_async(dispatch_get_main_queue(), ^{
             self.showImageV.image = resultImage;
         });
     });
 }


#pragma  mark -  懒加载部分
#pragma  mark -
- (NSArray *)dataArray {
    if (!_dataArray) {
        _dataArray = [NSArray arrayWithObjects:
                      @"OriginalImage",
                      @"CIPhotoEffectInstant",
                      @"CIPhotoEffectMono",
                      @"CIPhotoEffectNoir",
                      @"CIPhotoEffectFade",
                      @"CIPhotoEffectTonal",
                      @"CIPhotoEffectProcess",
                      @"CIPhotoEffectTransfer",
                      @"CIPhotoEffectChrome",
                      nil];
    }
    return _dataArray;
}

- (NSArray *)pickerData {
    if (!_pickerData) {
        _pickerData = [NSArray arrayWithObjects:
                       @"原图",
                       @"怀旧",
                       @"单色",
                       @"黑白",
                       @"褪色",
                       @"色调",
                       @"冲印",
                       @"岁月",
                       @"铬黄",
                       nil];
    }
    return _pickerData;
}

- (NSMutableArray *)inputBrightness {//亮度
    if (!_inputBrightness) {
        _inputBrightness = [NSMutableArray arrayWithArray:@[@-1,@-0.5,@0,@0.5,@1]];
    }
    return _inputBrightness;
}


- (NSMutableArray *)inputSaturation {//对比度
    if (!_inputSaturation) {
        _inputSaturation = [NSMutableArray arrayWithArray:@[@0,@1,@2,@3,@4]];
    }
    return _inputSaturation;
}


- (NSMutableArray *)inputContrast {//饱和度
    if (!_inputContrast) {
        _inputContrast = [NSMutableArray arrayWithArray:@[@0,@0.5,@1,@1.5,@2]];
    }
    return _inputContrast;
}

- (UIImageView *)showImageV {
    if (!_showImageV) {
        _showImageV = [[UIImageView alloc]initWithImage:self.originalImage];
        _showImageV.contentMode = UIViewContentModeScaleAspectFit;
        _showImageV.frame = CGRectMake(0, 0, 300, 300);
        _showImageV.center = CGPointMake(self.view.center.x, self.view.center.y - 100);
    }
    return _showImageV;
}

- (UIImage *)originalImage {
    if (!_originalImage) {
        _originalImage = [UIImage imageNamed:@"original"];
    }
    return _originalImage;
}

- (UIPickerView *)pickView {
    if (!_pickView) {
        _pickView = [[UIPickerView alloc]initWithFrame:CGRectMake(0, ScreenHeight - 300, ScreenWidth, 300)];
        _pickView.dataSource = self;
        _pickView.delegate = self;
        //默认选中
        [self.pickView selectRow:0 inComponent:0 animated:YES];
        [self.pickView selectRow:2 inComponent:1 animated:YES];
        [self.pickView selectRow:2 inComponent:2 animated:YES];
        [self.pickView selectRow:1 inComponent:3 animated:YES];
        
    }
    return _pickView;
}

建议大家运行一下demo来看一下效果,为了方便大家查看效果,我已经使用pickView来将效果展示出来,我觉得还是比较方便的,有什么不懂得 一看代码就懂了,这里我还是按照惯例总结一下吧:

滤镜的实现步骤:
  • 将原始的UIImage对象转换成CIImage的对象
  • 创建滤镜
  • 获取绘制上下文
  • 渲染并输出CIImage对象
  • 创建CGImage句柄
  • 将CGImageRef对象转换为UIImage对象
  • 释放CGImage句柄(这里要注意 内存释放)

图片饱和度、亮度等设置我就不写步骤了,其实原理是一样的,都是通过创建一个滤镜 设置不同的值来实现效果,建议大家看看代码吧,不是很难。

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

推荐阅读更多精彩内容

  • 许多UIView的子类,如一个UIButton或一个UILabel,它们知道怎么绘制自己。迟早,你也将想要做一些自...
    shenzhenboy阅读 1,622评论 2 8
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,513评论 0 20
  • 原链接:http://www.csdn.net/article/2015-02-13/2823961-core-i...
    hament阅读 992评论 0 1
  • 妇产科实验到今天就结束了。现在是第7周。等到13周就要去附属医院见习了,见习4周后就要真正意义上实习了,好快!!!...
    梦霞mm阅读 423评论 0 0
  • 此时此刻我头疼欲裂,本来想着要不今天请假吧,可是我怕自己一请假就不能坚持了,想了想还是拿起手机,说说自己的健康问题...
    月儿的2016阅读 297评论 2 1