iOS濾鏡 圖片處理

來源:互聯網
上載者:User

iOS濾鏡 圖片處理
摘要:本文結合執行個體詳解了OS X和iOS影像處理架構Core Image的使用,如何通過Core Image來建立和使用iOS的內建濾鏡,非常適合初學者學習。雖然範例程式碼是用Swift寫的iOS程式,不過實現概念很容易轉換到Objective-C和OS X。

這篇文章會為初學者介紹一下Core Image,一個OS X和iOS的影像處理架構。

如果你想跟著本文中的代碼學習,你可以在GitHub上下載樣本工程。樣本工程是一個iOS應用程式,列出了系統提供的大量映像濾鏡以供選擇,並提供了一個使用者介面用來調整參數並觀察效果。

雖然範例程式碼是用Swift寫的iOS程式,不過實現概念很容易轉換到Objective-C和OS X。

基本概念

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

一個濾鏡是一個對象,有很多輸入和輸出,並執行一些變換。例如,模糊濾鏡可能需要輸入映像和一個模糊半徑來產生適當的模糊後的輸出映像。

一個濾鏡圖表是一個連結在一起的濾鏡網路(無迴路有向圖),使得一個濾鏡的輸出可以是另一個濾鏡的輸入。以這種方式,可以實現精心製作的效果。我們將在下面看到如何串連濾鏡來建立一個複古的拍照效果。

熟悉Core Image API

有了上述的這些概念,我們可以開始探索Core Image的映像濾鏡細節了。

Core Image架構

Core Image有一個外掛程式架構,這意味著它允許使用者編寫自訂的濾鏡並與系統提供的濾鏡整合來擴充其功能。我們在這篇文章中不會用到Core Image的可擴充性;我提到它只是因為它影響到了架構的API。

Core Image 是用來最大化利用其所運行之上的硬體的。每個濾鏡實際上的實現,即核心,是由一個GLSL(即OpenGL的著色語言)的子集來書寫的。當多個濾鏡串連成一個濾鏡圖表,Core Image便把核心串在一起來構建一個可在GPU上啟動並執行高效程式。

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

為了完成工作,Core Image需要一個稱為上下文(context)的對象。這個上下文是架構真正工作的地方,它需要分配必要的記憶體,並編譯和運行濾鏡核心來執行影像處理。建立一個上下文是非常昂貴的,所以你會經常想建立一個反覆使用的上下文。接下來我們將看到如何建立一個上下文。

查詢可用的濾鏡

Core Image濾鏡是按名字建立的。要獲得系統濾鏡的列表,我們要向Core Image的kCICategoryBuiltIn類別請求得到濾鏡的名字:

letfilterNames=CIFilter.filterNamesInCategory(kCICategoryBuiltIn)as[String]

iOS上可用的濾鏡列表非常接近於OS X上可用濾鏡的一個子集。在OS X上有169個內建濾鏡,在iOS上有127個。

通過名字建立一個濾鏡

現在,我們有了可用濾鏡的列表,我們就可以建立和使用濾鏡了。例如,要建立一個高斯模糊濾鏡,我們傳給CIFilter初始化方法相應的名稱就可以了:

letblurFilter=CIFilter(named:"CIGaussianBlur")

設定濾鏡參數

由於Core Image的外掛程式結構,大多數濾鏡屬性並不是直接設定的,而是通過索引值編碼(KVC)設定。例如,要設定模糊濾鏡的模糊半徑,我們使用KVC來設定inputRadius屬性:

blurFilter.setValue(10.0forKey:"inputRadius")

由於這種方法需要AnyObject? (即Objective-C裡的id)作為其參數值,它不是型別安全的。因此,設定濾鏡參數需要謹慎一些,確保你傳值的類型是正確的。

查詢濾鏡屬性

為了知道一個濾鏡提供什麼樣的輸入和輸出參數,我們就可以分別擷取inputKeys和outputKeys數組。它們都返回NSString的數組。

要擷取每個參數的詳細資料,我們可以看看由濾鏡提供的attributes字典。每個輸入和輸出參數名映射到它自己的字典裡,描述了它是什麼樣的參數,如果有的話還會給出它的最大值和最小值。例如,下面是 CIColorControls濾鏡對應的inputBrightness參數字典:

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

對於數值參數,該字典會包含 kCIAttributeSliderMin 和 kCIAttributeSliderMax 鍵,來限制期望的輸入欄位。大多數參數還包含一個 kCIAttributeDefault 關鍵字,映射到該參數的預設值。

圖片濾鏡實戰

映像濾鏡的工作由三部分組成:構建和配置濾鏡圖表,發送等待濾鏡處理的映像,得到濾鏡處理後的映像。下面的部分對此進行了詳細描述。

構建一個濾鏡圖表

構建一個濾鏡圖表由這幾個部分組成:執行個體化我們需要的濾鏡,設定它們的參數,把它們串連起來以便該映像資料按順序傳過每個濾鏡。

在本節中,我們將建立一個用來製作 19 世紀錫版照風格映像的濾鏡圖表。我們將兩個效果鏈在一起來達到這種效果:同時去飽和以及染色調的黑白濾鏡,和一個暗角濾鏡來建立一個有陰影製作效果的加框圖片。

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

一旦達到了我們滿意的效果,我們可以重新在代碼裡建立濾鏡圖表:

letsepiaColor=CIColor(red:0.76,green:0.65,blue:0.54)letmonochromeFilter=CIFilter(name:"CIColorMonochrome", withInputParameters:["inputColor":sepiaColor,"inputIntensity":1.0])monochromeFilter.setValue(inputImage,forKey:"inputImage") letvignetteFilter=CIFilter(name:"CIVignette",withInputParameters:["inputRadius":1.75,"inputIntensity":1.0]) vignetteFilter.setValue(monochromeFilter.outputImage,forKey:"inputImage")letoutputImage=vignetteFilter.outputImage

需要注意的是黑白濾鏡的輸出映像變為暗角濾鏡的輸入映像。這將導致暗角效果要應用到黑白映像上。還要注意的是,我們可以在初始化中指定參數,而不一定需要用KVC單獨設定它們。

建立輸入映像

Core Image濾鏡要求其輸入映像是CIImage類型。而對於iOS的程式員來說這可能會有一點不尋常,因為他們更習慣用UIImage,但這個區別是值得的。一個CIImage執行個體實際上比UIImage更全面,因為CIImage可以無限大。當然,我們不能儲存無限的映像在記憶體中,但在概念上,這意味著你可以從2D平面上的任意地區擷取映像資料,並得到一個有意義的結果。

所有我們在本文中使用的映像都是有限的,而且也可以很容易從一個UIImage來建立一個CIImage。事實上,這隻需要一行代碼:

letinputImage=CIImage(image:uiImage)

也有很方便的初始化方法直接從映像資料或檔案URL來建立CIImage。

一旦我們有了一個CIImage,我們就可以通過設定濾鏡的inputImage參數來將其設定為濾鏡的輸入映像:

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

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

濾鏡都有一個名為outputImage的屬性。正如你可能已經猜到的一樣,它是 CIImage 類型的。那麼,我們如何?從一個CIImage建立UIImage這樣一個反向操作?好了,雖然我們到此已經花了所有的時間建立一個濾鏡圖表,現在是調用CIContext的力量來實際的做映像濾鏡處理工作的時候了。

建立一個上下文最簡單的方法是給它的構造方法傳一個nil字典:

letciContext=CIContext(options:nil)

為了得到一個濾鏡處理過的映像,我們需要CIContext從輸出映像的一個矩形內建立一個CGImage,傳入輸入映像的範圍(bounds):

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

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

現在,我們可以從這個新建立的CGImage來建立一個UIImage了:

letuiImage=UIImage(CGImage:cgImage)

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

用OpenGL來提高效能

用CPU來繪製一個CGImage是非常耗時和浪費的,它只將結果回傳給UIKit來做合成。我們更希望能夠在螢幕上繪製應用濾鏡後的映像,而不必去Core Graphics裡繞一圈。幸運的是,由於OpenGL和Core Image的可互通性,我們可以這麼做。

要OpenGL上下文和Core Image上下文之間共用資源,我們需要用一個稍微不同的方式來建立我們的 CIContext:

 leteaglContext=EAGLContext(API:.OpenGLES2)letciContext=CIContext(EAGLContext:context)

在這裡,我們用OpenGL ES 2.0的功能集建立了一個EAGLContext。這個GL上下文可以用作一個GLKView的背襯上下文或用來繪製成一個CAEAGLLayer。範例程式碼使用這種技術來有效地繪製映像。

當一個CIContext具有了關聯GL的上下文,濾鏡處理後的映像就可用OpenGL來繪製,像如下這樣調用方法:

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

與以前一樣,fromRect 參數是用濾鏡處理後的映像的座標空間來繪製的映像的一部分。這個inRect 參數是GL內容相關的座標空間的矩形應用到需要繪製映像上。如果你想保持映像的長寬比,你可能需要做一些數學計算來得到適當的inRect。

強制在CPU上做濾鏡操作

只要有可能,Core Image將在GPU上執行濾鏡操作。然而,它確實有復原到CPU上執行的可能。濾鏡操作在CPU上完成可具有更好的精確度,因為GPU經常在浮點計算上以失真換得更快的速度。在建立一個上下文時,你可以通過設定kCIContextUseSoftwareRenderer關鍵字的值為true來強制Core Image在CPU上運行。

你可以通過在Xcode中設定計劃配置(scheme configuration)裡的CI_PRINT_TREE環境變數為1來決定用CPU 還是GPU來渲染。這將導致每次一個濾鏡處理映像被渲染的時候Core Image都會列印診斷資訊。此設定用來檢查合成映像濾鏡樹也很有用。

樣本應用程式清單

本文的範例程式碼是一個iPhone應用程式,展示了iOS裡大量的各式Core Image映像濾鏡。

為濾鏡參數建立一個GUI

為了儘可能多的示範各種濾鏡,應用程式範例利用了Core Image的內省特點產生了一個介面,用於控制它支援的濾鏡參數:

應用程式範例只限於單一的映像輸入以及零個或多個數值輸入的濾鏡。也有一些有趣的濾鏡不屬於這一類(特別是那些合成和轉換濾鏡)。即便如此,該應用程式仍然很好的概述了Core Image支援的功能。

對於每個濾鏡的輸入參數,都有一個滑動條可以用於配置參數的最小值和最大值,其值被設定為預設值。當滑動條的值發生變化時,它把改變後的值傳給它的 delegate,一個持有CIFilter引用的 UIImageView子類。

使用內建的照片濾鏡

除了許多其他的內建濾鏡,應用程式範例還展示了iOS 7中引入的照片濾鏡。這些濾鏡沒有我們可以調整的參數,但它們值得被囊括進來,因為它們展示了如何在iOS中類比照片應用程式的效果:

結論

這篇文章簡要介紹了Core Image這個高效能的影像處理架構。我們一直在試圖在如此簡短的形式內儘可能多的展示這個架構的功能。你現在已經學會了如何執行個體化和串聯Core Image的濾鏡,在濾鏡圖表傳入和輸出映像,以及調整參數來獲得想要的結果。你還學習了如何訪問系統提供的照片濾鏡,用以類比在iOS上的照片應用程式的行為。

現在你知道了足夠多的東西來寫你自己的相片編輯應用程式了。隨著更多的一些探索,你就可以寫自己的濾鏡了,利用你的Mac或iPhone的神奇的力量來執行以前無法想象的效果。快去動手做吧!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.