在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ Core Image 介紹
與四軸無人機的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動開發(fā)
Collection View 動畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進的自動布局工具箱
動畫
為 iOS 7 重新設(shè)計 App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項目介紹
Swift 的強大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計優(yōu)雅的移動游戲
繪制像素到屏幕上
相機與照片
音頻 API 一覽
交互式動畫
常見的后臺實踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機項目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動追蹤
依賴注入
Swift
項目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實戰(zhàn)
iOS 7
Layer 中自定義屬性的動畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機捕捉
語言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機工作原理
Build 過程

Core Image 介紹

這篇文章會為初學(xué)者介紹一下 Core Image,一個 OS X 和 iOS 的圖像處理框架。

如果你想跟著本文中的代碼學(xué)習(xí),你可以在 GitHub 上下載示例工程。示例工程是一個 iOS 應(yīng)用程序,列出了系統(tǒng)提供的大量圖像濾鏡以供選擇,并提供了一個用戶界面用來調(diào)整參數(shù)并觀察效果。

雖然示例代碼是用 Swift 寫的 iOS 程序,不過實現(xiàn)概念很容易轉(zhuǎn)換到 Objective-C 和 OS X.

基本概念

說到 Core Image,我們首先需要介紹幾個基本的概念。

一個濾鏡是一個對象,有很多輸入和輸出,并執(zhí)行一些變換。例如,模糊濾鏡可能需要輸入圖像和一個模糊半徑來產(chǎn)生適當(dāng)?shù)哪:蟮妮敵鰣D像。

一個濾鏡圖表是一個鏈接在一起的濾鏡網(wǎng)絡(luò) (無回路有向圖),使得一個濾鏡的輸出可以是另一個濾鏡的輸入。以這種方式,可以實現(xiàn)精心制作的效果。我們將在下面看到如何連接濾鏡來創(chuàng)建一個復(fù)古的拍照效果。

熟悉 Core Image API

有了上述的這些概念,我們可以開始探索 Core Image 的圖像濾鏡細(xì)節(jié)了。

Core Image 架構(gòu)

Core Image 有一個插件架構(gòu),這意味著它允許用戶編寫自定義的濾鏡并與系統(tǒng)提供的濾鏡集成來擴展其功能。我們在這篇文章中不會用到 Core Image 的可擴展性;我提到它只是因為它影響到了框架的 API。

Core Image 是用來最大化利用其所運行之上的硬件的。每個濾鏡實際上的實現(xiàn),即內(nèi)核,是由一個 GLSL (即 OpenGL 的著色語言) 的子集來書寫的。當(dāng)多個濾鏡連接成一個濾鏡圖表,Core Image 便把內(nèi)核串在一起來構(gòu)建一個可在 GPU 上運行的高效程序。

只要有可能,Core Image 都會把工作延遲。通常情況下,直到濾鏡圖表的最后一個濾鏡的輸出被請求之前都不會發(fā)生分配或處理。

為了完成工作,Core Image 需要一個稱為上下文 (context) 的對象。這個上下文是框架真正工作的地方,它需要分配必要的內(nèi)存,并編譯和運行濾鏡內(nèi)核來執(zhí)行圖像處理。建立一個上下文是非常昂貴的,所以你會經(jīng)常想創(chuàng)建一個反復(fù)使用的上下文。接下來我們將看到如何創(chuàng)建一個上下文。

查詢可用的濾鏡

Core Image 濾鏡是按名字創(chuàng)建的。要獲得系統(tǒng)濾鏡的列表,我們要向 Core Image 的 kCICategoryBuiltIn 類別請求得到濾鏡的名字:

let filterNames = CIFilter.filterNamesInCategory(kCICategoryBuiltIn) as [String]

iOS 上可用的濾鏡列表非常接近于 OS X 上可用濾鏡的一個子集。在 OS X 上有 169 個內(nèi)置濾鏡,在 iOS 上有 127 個。

通過名字創(chuàng)建一個濾鏡

現(xiàn)在,我們有了可用濾鏡的列表,我們就可以創(chuàng)建和使用濾鏡了。例如,要創(chuàng)建一個高斯模糊濾鏡,我們傳給 CIFilter 初始化方法相應(yīng)的名稱就可以了:

let blurFilter = CIFilter(named:"CIGaussianBlur")

設(shè)置濾鏡參數(shù)

由于 Core Image 的插件結(jié)構(gòu),大多數(shù)濾鏡屬性并不是直接設(shè)置的,而是通過鍵值編碼(KVC)設(shè)置。例如,要設(shè)置模糊濾鏡的模糊半徑,我們使用 KVC 來設(shè)置 inputRadius 屬性:

blurFilter.setValue(10.0 forKey:"inputRadius")

由于這種方法需要 AnyObject? (即 Objective-C 里的 id)作為其參數(shù)值,它不是類型安全的。因此,設(shè)置濾鏡參數(shù)需要謹(jǐn)慎一些,確保你傳值的類型是正確的。

查詢?yōu)V鏡屬性

為了知道一個濾鏡提供什么樣的輸入和輸出參數(shù),我們就可以分別獲取 inputKeysoutputKeys 數(shù)組。它們都返回 NSString 的數(shù)組。

要獲取每個參數(shù)的詳細(xì)信息,我們可以看看由濾鏡提供的 attributes 字典。每個輸入和輸出參數(shù)名映射到它自己的字典里,描述了它是什么樣的參數(shù),如果有的話還會給出它的最大值和最小值。例如,下面是 CIColorControls 濾鏡對應(yīng)的 inputBrightness 參數(shù)字典:

inputBrightness = {
    CIAttributeClass = NSNumber;
    CIAttributeDefault = 0;
    CIAttributeIdentity = 0;
    CIAttributeMin = -1;
    CIAttributeSliderMax = 1;
    CIAttributeSliderMin = -1;
    CIAttributeType = CIAttributeTypeScalar;
};

對于數(shù)值參數(shù),該字典會包含 kCIAttributeSliderMinkCIAttributeSliderMax 鍵,來限制期望的輸入域。大多數(shù)參數(shù)還包含一個 kCIAttributeDefault 關(guān)鍵字,映射到該參數(shù)的默認(rèn)值。

圖片濾鏡實戰(zhàn)

圖像濾鏡的工作由三部分組成:構(gòu)建和配置濾鏡圖表,發(fā)送等待濾鏡處理的圖像,得到濾鏡處理后的圖像。下面的部分對此進行了詳細(xì)描述。

構(gòu)建一個濾鏡圖表

構(gòu)建一個濾鏡圖表由這幾個部分組成:實例化我們需要的濾鏡,設(shè)置它們的參數(shù),把它們連接起來以便該圖像數(shù)據(jù)按順序傳過每個濾鏡。

在本節(jié)中,我們將創(chuàng)建一個用來制作 19 世紀(jì)錫版照風(fēng)格圖像的濾鏡圖表。我們將兩個效果鏈在一起來達(dá)到這種效果:同時去飽和以及染色調(diào)的黑白濾鏡,和一個暗角濾鏡來創(chuàng)建一個有陰影效果的加框圖片。

用 Quartz Composer,來做 Core Image 濾鏡圖表的原型非常有用,可以從蘋果開發(fā)者網(wǎng)站下載。下面,我們整理了所需的照片濾鏡,把黑白濾鏡和暗角濾鏡串在一起:

http://wiki.jikexueyuan.com/project/objc/images/21-22.png" alt="" />

一旦達(dá)到了我們滿意的效果,我們可以重新在代碼里創(chuàng)建濾鏡圖表:

let sepiaColor = CIColor(red: 0.76, green: 0.65, blue: 0.54)
let monochromeFilter = CIFilter(name: "CIColorMonochrome",
    withInputParameters: ["inputColor" : sepiaColor, "inputIntensity" : 1.0])
monochromeFilter.setValue(inputImage, forKey: "inputImage")

let vignetteFilter = CIFilter(name: "CIVignette",
    withInputParameters: ["inputRadius" : 1.75, "inputIntensity" : 1.0])
vignetteFilter.setValue(monochromeFilter.outputImage, forKey: "inputImage")

let outputImage = vignetteFilter.outputImage

需要注意的是黑白濾鏡的輸出圖像變?yōu)榘到菫V鏡的輸入圖像。這將導(dǎo)致暗角效果要應(yīng)用到黑白圖像上。還要注意的是,我們可以在初始化中指定參數(shù),而不一定需要用 KVC 單獨設(shè)置它們。

創(chuàng)建輸入圖像

Core Image 濾鏡要求其輸入圖像是 CIImage 類型。而對于 iOS 的程序員來說這可能會有一點不尋常,因為他們更習(xí)慣用 UIImage,但這個區(qū)別是值得的。一個 CIImage 實例實際上比 UIImage 更全面,因為 CIImage 可以無限大。當(dāng)然,我們不能存儲無限的圖像在內(nèi)存中,但在概念上,這意味著你可以從 2D 平面上的任意區(qū)域獲取圖像數(shù)據(jù),并得到一個有意義的結(jié)果。

所有我們在本文中使用的圖像都是有限的,而且也可以很容易從一個 UIImage 來創(chuàng)建一個 CIImage。事實上,這只需要一行代碼:

let inputImage = CIImage(image: uiImage)

也有很方便的初始化方法直接從圖像數(shù)據(jù)或文件 URL 來創(chuàng)建 CIImage。

一旦我們有了一個 CIImage,我們就可以通過設(shè)置濾鏡的 inputImage 參數(shù)來將其設(shè)置為濾鏡的輸入圖像:

filter.setValue(inputImage, forKey:"inputImage")

得到一個濾鏡處理后的圖片

濾鏡都有一個名為 outputImage 的屬性。正如你可能已經(jīng)猜到的一樣,它是 CIImage 類型的。那么,我們?nèi)绾螌崿F(xiàn)從一個 CIImage 創(chuàng)建 UIImage 這樣一個反向操作?好了,雖然我們到此已經(jīng)花了所有的時間建立一個濾鏡圖表,現(xiàn)在是調(diào)用 CIContext 的力量來實際的做圖像濾鏡處理工作的時候了。

創(chuàng)建一個上下文最簡單的方法是給它的構(gòu)造方法傳一個 nil 字典:

let ciContext = CIContext(options: nil)

為了得到一個濾鏡處理過的圖像,我們需要 CIContext 從輸出圖像的一個矩形內(nèi)創(chuàng)建一個 CGImage,傳入輸入圖像的范圍(bounds):

let cgImage = ciContext.createCGImage(filter.outputImage, fromRect: inputImage.extent())

我們使用輸入圖像大小的原因是,輸出圖像通常和輸入圖像具有不同的尺寸比。例如,一個模糊圖像由于采樣超出了輸入圖像的邊緣,圍繞在其邊界外還會有一些額外的像素。

現(xiàn)在,我們可以從這個新創(chuàng)建的 CGImage 來創(chuàng)建一個 UIImage 了:

let uiImage = UIImage(CGImage: cgImage)

直接從一個 CIImage 創(chuàng)建 UIImage 也是可以的,但這種方法有點讓人郁悶:如果你試圖在一個 UIImageView 上顯示這樣的圖像,其 contentMode 屬性將被忽略。使用過渡的 CGImage 則需要一個額外的步驟,但可以省去這一煩惱。

用 OpenGL 來提高性能

用 CPU 來繪制一個 CGImage 是非常耗時和浪費的,它只將結(jié)果回傳給 UIKit 來做合成。我們更希望能夠在屏幕上繪制應(yīng)用濾鏡后的圖像,而不必去 Core Graphics 里繞一圈。幸運的是,由于 OpenGL 和 Core Image 的可互操作性,我們可以這么做。

要 OpenGL 上下文和 Core Image 上下文之間共享資源,我們需要用一個稍微不同的方式來創(chuàng)建我們的 CIContext

let eaglContext = EAGLContext(API: .OpenGLES2)
let ciContext = CIContext(EAGLContext: context)

在這里,我們用 OpenGL ES 2.0 的功能集創(chuàng)建了一個 EAGLContext。這個 GL 上下文可以用作一個 GLKView 的背襯上下文或用來繪制成一個 CAEAGLLayer。示例代碼使用這種技術(shù)來有效地繪制圖像。

當(dāng)一個 CIContext 具有了關(guān)聯(lián) GL 的上下文,濾鏡處理后的圖像就可用 OpenGL 來繪制,像如下這樣調(diào)用方法:

ciContext.drawImage(filter.outputImage, inRect: outputBounds, fromRect: inputBounds)

與以前一樣,fromRect 參數(shù)是用濾鏡處理后的圖像的坐標(biāo)空間來繪制的圖像的一部分。這個 inRect 參數(shù)是 GL 上下文的坐標(biāo)空間的矩形應(yīng)用到需要繪制圖像上。如果你想保持圖像的長寬比,你可能需要做一些數(shù)學(xué)計算來得到適當(dāng)?shù)?inRect。

強制在 CPU 上做濾鏡操作

只要有可能,Core Image 將在 GPU 上執(zhí)行濾鏡操作。然而,它確實有回滾到 CPU 上執(zhí)行的可能。濾鏡操作在 CPU 上完成可具有更好的精確度,因為 GPU 經(jīng)常在浮點計算上以失真換得更快的速度。在創(chuàng)建一個上下文時,你可以通過設(shè)置 kCIContextUseSoftwareRenderer 關(guān)鍵字的值為 true 來強制 Core Image 在 CPU 上運行。

你可以通過在 Xcode 中設(shè)置計劃配置(scheme configuration)里的 CI_PRINT_TREE 環(huán)境變量為 1 來決定用 CPU 還是 GPU 來渲染。這將導(dǎo)致每次一個濾鏡處理圖像被渲染的時候 Core Image 都會打印診斷信息。此設(shè)置用來檢查合成圖像濾鏡樹也很有用。

示例應(yīng)用一覽

本文的示例代碼是一個 iPhone 應(yīng)用程序,展示了 iOS 里大量的各式 Core Image 圖像濾鏡。

為濾鏡參數(shù)創(chuàng)建一個 GUI

為了盡可能多的演示各種濾鏡,示例應(yīng)用程序利用了 Core Image 的內(nèi)省特點生成了一個界面,用于控制它支持的濾鏡參數(shù):

http://wiki.jikexueyuan.com/project/objc/images/21-23.png" alt="" />

示例應(yīng)用程序只限于單一的圖像輸入以及零個或多個數(shù)值輸入的濾鏡。也有一些有趣的濾鏡不屬于這一類(特別是那些合成和轉(zhuǎn)換濾鏡)。即便如此,該應(yīng)用程序仍然很好的概述了 Core Image 支持的功能。

對于每個濾鏡的輸入?yún)?shù),都有一個滑動條可以用于配置參數(shù)的最小值和最大值,其值被設(shè)置為默認(rèn)值。當(dāng)滑動條的值發(fā)生變化時,它把改變后的值傳給它的 delegate,一個持有 CIFilter 引用的 UIImageView 子類。

使用內(nèi)建的照片濾鏡

除了許多其他的內(nèi)置濾鏡,示例應(yīng)用程序還展示了 iOS 7 中引入的照片濾鏡。這些濾鏡沒有我們可以調(diào)整的參數(shù),但它們值得被囊括進來,因為它們展示了如何在 iOS 中模擬照片應(yīng)用程序的效果:

http://wiki.jikexueyuan.com/project/objc/images/21-24.png" alt="" />

結(jié)論

這篇文章簡要介紹了 Core Image 這個高性能的圖像處理框架。我們一直在試圖在如此簡短的形式內(nèi)盡可能多的展示這個框架的功能。你現(xiàn)在已經(jīng)學(xué)會了如何實例化和串聯(lián) Core Image 的濾鏡,在濾鏡圖表傳入和輸出圖像,以及調(diào)整參數(shù)來獲得想要的結(jié)果。你還學(xué)習(xí)了如何訪問系統(tǒng)提供的照片濾鏡,用以模擬在 iOS 上的照片應(yīng)用程序的行為。

現(xiàn)在你知道了足夠多的東西來寫你自己的照片編輯應(yīng)用程序了。隨著更多的一些探索,你就可以寫自己的濾鏡了,利用你的 Mac 或 iPhone 的神奇的力量來執(zhí)行以前無法想象的效果??烊邮肿霭桑?/p>

參考

Core Image Filter Reference 包含了 Core Image 提供的圖像濾鏡的完整列表,以及用法示例。

如果想要寫更函數(shù)式風(fēng)格的 Core Image 代碼,可以看看 Florian Kluger 在 objccn.io 話題 #16 里的文章