iOS8 Core Image In Swift:更復雜的濾鏡 – iPhone手機開發技術文章 iPhone軟體開發教學課程

iOS8 Core Image In Swift:自動改善圖像以及內置濾鏡的使用

上面那篇文章主要是Core Image的基礎,隻是為瞭說明CIImage、CIFilter、CIContext,以及基礎濾鏡的簡單使用。在上一篇中幾乎沒有對濾鏡進行更復雜的操作,都是直接把inputImage扔給CIFilter而已,而Core Image實際上還能對濾鏡進行更加細粒度的控制,我們在新的工程中對其進行探索。為此,我重新建立瞭一個空的workspace,並把之前所使用的工程添加到這個workspace中,編譯、運行,沒問題的話我們就開始創建新的工程。

通過workspace左下角的Add Files to添加已有的工程:

/

 

 

當添加工程到workspace的時候,記得要把被添加的工程關掉,不然workspacce不能識別。
另外,在流程上這篇也會與上一篇不同,上一篇一開始我就給出瞭代碼,然後先看效果再步步為營,這篇不會在一開始給出代碼。

 

 

 

動態改變濾鏡參數的值

用Single View Application的工程模板建立一個新的工程,在View上放一個UIImageView,還是同樣的frame,同樣的ContentMode設置為Aspect Fit,同樣的關閉Auto Layout以及Size Classes,最後把上個工程中使用的圖片復制過來,在這個工程中同樣使用這張圖。

做完上面這些基礎工作後,我們回到VC中,把showFiltersInConsole方法從上個工程中復制過來,然後在viewDidLoad裡調用,在運行之前我們先看看Core Image有哪些類別,畢竟全部的濾鏡有127種,不可能一一用到的。

類別有很多,而且我們從上一篇中知道瞭濾鏡可以同時屬於不同的類別,除此之外,類別還分為兩大類:

按效果分類:

 

kCICategoryDistortionEffect 扭曲效果,比如bump、旋轉、holekCICategoryGeometryAdjustment 幾何開著調整,比如仿射變換、平切、透視轉換kCICategoryCompositeOperation 合並,比如源覆蓋(source over)、最小化、源在頂(source atop)、色彩混合模式kCICategoryHalftoneEffect Halftone效果,比如screen、line screen、hatchedkCICategoryColorAdjustment 色彩調整,比如伽馬調整、白點調整、曝光kCICategoryColorEffect 色彩效果,比如色調調整、posterizekCICategoryTransition 圖像間轉換,比如dissolve、disintegrate with mask、swipekCICategoryTileEffect 瓦片效果,比如parallelogram、trianglekCICategoryGenerator 圖像生成器,比如stripes、constant color、checkerboardkCICategoryGradient 漸變,比如軸向漸變、仿射漸變、高斯漸變kCICategoryStylize 風格化,比如像素化、水晶化kCICategorySharpen 銳化、發光kCICategoryBlur 模糊,比如高斯模糊、焦點模糊、運動模糊

按使用場景分類:

kCICategoryStillImage 能用於靜態圖像kCICategoryVideo 能用於視頻kCICategoryInterlaced 能用於交錯圖像kCICategoryNonSquarePixels 能用於非矩形像素kCICategoryHighDynamicRange 能用於HDR

這些專業詞太難翻譯瞭,有不準確的地方還望告知

此外還有我們之前用到的kCICategoryBuiltIn。我們把kCICategoryColorAdjustment這個類別下的濾鏡打印出來看看:/

有11個濾鏡,其中有一個CIHueAdjust,這個看名字應該是修改圖像色調的,效果應該會比較明顯,看看它有哪些參數:
/
它的詳細信息裡除瞭我們之前瞭解的inputImage和所屬分類信息以外,多瞭個inputAngle,顯然這是一個輸入參數,而且這個參數也打印的非常清晰,其中包括瞭:參數類型:NSNumber默認值:0kCIAttributeIdentity:雖然這個值大部分情況下與默認值是一樣的,但是它們的含義不一樣,kCIAttributeIdentity表示的含義是這個值被應用到參數上的時候,就表示被應用的參數不會對inputImage造成任何影響最大值:?最小值:-?屬性類型:角度上面的這些參數以及取值對不同的CIFilter來說都不一樣,要具體情況具體分析。瞭解瞭以上情況後,我們就可以開始編碼瞭。首先在VC裡添加上個工程中的常用屬性:

class ViewController: UIViewController {

@IBOutlet var imageView: UIImageView!

@IBOutlet var slider: UISlider!

lazy var originalImage: UIImage = {

return UIImage(named: Image)

}()

 

lazy var context: CIContext = {

return CIContext(options: nil)

}()

 

var filter: CIFilter!

……

與之前工程中不同的是,我多加瞭一個UISlider,Main.storyboard中VC的view像這樣:/

把UIImageView及UISlider的連線與VC中的連接起來,然後我們在viewDidLoad方法裡寫上:

 

override func viewDidLoad() {

super.viewDidLoad()

 

imageView.layer.shadowOpacity = 0.8

imageView.layer.shadowColor = UIColor.blackColor().CGColor

imageView.layer.shadowOffset = CGSize(width: 1, height: 1)

 

slider.maximumValue = Float(M_PI)

slider.minimumValue = Float(-M_PI)

slider.value = 0

slider.addTarget(self, action: valueChanged, forControlEvents: UIControlEvents.ValueChanged)

 

let inputImage = CIImage(image: originalImage)

filter = CIFilter(name: CIHueAdjust)

filter.setValue(inputImage, forKey: kCIInputImageKey)

slider.sendActionsForControlEvents(UIControlEvents.ValueChanged)

 

showFiltersInConsole()

}

imageView的設置同以前一樣,增加點陰影顯得好看多瞭。

接著對slider初始化,在之前我們瞭解到CIHueAdjust濾鏡的inputAngle參數最大值是?,最小值是負?,默認值是0,就用這些值來初始化,然後添加一個當值發生改變時觸發的事件。

初始化filter,由於隻有一個濾鏡,filter對象也可以重用,設置完inputImage後,觸發slider的事件就可以瞭。

valueChanged方法實現:

 

@IBAction func valueChanged() {

filter.setValue(slider.value, forKey: kCIInputAngleKey)

let outputImage = filter.outputImage

let cgImage = context.createCGImage(outputImage, fromRect: outputImage.extent())

imageView.image = UIImage(CGImage: cgImage)

}

filter會在每次觸發這個事件的時候更新inputAngle屬性,同時輸出到imageView上。

 

雖然我並不是在Storyboard裡把slider的valueChanged事件連接到VC的方法上,但是在這裡使用@IBAction也是適當的,這樣可以表明這個方法不是業務邏輯方法,而是一個UI控件觸發的方法。

編譯、運行,應該可以看到效果瞭。

/

 

 

復合濾鏡–老電影效果

在此之前,無論是使用簡單濾鏡,還是能動態修改參數值的濾鏡,都不算復雜,因為我們最多也隻是對一個濾鏡設置點參數而已。可是如果現有的濾鏡沒有想要的效果,或者說單個濾鏡實現不瞭自己想要的效果,就隻能自己處理瞭,其中,最簡單的做法是把多個濾鏡組合起來。Core Image並沒有內置類似於老電影的效果,就是那種影像有點發黃,同時還會帶點黑條、白條之類的,而我們如果要實現這種效果,總體上就像這樣:/

大致過程如下:需要使用CISepiaTone濾鏡,CISepiaTone能使整體顏色偏棕褐色,又有點像復古需要創建隨機噪點圖,很像以前電視機沒信號時顯示的圖像,再通過它生成一張白斑圖濾鏡需要創建另一個隨機噪點圖,然後通過它生成一張黑色磨砂圖濾鏡,就像是一張使用過的黑色砂紙一樣把它們組合起來在開始之前首先要知道一件事,我們已經知道瞭一些簡單的濾鏡,它們隻需要設置inputImage就行瞭;還有一些除瞭inputImage參數外有其他參數的濾鏡,除此之外,還有一些濾鏡不需要任何參數,就是上面提到的隨機噪點圖,另外,有些Core Image濾鏡會生成無限大小的圖,比如CICategoryTileEffect類別下的濾鏡,在渲染它們生成的圖之前,必須先把這些無限大小的圖裁剪一番,你可以通過CICrop濾鏡來完成這一步,也可以通過在一個有限的矩形范圍之類渲染這張圖來達到同樣的效果。然後我們就動手吧。在VC裡添加一個IBAction方法:oldFilmEffect,然後在Storyboard的VC上增加一個按鈕,就叫“老電影”,然後連接到oldFilmEffect方法上,oldFilmEffect方法實現的代碼稍後給出,這裡先描述下詳細步驟,其實通過這些詳細步驟,已經可以自己先實現出來瞭:

應用CISepiaTone濾鏡到原圖上

設置inputImage為原圖設置inputIntensity為1.0

創建白斑圖濾鏡

用CIRandomGenerator生成隨機噪點濾鏡,然後通過imageByCroppingToRect方法對其進行裁剪,在imageByCroppingToRect方法內Core Image隱式的使用瞭CICrop濾鏡。接下來使用CIColorMatrix濾鏡,該濾鏡可以很方便的調整圖片中RGBA各分量的值,其參數設置如下:設置inputImage為CIRandomGenerator生成的隨機噪點圖設置inputRVector、inputGVector和inputBVector為(0,1,0,0)設置inputBiasVector為(0,0,0,0)用CISourceOverCompositing(源覆蓋)濾鏡把前景圖(inputImage)覆蓋在背景圖(inputBackgroundImage)上:設置inputImage為CISepiaTone濾鏡生成的圖設置inputBackgroundImage為白斑圖濾鏡

創建黑色磨砂圖濾鏡

還是先用CIRandomGenerator生成隨機噪點圖,然後用CIAffineTransform濾鏡對其進行處理,其實就是把生成的點放大。參數設置如下:設置inputImage為CIRandomGenerator生成的隨機噪點圖設置inputTransform為x放大1.5倍、y放大25倍,把點拉長、拉厚,但是它們仍然是有顏色的在這裡除瞭使用CIAffineTransform濾鏡外,還有一種替代方法可以達到同樣的效果,同時不用顯式創建CIAffineTransform濾鏡,就是使用CIImage的imageByApplyingTransform:方法。再次用CIColorMatrix濾鏡對顏色進行處理:設置inputImage為CIAffineTransform生成的圖設置inputRVector為(4,0,0,0)設置inputGVector、inputBVector和inputAVector為(0,0,0,0)設置inputBiasVector為(0,1,1,1)現在產生的是一個藍綠色磨砂圖濾鏡,再把CIMinimumComponent濾鏡應用到這個藍綠色磨砂圖濾鏡產生的圖上。CIMinimumComponent濾鏡會使用r、g、b的最小值生成一張灰度圖像。

把所有的濾鏡組合起來

使用CIMultiplyCompositing做最後的組合,參數設置如下:設置inputImage為CISourceOverCompositing濾鏡生成的圖(內含CISepiaTone、白斑圖濾鏡的效果)設置inputBackgroundImage為CIMinimumComponent濾鏡生成的圖(內含黑色磨砂圖濾鏡效果)最後把CIMultiplyCompositing生成出的圖輸出到imageView上,還是以前的方式,先轉成CGImage,再把CGImage轉成UIImage。
有點小長,而且同時用到瞭多個濾鏡,其實想表達的意思並沒有那麼復雜,可以使用kCICategoryBuiltIn把所有的濾鏡打印出來,然後對照著看它們的參數。

這裡是oldFilmEffect方法實現:

@IBAction func oldFilmEffect() {

let inputImage = CIImage(image: originalImage)

// 1.創建CISepiaTone濾鏡

let sepiaToneFilter = CIFilter(name: CISepiaTone)

sepiaToneFilter.setValue(inputImage, forKey: kCIInputImageKey)

sepiaToneFilter.setValue(1, forKey: kCIInputIntensityKey)

// 2.創建白斑圖濾鏡

let whiteSpecksFilter = CIFilter(name: CIColorMatrix)

whiteSpecksFilter.setValue(CIFilter(name: CIRandomGenerator).outputImage.imageByCroppingToRect(inputImage.extent()), forKey: kCIInputImageKey)

whiteSpecksFilter.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: inputRVector)

whiteSpecksFilter.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: inputGVector)

whiteSpecksFilter.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: inputBVector)

whiteSpecksFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: inputBiasVector)

// 3.把CISepiaTone濾鏡和白斑圖濾鏡以源覆蓋(source over)的方式先組合起來

let sourceOverCompositingFilter = CIFilter(name: CISourceOverCompositing)

sourceOverCompositingFilter.setValue(whiteSpecksFilter.outputImage, forKey: kCIInputBackgroundImageKey)

sourceOverCompositingFilter.setValue(sepiaToneFilter.outputImage, forKey: kCIInputImageKey)

// ———上面算是完成瞭一半

// 4.用CIAffineTransform濾鏡先對隨機噪點圖進行處理

let affineTransformFilter = CIFilter(name: CIAffineTransform)

affineTransformFilter.setValue(CIFilter(name: CIRandomGenerator).outputImage.imageByCroppingToRect(inputImage.extent()), forKey: kCIInputImageKey

affineTransformFilter.setValue(NSValue(CGAffineTransform: CGAffineTransformMakeScale(1.5, 25)), forKey: kCIInputTransformKey)

// 5.創建藍綠色磨砂圖濾鏡

let darkScratchesFilter = CIFilter(name: CIColorMatrix)

darkScratchesFilter.setValue(affineTransformFilter.outputImage, forKey: kCIInputImageKey)

darkScratchesFilter.setValue(CIVector(x: 4, y: 0, z: 0, w: 0), forKey: inputRVector)

darkScratchesFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: inputGVector)

darkScratchesFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: inputBVector)

darkScratchesFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: inputAVector)

darkScratchesFilter.setValue(CIVector(x: 0, y: 1, z: 1, w: 1), forKey: inputBiasVector)

// 6.用CIMinimumComponent濾鏡把藍綠色磨砂圖濾鏡處理成黑色磨砂圖濾鏡

let minimumComponentFilter = CIFilter(name: CIMinimumComponent)

minimumComponentFilter.setValue(darkScratchesFilter.outputImage, forKey: kCIInputImageKey)

// ———上面算是基本完成瞭

// 7.最終組合在一起

let multiplyCompositingFilter = CIFilter(name: CIMultiplyCompositing)

multiplyCompositingFilter.setValue(minimumComponentFilter.outputImage, forKey: kCIInputBackgroundImageKey)

multiplyCompositingFilter.setValue(sourceOverCompositingFilter.outputImage, forKey: kCIInputImageKey)

// 8.最後輸出

let outputImage = multiplyCompositingFilter.outputImage

let cgImage = context.createCGImage(outputImage, fromRect: outputImage.extent())

imageView.image = UIImage(CGImage: cgImage)

}

以上就是一個老電影濾鏡的“配方”瞭。編譯、運行,顯示效果如下:
/

子類化CIFilter

有時可能會對一些圖片應用同樣的濾鏡,我們可能會像上面那樣把一連串的濾鏡組合起來,以達到自己想要的效果,那麼我們就可以把這些操作封裝到一個CIFilter的子類中,然後在多個地方反復使用,就像使用Core Image預置的濾鏡那樣。CICategoryColorEffect類別中有個CIColorInvert濾鏡,這個濾鏡提供反色功能,實現起來並不復雜,因為我們並不是做一個真正的自定義濾鏡,而是在裡面對Core Image已有濾鏡的封裝,我們可以為子類定義一些輸入參數,參照蘋果對CIFilter子類的命名約定,輸入參數必須用input作前綴,如inputImage,然後再重寫outputImage方法就行瞭。
現在我們回到Xcode中,做以下幾件事:新建一個Cocoa Touch Class,類名就叫CIColorInvert,繼承自CIFilter。添加一個inputImage參數,類型自然是CIImage,由外界賦值。重寫outputImage屬性的getter。如果你之前寫過Objective-C,應該對屬性有這樣一個印象:子類要重寫父類的屬性,隻需要單獨寫個getter或setter方法就行瞭,但在Swift裡,不能通過這種方式重寫屬性,必須連getter、setter(如果父類的屬性支持setter的話)一起重寫。在我們的例子中outputImage在CIFilter中隻是一個getter屬性,在outputImage裡通過CIColorMatrix濾鏡對圖像的各向量進行調整。CIColorInvert類實現:

class CIColorInvert: CIFilter {

var inputImage: CIImage!

 

override var outputImage: CIImage! {

get {

return CIFilter(name: CIColorMatrix, withInputParameters: [

kCIInputImageKey : inputImage,

inputRVector : CIVector(x: -1, y: 0, z: 0),

inputGVector : CIVector(x: 0, y: -1, z: 0),

inputBVector : CIVector(x: 0, y: 0, z: -1),

inputBiasVector : CIVector(x: 1, y: 1, z: 1),

]).outputImage

}

}

}

然後在Storyboard的VC上增加一個按鈕“反色”,連接到VC的colorInvert方法上,colorInvert方法實現如下:

@IBAction func colorInvert() {

let colorInvertFilter = CIColorInvert()

colorInvertFilter.inputImage = CIImage(image: imageView.image)

let outputImage = colorInvertFilter.outputImage

let cgImage = context.createCGImage(outputImage, fromRect: outputImage.extent())

imageView.image = UIImage(CGImage: cgImage)

}

這樣一下,一個對Core Image預置濾鏡的簡單封裝就完成瞭,每一個濾鏡的效果就像是一張配方,CIFilter就是裝有配方的瓶子,所以子類化CIFilter並不算自定義濾鏡,但是從iOS 8開始,Core Image是支持真正的自定義濾鏡的,自定義的濾鏡被稱之為內核(CIKernel),在WWDC視頻裡對其有50分鐘的介紹:https://developer.apple.com/videos/wwdc/2014/#515。運行後反色的效果,再次點擊反色按鈕後顯示原圖:/

簡單摳圖並更換背景

利用Core Image預置的濾鏡能滿足大部分使用場景,我們做一個簡單的替換背景的功能。為瞭方便測試,加入兩張新的圖://
點擊圖片可以打開原圖。將兩張圖添加到當前工程中,然後把ViewController的屬性originalImage改為返回左邊的圖:

……

lazy var originalImage: UIImage = {

return UIImage(named: Image2)

}()

……

然後在Storyboard的VC上增加兩個按鈕:一個用於顯示原圖:

@IBAction func showOriginalImage() {

self.imageView.image = originalImage

}

另一個按鈕就叫“更換背景”,連接到VC的IBAction方法replaceBackground上。我們先看要做的事情:消除深綠色組合圖片

消除深綠色

就像Photoshop的魔法棒一樣,Core Image也有類似的濾鏡,但是沒有那麼簡單粗暴,使用起來很麻煩。在Core Image裡,我們為瞭消除某種顏色,需要使用CIColorCube濾鏡,而CIColorCube濾鏡需要一張cube映射表,這張表其實就是張顏色表(3D顏色查找表),把你想消除的顏色的alpha值設置為0,其他的顏色不變,Core Image將會把圖像數據上的顏色映射為表中的顏色,以此來達到消除某種顏色的目的。CIColorCube的這張表默認不會對inputImage作任何處理,但在我們這裡要將所有的深綠色幹掉,所以需要自己來建立這張表。
我們要消除的“深綠色”並不隻是視覺上的一種顏色,而是顏色的范圍,最直接的方法是將RGBA轉成HSV(Hue,Saturation,Value),在HSV的格式下,顏色是圍繞圓柱體中軸的角度來表現的,在這種表現方法下,你能把顏色的范圍想象成連在一起的扇形,然後直接把該塊區域幹掉(alpha設為0),這就表示我們實際上需要指定顏色區域的范圍——圍繞圓柱體中軸線的最小角度以及最大角度,此范圍內的顏色alpha設為0。最後,Cube Map表中的數據必須乘以alpha,所以創建Cube Map的最後一步是把RGB值乘以你剛剛計算出來的alpha值:如果是想要消除的顏色,乘出來就是0,反之則是1。這是一張代表顏色值區域的HSV(Hue值)圖:/
可以看到如果是純綠色,其取值是120度,藍色是240度,我們這種情況取值大概在60到90左右(偏綠一點),在這個網站上可以看到更詳細的RGB顏色對應的HSV值。那麼接下來我們就準備創建Cube Map表,創建Cube Map表的方法在蘋果官方示例中可以找到,是C語言實現的,為瞭方便起見,我們就直接創建一個C文件來包含這些代碼。在工程裡選擇新建一個.c文件,我取名為CubeMap.c,在創建這個.c文件的時候,不出意外的話Xcode會問你是否需要創建一個橋接頭文件(xxxx.Bridging-Header.H),選擇是,Xcode會創建該文件,並自動把其路徑放到編譯選項的Objective-C Bridging Header中。如果你要自己添加這個文件,並且需要手動修改Objective-C Bridging Header的編譯選項,可以看這裡。.c文件搞完以後,即把蘋果官方示例中的代碼(以下代碼)添加進去:

struct CubeMap {

int length;

float dimension;

float *data;

};

 

struct CubeMap createCubeMap(float minHueAngle, float maxHueAngle) {

const unsigned int size = 64;

struct CubeMap map;

map.length = size * size * size * sizeof (float) * 4;

map.dimension = size;

float *cubeData = (float *)malloc (map.length);

float rgb[3], hsv[3], *c = cubeData;

 

for (int z = 0; z < size; z++){

rgb[2] = ((double)z)/(size-1); // Blue value

for (int y = 0; y < size; y++){

rgb[1] = ((double)y)/(size-1); // Green value

for (int x = 0; x < size; x ++){

rgb[0] = ((double)x)/(size-1); // Red value

rgbToHSV(rgb,hsv);

// Use the hue value to determine which to make transparent

// The minimum and maximum hue angle depends on

// the color you want to remove

float alpha = (hsv[0] > minHueAngle && hsv[0] < maxHueAngle) ? 0.0f: 1.0f;

// Calculate premultiplied alpha values for the cube

c[0] = rgb[0] * alpha;

c[1] = rgb[1] * alpha;

c[2] = rgb[2] * alpha;

c[3] = alpha;

c += 4; // advance our pointer into memory for the next color value

}

}

}

map.data = cubeData;

return map;

}

我將這個方法稍微改造瞭一下,選擇一個結構體,因為外面要用到length和dimension。蘋果沒有提供rgbToHSV方法的實現,可以用我找到的這個:

void rgbToHSV(float *rgb, float *hsv) {

float min, max, delta;

float r = rgb[0], g = rgb[1], b = rgb[2];

float *h = hsv, *s = hsv + 1, *v = hsv + 2;

 

min = fmin(fmin(r, g), b );

max = fmax(fmax(r, g), b );

*v = max;

delta = max – min;

if( max != 0 )

*s = delta / max;

else {

*s = 0;

*h = -1;

return;

}

if( r == max )

*h = ( g – b ) / delta;

else if( g == max )

*h = 2 + ( b – r ) / delta;

else

*h = 4 + ( r – g ) / delta;

*h *= 60;

if( *h < 0 )

*h += 360;

}

我在.c文件中導入的庫:

#include

#include

#include

對瞭,如果那個橋接文件裡沒有導入這個.c文件的話是不行的,Swift的類會找不到這裡面的方法。

// ComplexFilters-Bridging-Header.h

// Use this file to import your target's public headers that you would like to expose to Swift.

//

 

#import CubeMap.c

組合圖片

VC中的replaceBackground方法隻需要做三件事:
創建Cube Map表創建CIColorCube濾鏡並使用Cube Map用CISourceOverCompositing濾鏡將處理過的人物圖像和未處理過的背景圖粘合起來方法實現如下:

@IBAction func replaceBackground() {

let cubeMap = createCubeMap(60,90)

let data = NSData(bytesNoCopy: cubeMap.data, length: Int(cubeMap.length), freeWhenDone: true)

let colorCubeFilter = CIFilter(name: CIColorCube)

 

colorCubeFilter.setValue(cubeMap.dimension, forKey: inputCubeDimension)

colorCubeFilter.setValue(data, forKey: inputCubeData)

colorCubeFilter.setValue(CIImage(image: imageView.image), forKey: kCIInputImageKey)

var outputImage = colorCubeFilter.outputImage

 

let sourceOverCompositingFilter = CIFilter(name: CISourceOverCompositing)

sourceOverCompositingFilter.setValue(outputImage, forKey: kCIInputImageKey)

sourceOverCompositingFilter.setValue(CIImage(image: UIImage(named: background)), forKey: kCIInputBackgroundImageKey)

 

outputImage = sourceOverCompositingFilter.outputImage

let cgImage = context.createCGImage(outputImage, fromRect: outputImage.extent())

imageView.image = UIImage(CGImage: cgImage)

}

參數設置都還比較簡單,CISourceOverCompositing濾鏡目前已經使用過多次瞭,並沒有什麼復雜的。編譯、運行,可以分兩次執行,先看消除深綠色的效果,再看最後使用CISourceOverCompositing濾鏡組合圖片之後的效果:/

GitHub下載地址

我在GitHub上會保持更新。

 

發佈留言