Swift3.1動畫之Core Image

圖片來源于網(wǎng)絡(luò)

前言:Core Image是一個強大的框架,可讓您輕松地將過濾器應(yīng)用于圖像。您可以獲得各種各樣的效果,如修改活力,色調(diào)或曝光。它可以使用CPU或GPU來處理圖像數(shù)據(jù),并且速度非???- 足以實現(xiàn)視頻幀的實時處理!
核心圖像濾鏡也可以鏈接在一起,以一次將多個效果應(yīng)用于圖像或視頻幀。多個濾波器被組合成應(yīng)用于圖像的單個濾波器。與通過每個過濾器一次處理圖像相比,這樣做非常有效。

入門

在開始之前,讓我們來討論Core Image框架中的一些最重要的類:
CIContext。核心圖像的所有處理都以CIContext完成。這與Core Graphics或OpenGL上下文有些相似。
CIImage。該類保存圖像數(shù)據(jù)。它可以從UIImage,從圖像文件或從像素數(shù)據(jù)創(chuàng)建。
CIFilter。CIFilter類有一個字典,用于定義它所代表的特定過濾器的屬性。過濾器的例子是振動,顏色反轉(zhuǎn),裁剪等等。

基本圖像過濾

通過簡單地運行您的圖像CIFilter并在屏幕上顯示圖像來開始。每次想要將CIFilter應(yīng)用于圖像時,有4個步驟:

1、創(chuàng)建一個CIImage對象。CIImage有幾種初始化方法,包括:CIImage(CIImage(contentsOf: ),CIImage(data :),CIImage(CGImage :),CIImage(bitmapData:bytesPerRow:size:format:colorSpace :)等幾個。最常用的是用CIImage(contentsOf: )
2、創(chuàng)建CIContext。CIContext可以是基于CPU或GPU的。CIContext初始化相對耗費資源,因此您可以重用它,而不是一遍又一遍地創(chuàng)建它。輸出CIImage對象時,您將始終需要一個。
3、創(chuàng)建一個CIFilter。創(chuàng)建過濾器時,您可以配置依賴于您使用的過濾器的許多屬性。
4、獲取過濾器輸出。過濾器為您提供輸出圖像作為CIImage - 您可以使用CIContext將其轉(zhuǎn)換為UIImage,如下所示

  // 1
  let fileURL = Bundle.main.url(forResource: "beauty", withExtension: "jpg")
  // 2
  let beginImage = CIImage(contentsOf: fileURL!)
  // 3
  let filter = CIFilter (name: "CISepiaTone")
  filter?.setValue(beginImage, forKey: kCIInputImageKey)
  filter?.setValue(0.5, forKey: kCIInputIntensityKey)
  // 4
  let newImage = UIImage(ciImage: (filter?.outputImage)!)
  self.imageView.image = newImage;

我們先來看看這一節(jié):

1、此行創(chuàng)建一個<code>NSURL</code>對象,該對象保存圖像文件的路徑。
2、接下來,使用<code>CIImage(contentsOf: )</code>構(gòu)造函數(shù)創(chuàng)建您的CIImage。
3、接下來,您將創(chuàng)建您的<code>CIFilter</code>對象。<code>CIFilter</code>構(gòu)造函數(shù)使用過濾器的名稱,并指定該過濾器的鍵和值的字典。每個過濾器將有自己唯一的密鑰和一組有效的值。所述<code>CISepiaTone</code>過濾器只需兩個值:<code>KCIInputImageKey</code>(一個CIImage)和在0和1之間的<code>kCIInputIntensityKey</code> ,你給該值0.5。大多數(shù)過濾器具有默認值,如果沒有提供值,將使用該值。一個例外是<code>CIImage</code>,這是必須提供的,因為沒有默認。
4、將<code>CIImage</code>從過濾器中恢復(fù)與使用該<code>outputImage</code>屬性一樣簡單。一旦輸出<code>CIImage</code>,您將需要將其轉(zhuǎn)換為<code>UIImage</code>。該<code>UIImage(ciImage:)</code>構(gòu)造函數(shù)轉(zhuǎn)換了<code>CIImage</code>到<code>UIImage</code>。一旦將其轉(zhuǎn)換為<code>UIImage</code>,您只需將其顯示在您之前添加的<code>imageView</code>中。

運行該項目,您將看到由深褐色濾鏡過濾的圖像。

置于上下文

在您繼續(xù)了解之前,您應(yīng)該了解一個優(yōu)化。
我之前提到你需要一個CIContext應(yīng)用CIFilter,但在上面的例子中沒有提到這個對象。事實證明,<code>UIImage(ciImage:)code</code>構(gòu)造函數(shù)為您做所有的工作。它創(chuàng)建CIContext并使用它來執(zhí)行過濾圖像的工作。這使得使用Core Image API非常簡單。
有一個主要的缺點 - CIContext每次使用時都會創(chuàng)建一個新的。CIContext實例旨在可重用以提高性能。如果要使用滑塊來更新過濾器值,就像在本教程中所做的那樣,每次更改過濾器時都會創(chuàng)建一個新的CIContext將太慢了。
我們這樣做是正確的。從viewDidLoad()添加的代碼中刪除步驟4 ,并將其替換為以下內(nèi)容:

// 1
let context = CIContext(options:nil)

// 2
let cgimg = context.createCGImage(filter!.outputImage!, from: filter!.outputImage!.extent)

// 3
let newImage = UIImage(cgImage: cgimg!)
self.imageView.image = newImage;

再次,我們一起來看看這一節(jié)。
在這里,您設(shè)置CIContext對象并使用它來繪制CGImage。該CIContext(options:)構(gòu)造采用指定的選項一個NSDictionary如色彩格式,或上下文是否應(yīng)在CPU或GPU上運行。對于這個應(yīng)用程序,默認值是好的,所以你傳遞為nil為該參數(shù)。
<code>createCGImage(outputImage:from:)</code>使用提供的CIImage在上下文中調(diào)用將返回一個新的CGImage實例。
接下來,您使用<code>UIImage(cgImage:)</code>構(gòu)造函數(shù)從新創(chuàng)建的CGImage創(chuàng)建UIImage,而不是像以前一樣直接從CIImage創(chuàng)建。注意,在完成它之后,不需要明確地釋放CGImage,就像在Objective-C中一樣。在Swift中,ARC可以自動釋放Core Foundation對象。
構(gòu)建和運行,并確保它像以前一樣工作。
在這個例子中,自己處理CIContext的創(chuàng)建并沒有太多的區(qū)別。但在下一節(jié)中,您將看到為什么這對于性能很重要,因為您實現(xiàn)了動態(tài)修改過濾器的功能!
更改過濾器值

下面增加滑塊,每次滑塊更改時,都需要使用不同的值重做圖像過濾器。但是,您不想重做整個過程,這將是非常低效的,并且需要太長時間。您將需要更改類中的一些內(nèi)容,以便您可以保留在viewDidLoad方法中創(chuàng)建的一些對象。
如果為了重新使用CIContext,而每次重新創(chuàng)建它程序?qū)⑦\行非常緩慢。
添加一些實例變量才能完成此任務(wù)。將以下三個屬性添加到ViewController類中:

var context: CIContext!
var filter: CIFilter!
var beginImage: CIImage!

更改代碼,因此<code>viewDidLoad()</code>使用這些屬性,而不是聲明新的局部變量,如下所示:

beginImage = CIImage(contentsOf: fileURL!)

filter = CIFilter (name: "CISepiaTone")
filter?.setValue(beginImage, forKey: kCIInputImageKey)
filter?.setValue(0.5, forKey: kCIInputIntensityKey)

let outputImage = filter.outputImage
context = CIContext(options:nil)

let cgimg = context.createCGImage(filter!.outputImage!, from: filter!.outputImage!.extent)

實現(xiàn)changeValue方法。在CIFilter字典中改變<code>inputIntensity</code>值。
一旦你改變了這個值,你需要重復(fù)幾個步驟:

1、從CIFilter獲取輸出CIImage。
2、將CIImage轉(zhuǎn)換為CGImage。
3、將CGImage轉(zhuǎn)換為UIImage,并將其顯示在圖像視圖中。

將創(chuàng)建一個方法<code>amountSliderValueChanged(sender :)</code>:

@IBAction func amountSliderValueChange(_ sender: UISlider) {
    let sliderValue = sender.value
    
    filter.setValue(sliderValue, forKey: kCIInputIntensityKey)
    let outputImage = filter.outputImage
    
    let cgimg = context.createCGImage(outputImage!, from: outputImage!.extent)
    
    let newImage = UIImage(cgImage: cgimg!)
    self.imageView.image = newImage
}
Core Image變化

老相片效果

在這個Demo中,會得到一個更精致的老照片效果,完成與棕褐色,一點噪音和一些暈影

func oldPhoto (img: CIImage, withAmount intensity: Float) -> CIImage {
    //1 CISepiaTone 棕褐色調(diào)
    let sepia = CIFilter(name: "CISepiaTone")
    sepia?.setValue(img, forKey: kCIInputImageKey)
    sepia?.setValue(intensity, forKey: "inputIntensity")
    
    //2 設(shè)置一個過濾器,創(chuàng)建一個隨機噪聲模式
    let random = CIFilter(name: "CIRandomGenerator")
    
    //3 改變隨機噪聲發(fā)生器的輸出
    let lighten = CIFilter(name:"CIColorControls")
    lighten?.setValue(random?.outputImage, forKey:kCIInputImageKey)
    lighten?.setValue(1 - intensity, forKey:"inputBrightness")
    lighten?.setValue(0, forKey:"inputSaturation")
    
    //4 cropping(to rect: CGRect)輸出CIImage并將其作用到所提供的rect
    let croppedImage = lighten?.outputImage?.cropping(to: beginImage.extent)
    
    //5 將棕褐色濾鏡的輸出與CIRandomGenerator濾鏡的輸出相結(jié)合。
    let composite = CIFilter(name:"CIHardLightBlendMode")
    composite?.setValue(sepia?.outputImage, forKey:kCIInputImageKey)
    composite?.setValue(croppedImage, forKey:kCIInputBackgroundImageKey)
    
    //6 合成輸出上運行暈影濾鏡(vignette filter),使照片的邊緣變暗
    let vignette = CIFilter(name:"CIVignette")
    vignette?.setValue(composite?.outputImage, forKey:kCIInputImageKey)
    vignette?.setValue(intensity * 2, forKey:"inputIntensity")
    vignette?.setValue(intensity * 30, forKey:"inputRadius")
    
    //7 返回濾鏡的輸出
    return vignette!.outputImage!
}

效果圖:

老照片.png

解析以上代碼:
1、像在簡單的場景中所做的一樣,設(shè)置棕褐色濾鏡。您在方法中傳入浮點值以設(shè)置深色效果的強度。該值將由滑塊提供。
2、設(shè)置一個過濾器,創(chuàng)建一個如下所示的隨機噪聲模式:


CIRandomGenerator

它不需要任何參數(shù)。您將使用這種噪音模式將紋理添加到最終的“舊照片”外觀。
3、改變隨機噪聲發(fā)生器的輸出。你想把它改成灰度,并減輕一點點,所以效果不那么戲劇化。您會注意到,輸入圖像鍵被設(shè)置為隨機過濾器的outputImage屬性。這是一個方便的方式來傳遞一個過濾器的輸出作為下一個的輸入。
4、 cropping(to rect: CGRect)輸出CIImage并將其作用到所提供的rect。在這種情況下,您需要裁剪CIRandomGenerator過濾器的輸出,因為它無限制地打磚塊。如果您在某些時候沒有裁剪,就會出現(xiàn)一個錯誤,表示過濾器具有“無限長度”。CIImages實際上并不包含圖像數(shù)據(jù),它們描述了創(chuàng)建它的“配方”。直到你在CIContext上調(diào)用一個方法來實際處理數(shù)據(jù)。
5、將棕褐色濾鏡的輸出與CIRandomGenerator濾鏡的輸出相結(jié)合。該過濾器執(zhí)行與Photoshop圖層中的“硬光”設(shè)置完全相同的操作。使用Core Image可以實現(xiàn)Photoshop中的大多數(shù)濾鏡選項。
6、在此合成輸出上運行暈影濾鏡,使照片的邊緣變暗。您正在使用滑塊的值來設(shè)置此效果的半徑和強度。
7、返回最后一個過濾器的輸出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Core Image是一個強大的框架,它能夠讓你輕松地對圖像進行過濾。你能夠通過修改圖像的飽和度、色調(diào)或曝光率來獲...
    木易林1閱讀 1,204評論 0 1
  • 許多UIView的子類,如一個UIButton或一個UILabel,它們知道怎么繪制自己。遲早,你也將想要做一些自...
    shenzhenboy閱讀 1,754評論 2 8
  • 前言 最近在研究 Core Image 自定義 Filter 相關(guān)內(nèi)容,重新學(xué)習(xí)了 Core Image,對 Co...
    泥孩兒0107閱讀 878評論 0 4
  • 原鏈接:http://www.csdn.net/article/2015-02-13/2823961-core-i...
    hament閱讀 1,064評論 0 1
  • 望空樓而思憶,時三更而躊躇。笑笨鳥遲飛,本鈍劍難鳴。心有溝壑萬丈,胸?zé)o一點墨痕。哀矣! 日見雛鷹欲登千丈而飛,不集...
    小小小歐巴閱讀 405評論 0 3

友情鏈接更多精彩內(nèi)容