1. 程式人生 > >iOS CoreImage濾鏡 圖片處理效果

iOS CoreImage濾鏡 圖片處理效果

前言
現在很多的APP當中選擇圖片都會帶有圖片處理效果,一些類似於美圖,PS的功能,其實在iOS中系統內部也有這樣一個框架,在Xcode7.0之前的版本需要手動去匯入這個框架,7.0之後系統已經自動幫我們匯入了這個框架。我們想要處理圖片直接就可以在方法裡面去實現處理圖片的效果。

在學習這個框架之前我們要看一下什麼是濾鏡的效果,我們先找到一張圖片,然後拿一個檢視層來覆蓋到源圖上面,這裡我就隨便找一張圖片

修過的圖
再來貼一張原圖吧

原圖

可以看到經過處理之後圖片變得像那種黃昏一樣的效果,我們在美圖或者PS上都可以簡單的實現這些小功能,那麼今天就說一下iOS系統中,系統是如何來做這個圖片處理的。

  • 1.框架介紹


    (1)CoreImage
    (2)是一個圖片框架
    它基於OpenGL頂層建立
    底層則用著色器來處理影象
    (3)他利用了GPU基於硬體加速來處理影象
    (4)CoreImage中有很多濾鏡
    (5)它們能夠一次給予一張影象或者視訊幀多種視覺效果 -> 濾鏡鏈
    (6)而且濾鏡可以連線起來組成一個濾鏡鏈 把濾鏡效果疊加起來處理影象

  • 2.類的介紹
    1.CIImage 儲存影象資料的類
    CGImageRef->影象中的資料
    2.CIFilter 濾鏡類
    圖片屬性進行細節處理的類
    它對所有的畫素進行操作 用鍵-值(KVC)來設定
    3.CIContext 上下文是實現對影象處理的具體物件 用來把濾鏡和圖片合成成為一張圖片 濾鏡物件輸出的影象並不是合成之後的影象,需要使用圖片處理的上下文 合併輸出影象

接下來就是他系統內部的效果分類,效果分類就不在這裡一一羅列出來了,因為這裡根本寫不下,可以點進CIFilter裡,然後找到128行,從這裡開始,可以一一瞭解一下這些效果。

然後我們就可以做一個圖片處理的效果,我們處理圖片的原理上面給大家說過了,就是給他添加了一個濾鏡,CIFilter,來使他的檢視發生一些變化。

在這裡我們雖然展示在檢視上的仍然是UIImageView上面的image,但是我們做處理的時候使用的是CIImage。然後我們需要找到我們需要的效果類,在CIFilter中查詢我們需要的效果類,這裡直接上程式碼給大家解釋,因為在找效果類的時候比較複雜。

首先我們建立一個全域性變數的UIImageView,然後讓他初始化出來

 @interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
{
     UIImageView *imageView;
}
@end

因為要訪問相簿,所以我們同樣需要匯入導航欄和UIImagePickerController的代理

然後我們寫兩個按鈕,一個按鈕用來找到並顯示圖片,一個按鈕用來對圖片做一些處理

imageView = [[UIImageView alloc]initWithFrame:self.view.frame];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:imageView];
self.view.backgroundColor = [UIColor colorWithRed:0.813 green:1.000 blue:0.564 alpha:1.000];
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
button1.frame = CGRectMake(100, 100, 120, 45);
[button1 setTitle:@"找圖片" forState:UIControlStateNormal];
button1.backgroundColor = [UIColor brownColor];
[button1 addTarget:self action:@selector(doit) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button1];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(250, 200, 150, 45);
[button setTitle:@"讓我來修改" forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithRed:102/255.0f green:153/255.0f blue:0.0f alpha:1] forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont systemFontOfSize:12]];
[button.layer setCornerRadius:5];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef colorRef = CGColorCreate(colorSpace,(CGFloat[]){ 102/255.0f, 153/255.0f, 0.0f, 1 });
[button.layer setBorderColor:colorRef];
[button.layer setBorderWidth:1.0f];
[button addTarget:self action:@selector(addColorFilter) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];

 //跳轉相簿的觸發方法
- (void)doit{
UIImagePickerController *vc = [[UIImagePickerController alloc]init];
vc.delegate = self;
[self presentViewController:vc animated:YES completion:nil];


}
//讓圖片顯示在VC上面的方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
NSLog(@"%@",info);
//獲得選中的影象
UIImage *chooseImage = info[UIImagePickerControllerOriginalImage];
//先是在試圖空間上
imageView.image = chooseImage;

[self dismissViewControllerAnimated:YES completion:nil];
}

這裡我就簡單的寫兩個按鈕(其實就是從程式碼片段裡拖出來的 =-=)

然後我們重點做一個圖片的處理效果的方法。這裡我們選擇把它的顏色發生一些改變

- (void)addColorFilter{

CIImage *inputImage = [CIImage imageWithCGImage:imageView.image.CGImage];
//先列印NSLog(@"%@",[CIFilter filterNamesInCategory:kCICategoryDistortionEffect]);進去找到需要設定的屬性(查詢效果分類中都有什麼效果)  可以設定什麼效果
//然後通過[CIFilter filterWithName:@""];找到屬性   具體效果的屬性
//然後通過KVC的方式設定屬性
NSLog(@"%@",[CIFilter filterNamesInCategory:kCICategoryDistortionEffect]);
/*
 1.查詢 效果分類中 包含什麼效果:filterNamesInCategory:
 2.查詢 使用的效果中 可以設定什麼屬性(KVC) attributes

 使用步驟
 1.需要新增濾鏡的源圖
 2.初始化一個濾鏡 設定濾鏡(根據查詢到的屬性來設定)
 3.把濾鏡 輸出的影象 和濾鏡  合併 CIContext -> 得到一個合成之後的影象
 4.展示
 */
CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome"];
NSLog(@"%@",filter.attributes);
//這個屬性是必須賦值的,假如你處理的是圖片的話
[filter setValue:inputImage forKey:kCIInputImageKey];
CIColor *color = [CIColor colorWithRed:1.000 green:0.759 blue:0.592 alpha:1];
[filter setValue:color forKey:kCIInputColorKey];
//CIContext
    CIContext *context = [CIContext contextWithOptions:nil];

CIImage *outPutImage = filter.outputImage;

    CGImageRef image = [context createCGImage:outPutImage fromRect:outPutImage.extent];

    imageView.image = [UIImage imageWithCGImage:image];


 }

首先我們第一步通過全域性變數來獲得我們找到的image把他轉換成CIImage的型別來獲得到。

第二部,進入CIFilter中,找到128行-148行,全都是效果的分類,然後,來找你需要的效果,這裡我們就使用kCICategoryDistortionEffect失真的效果類,記住,這裡是效果型別,然後nslog打印出這個效果型別,看裡面包含了哪些效果。
我們在這裡找到CIColorMonochrome這個效果,然後我們使用濾鏡使用這個效果。

CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome"];

再列印這個效果包含了哪些屬性,這裡我們列印他的屬性

NSLog(@"%@",filter.attributes);

在裡面我們可以看到好多屬性,裡面是多個字典的形式,找到我們想要修改的屬性(key值) 然後在他對應的value裡面檢視一下他的屬性型別,比如我們列印的CIColorMonochrome裡面有一個inputColor

inputColor =     {
    CIAttributeClass = CIColor;
    CIAttributeDefault = "(0.6 0.45 0.3 1)";
    CIAttributeDescription = "The monochrome color to apply to the image.";
    CIAttributeDisplayName = Color;
    CIAttributeType = CIAttributeTypeOpaqueColor;
};

我們看到他是一個CIColor型別的,有預設值,這裡我們寫了一個CIColor來給他進行賦值。

賦值的時候要使用KVC的形式來賦值

[filter setValue:color forKey:kCIInputColorKey];

接下來,賦值之後,被濾鏡過濾之後的圖片就有了,但是我們這個時候拿出這個圖片的時候發現他並沒有發生變化,因為它只是單一進行了濾鏡處理,還沒有和原圖片進行一個糅合。

CIImage *outPutImage = filter.outputImage;

我們找到新增效果後的圖片,然後使用CIContext找到上下文對他進行糅合

//extent得到影象的尺寸    合併一個包含源圖   濾鏡效果的圖片
//1 濾鏡輸出的影象    2.合成之後影象的尺寸   影象.extent
CGImageRef imageRef = [context createCGImage:outPutImage fromRect:outPutImage.extent];

這樣我就進行了一個簡單的圖片處理。我們可以看到它已經發生了一些變化。
假如你的圖片消失了,請檢查一下,第一步獲取圖片的時候一定要獲得圖片的CGImage再來來獲取,不要直接使用imageView.image.CGImage。

假如你的圖片還是沒有出來,請檢查你使用的效果類是否適合用來處理圖片,或者它裡面有沒有必須要賦值的屬性你沒有賦值。或者檢查一下處理圖片的時候有沒有給kCIInputImageKey賦值

對於第二步列印效果分類,在這裡放上一個圖片來便於大家理解

詳情

在給一張圖片新增多種濾鏡效果的時候,我們把它稱為濾鏡鏈,我們再新增濾鏡鏈的時候,就是把圖片新增一層濾鏡,然後,和原圖片糅合處理,然後在處理之後的圖片上再新增一層濾鏡,並不是直接給一張圖片添加了兩層路徑,所以稱為濾鏡鏈。

我們繼續使用這個圖片,在它新增第一層濾鏡的時候做一些修改
修改如下

//上接給效果屬性賦值
//把下面註釋的給註釋掉,然後新增一個方法
    //CIContext
//    CIContext *context = [CIContext contextWithOptions:nil];

CIImage *outPutImage = filter.outputImage;
[self addFilterLinkerWithImage:outPutImage];
//    CGImageRef image = [context createCGImage:outPutImage fromRect:outPutImage.extent];

//    imageView.image = [UIImage imageWithCGImage:image];

//再次新增濾鏡  ->  形成濾鏡鏈
- (void)addFilterLinkerWithImage:(CIImage *)image
{
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"];
[filter setValue:image forKey:kCIInputImageKey];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef resultImage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
imageView.image = [UIImage imageWithCGImage:resultImage];
//把新增好濾鏡效果的圖片   儲存到相簿
//不可以直接儲存 outputImage  ->  這是一個沒有吧濾鏡效果和源圖合成的影象
UIImageWriteToSavedPhotosAlbum(imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
 }
//儲存圖片回撥
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    NSLog(@"儲存成功");
}

這樣就能做一個雙重濾鏡效果,同時把它儲存到了相簿。

進行圖片處理的時候要了解他的效果型別,還有屬性的型別,賦值的過程,理解了這一點,新增濾鏡就沒有什麼大問題了,在這點我來來回回說了三遍,希望能有所有幫助。