iOS Core Image 复杂的滤镜
在上一篇中幾乎沒有對濾鏡進(jìn)行更復(fù)雜的操作,都是直接把inputImage扔給CIFilter而已,而Core Image實際上還能對濾鏡進(jìn)行更加細(xì)粒度的控制,我們在新的工程中對其進(jìn)行探索。為此,我重新建立了一個空的workspace,并把之前所使用的工程添加到這個workspace中,編譯、運行,沒問題的話我們就開始創(chuàng)建新的工程。
通過workspace左下角的Add Files to添加已有的工程文件(xx.xcodeproj):
| 當(dāng)添加工程到workspace的時候,記得要把被添加的工程關(guān)掉,不然workspacce不能識別。 另外,在流程上這篇也會與上一篇不同,上一篇一開始我就給出了代碼,然后先看效果再步步為營,這篇不會在一開始給出代碼。 |
動態(tài)改變?yōu)V鏡參數(shù)的值
用Single View Application的工程模板建立一個新的工程,在View上放一個UIImageView,還是同樣的frame,同樣的ContentMode設(shè)置為Aspect Fit,同樣的關(guān)閉Auto Layout以及Size Classes,最后把上個工程中使用的圖片復(fù)制過來,在這個工程中同樣使用這張圖。
做完上面這些基礎(chǔ)工作后,我們回到VC中,把showFiltersInConsole方法從上個工程中復(fù)制過來,然后在viewDidLoad里調(diào)用,在運行之前我們先看看Core Image有哪些類別,畢竟全部的濾鏡有127種,不可能一一用到的。
類別有很多,而且我們從上一篇中知道了濾鏡可以同時屬于不同的類別,除此之外,類別還分為兩大類:
按效果分類:
- kCICategoryDistortionEffect 扭曲效果,比如bump、旋轉(zhuǎn)、hole
- kCICategoryGeometryAdjustment 幾何開著調(diào)整,比如仿射變換、平切、透視轉(zhuǎn)換
- kCICategoryCompositeOperation 合并,比如源覆蓋(source over)、最小化、源在頂(source atop)、色彩混合模式
- kCICategoryHalftoneEffect Halftone效果,比如screen、line screen、hatched
- kCICategoryColorAdjustment 色彩調(diào)整,比如伽馬調(diào)整、白點調(diào)整、曝光
- kCICategoryColorEffect 色彩效果,比如色調(diào)調(diào)整、posterize
- kCICategoryTransition 圖像間轉(zhuǎn)換,比如dissolve、disintegrate with mask、swipe
- kCICategoryTileEffect 瓦片效果,比如parallelogram、triangle
- kCICategoryGenerator 圖像生成器,比如stripes、constant color、checkerboard
- kCICategoryGradient 漸變,比如軸向漸變、仿射漸變、高斯?jié)u變
- kCICategoryStylize 風(fēng)格化,比如像素化、水晶化
- kCICategorySharpen 銳化、發(fā)光
- kCICategoryBlur 模糊,比如高斯模糊、焦點模糊、運動模糊
按使用場景分類:
- kCICategoryStillImage 能用于靜態(tài)圖像
- kCICategoryVideo 能用于視頻
- kCICategoryInterlaced 能用于交錯圖像
- kCICategoryNonSquarePixels 能用于非矩形像素
- kCICategoryHighDynamicRange 能用于HDR
| 這些專業(yè)詞太難翻譯了,有不準(zhǔn)確的地方還望告知 |
此外還有我們之前用到的kCICategoryBuiltIn。 我們把kCICategoryColorAdjustment這個類別下的濾鏡打印出來看看:
有11個濾鏡,其中有一個CIHueAdjust,這個看名字應(yīng)該是修改圖像色調(diào)的,效果應(yīng)該會比較明顯,看看它有哪些參數(shù):
它的詳細(xì)信息里除了我們之前了解的inputImage和所屬分類信息以外,多了個inputAngle,顯然這是一個輸入?yún)?shù),而且這個參數(shù)也打印的非常清晰,其中包括了:
- 參數(shù)類型:NSNumber
- 默認(rèn)值:0
- kCIAttributeIdentity:雖然這個值大部分情況下與默認(rèn)值是一樣的,但是它們的含義不一樣,kCIAttributeIdentity表示的含義是這個值被應(yīng)用到參數(shù)上的時候,就表示被應(yīng)用的參數(shù)不會對inputImage造成任何影響
- 最大值:?
- 最小值:-?
- 屬性類型:角度
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的設(shè)置同以前一樣,增加點陰影顯得好看多了。接著對slider初始化,在之前我們了解到CIHueAdjust濾鏡的inputAngle參數(shù)最大值是?,最小值是負(fù)?,默認(rèn)值是0,就用這些值來初始化,然后添加一個當(dāng)值發(fā)生改變時觸發(fā)的事件。
初始化filter,由于只有一個濾鏡,filter對象也可以重用,設(shè)置完inputImage后,觸發(fā)slider的事件就可以了。
valueChanged方法實現(xiàn):
@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會在每次觸發(fā)這個事件的時候更新inputAngle屬性,同時輸出到imageView上。
雖然我并不是在Storyboard里把slider的valueChanged事件連接到VC的方法上,但是在這里使用@IBAction也是適當(dāng)?shù)?#xff0c;這樣可以表明這個方法不是業(yè)務(wù)邏輯方法,而是一個UI控件觸發(fā)的方法。
編譯、運行,應(yīng)該可以看到效果了。
復(fù)合濾鏡--老電影效果
在此之前,無論是使用簡單濾鏡,還是能動態(tài)修改參數(shù)值的濾鏡,都不算復(fù)雜,因為我們最多也只是對一個濾鏡設(shè)置點參數(shù)而已。可是如果現(xiàn)有的濾鏡沒有想要的效果,或者說單個濾鏡實現(xiàn)不了自己想要的效果,就只能自己處理了,其中,最簡單的做法是把多個濾鏡組合起來。 Core Image并沒有內(nèi)置類似于老電影的效果,就是那種影像有點發(fā)黃,同時還會帶點黑條、白條之類的,而我們?nèi)绻獙崿F(xiàn)這種效果,總體上就像這樣:大致過程如下:
- 需要使用CISepiaTone濾鏡,CISepiaTone能使整體顏色偏棕褐色,又有點像復(fù)古
- 需要創(chuàng)建隨機噪點圖,很像以前電視機沒信號時顯示的圖像,再通過它生成一張白斑圖濾鏡
- 需要創(chuàng)建另一個隨機噪點圖,然后通過它生成一張黑色磨砂圖濾鏡,就像是一張使用過的黑色砂紙一樣
- 把它們組合起來
應(yīng)用CISepiaTone濾鏡到原圖上
- 設(shè)置inputImage為原圖
- 設(shè)置inputIntensity為1.0
創(chuàng)建白斑圖濾鏡
用CIRandomGenerator生成隨機噪點濾鏡,然后通過imageByCroppingToRect方法對其進(jìn)行裁剪,在imageByCroppingToRect方法內(nèi)Core Image隱式的使用了CICrop濾鏡。 接下來使用CIColorMatrix濾鏡,該濾鏡可以很方便的調(diào)整圖片中RGBA各分量的值,其參數(shù)設(shè)置如下:- 設(shè)置inputImage為CIRandomGenerator生成的隨機噪點圖
- 設(shè)置inputRVector、inputGVector和inputBVector為(0,1,0,0)
- 設(shè)置inputBiasVector為(0,0,0,0)
- 設(shè)置inputImage為CISepiaTone濾鏡生成的圖
- 設(shè)置inputBackgroundImage為白斑圖濾鏡
創(chuàng)建黑色磨砂圖濾鏡
還是先用CIRandomGenerator生成隨機噪點圖,然后用CIAffineTransform濾鏡對其進(jìn)行處理,其實就是把生成的點放大。參數(shù)設(shè)置如下:- 設(shè)置inputImage為CIRandomGenerator生成的隨機噪點圖
- 設(shè)置inputTransform為x放大1.5倍、y放大25倍,把點拉長、拉厚,但是它們?nèi)匀皇怯蓄伾?/li>
- 設(shè)置inputImage為CIAffineTransform生成的圖
- 設(shè)置inputRVector為(4,0,0,0)
- 設(shè)置inputGVector、inputBVector和inputAVector為(0,0,0,0)
- 設(shè)置inputBiasVector為(0,1,1,1)
把所有的濾鏡組合起來
使用CIMultiplyCompositing做最后的組合,參數(shù)設(shè)置如下:- 設(shè)置inputImage為CISourceOverCompositing濾鏡生成的圖(內(nèi)含CISepiaTone、白斑圖濾鏡的效果)
- 設(shè)置inputBackgroundImage為CIMinimumComponent濾鏡生成的圖(內(nèi)含黑色磨砂圖濾鏡效果)
有點小長,而且同時用到了多個濾鏡,其實想表達(dá)的意思并沒有那么復(fù)雜,可以使用kCICategoryBuiltIn把所有的濾鏡打印出來,然后對照著看它們的參數(shù)。
這里是oldFilmEffect方法實現(xiàn):
@IBAction?func?oldFilmEffect() {
? ??let?inputImage =?CIImage(image:?originalImage)
? ??// 1.創(chuàng)建CISepiaTone濾鏡
? ??let?sepiaToneFilter =?CIFilter(name:?"CISepiaTone")
? ? sepiaToneFilter.setValue(inputImage, forKey:?kCIInputImageKey)
? ? sepiaToneFilter.setValue(1, forKey:?kCIInputIntensityKey)
? ??// 2.創(chuàng)建白斑圖濾鏡
? ??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濾鏡先對隨機噪點圖進(jìn)行處理
? ??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.創(chuàng)建藍(lán)綠色磨砂圖濾鏡
? ??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濾鏡把藍(lán)綠色磨砂圖濾鏡處理成黑色磨砂圖濾鏡
? ??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
有時可能會對一些圖片應(yīng)用同樣的濾鏡,我們可能會像上面那樣把一連串的濾鏡組合起來,以達(dá)到自己想要的效果,那么我們就可以把這些操作封裝到一個CIFilter的子類中,然后在多個地方反復(fù)使用,就像使用Core Image預(yù)置的濾鏡那樣。 CICategoryColorEffect類別中有個CIColorInvert濾鏡,這個濾鏡提供反色功能,實現(xiàn)起來并不復(fù)雜,因為我們并不是做一個真正的自定義濾鏡,而是在里面對Core Image已有濾鏡的封裝,我們可以為子類定義一些輸入?yún)?shù),參照蘋果對CIFilter子類的命名約定,輸入?yún)?shù)必須用input作前綴,如inputImage,然后再重寫outputImage方法就行了。現(xiàn)在我們回到Xcode中,做以下幾件事:
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方法實現(xiàn)如下:@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預(yù)置濾鏡的簡單封裝就完成了,每一個濾鏡的效果就像是一張配方,CIFilter就是裝有配方的瓶子,所以子類化CIFilter并不算自定義濾鏡,但是從iOS 8開始,Core Image是支持真正的自定義濾鏡的,自定義的濾鏡被稱之為內(nèi)核(CIKernel),在WWDC視頻里對其有50分鐘的介紹:https://developer.apple.com/videos/wwdc/2014/#515。 運行后反色的效果,再次點擊反色按鈕后顯示原圖:簡單摳圖并更換背景
利用Core Image預(yù)置的濾鏡能滿足大部分使用場景,我們做一個簡單的替換背景的功能。 為了方便測試,加入兩張新的圖:點擊圖片可以打開原圖。 將兩張圖添加到當(dāng)前工程中,然后把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里,我們?yōu)榱讼撤N顏色,需要使用CIColorCube濾鏡,而CIColorCube濾鏡需要一張cube映射表,這張表其實就是張顏色表(3D顏色查找表),把你想消除的顏色的alpha值設(shè)置為0,其他的顏色不變,Core Image將會把圖像數(shù)據(jù)上的顏色映射為表中的顏色,以此來達(dá)到消除某種顏色的目的。 CIColorCube的這張表默認(rèn)不會對inputImage作任何處理,但在我們這里要將所有的深綠色干掉,所以需要自己來建立這張表。我們要消除的“深綠色”并不只是視覺上的一種顏色,而是顏色的范圍,最直接的方法是將RGBA轉(zhuǎn)成HSV(Hue,Saturation,Value),在HSV的格式下,顏色是圍繞圓柱體中軸的角度來表現(xiàn)的,在這種表現(xiàn)方法下,你能把顏色的范圍想象成連在一起的扇形,然后直接把該塊區(qū)域干掉(alpha設(shè)為0),這就表示我們實際上需要指定顏色區(qū)域的范圍------圍繞圓柱體中軸線的最小角度以及最大角度,此范圍內(nèi)的顏色alpha設(shè)為0。最后,Cube Map表中的數(shù)據(jù)必須乘以alpha,所以創(chuàng)建Cube Map的最后一步是把RGB值乘以你剛剛計算出來的alpha值:如果是想要消除的顏色,乘出來就是0,反之則不變。這是一張代表顏色值區(qū)域的HSV(Hue值)圖:
可以看到如果是純綠色,其取值是120度,藍(lán)色是240度,我們這種情況取值大概在60到90左右(偏綠一點),在這個網(wǎng)站上可以看到更詳細(xì)的RGB顏色對應(yīng)的HSV值。 那么接下來我們就準(zhǔn)備創(chuàng)建Cube Map表,創(chuàng)建Cube Map表的方法在蘋果官方示例中可以找到,是C語言實現(xiàn)的,為了方便起見,我們就直接創(chuàng)建一個C文件來包含這些代碼。 在工程里選擇新建一個.c文件,我取名為CubeMap.c,在創(chuàng)建這個.c文件的時候,不出意外的話Xcode會問你是否需要創(chuàng)建一個橋接頭文件(xxxx.Bridging-Header.H),選擇是,Xcode會創(chuàng)建該文件,并自動把其路徑放到編譯選項的Objective-C Bridging Header中。如果你要自己添加這個文件,并且需要手動修改Objective-C Bridging Header的編譯選項,可以看這里。 .c文件搞完以后,即把蘋果官方示例中的代碼(以下代碼)添加進(jìn)去:
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;
}
我將這個方法稍微改造了一下,選回一個結(jié)構(gòu)體,因為外面要用到length和dimension。蘋果沒有提供rgbToHSV方法的實現(xiàn),可以用我找到的這個: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文件中導(dǎo)入的庫:#include?<stdio.h>
#include?<stdlib.h>
#include?<math.h>
對了,如果那個橋接文件里沒有導(dǎo)入這個.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方法只需要做三件事:- 創(chuàng)建Cube Map表
- 創(chuàng)建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)
}
參數(shù)設(shè)置都還比較簡單,CISourceOverCompositing濾鏡目前已經(jīng)使用過多次了,并沒有什么復(fù)雜的。 編譯、運行,可以分兩次執(zhí)行,先看消除深綠色的效果,再看最后使用CISourceOverCompositing濾鏡組合圖片之后的效果:GitHub下載地址
我在GitHub上會保持更新。
UPDATED:
我在更換背景的右側(cè),新加入了一個顯示圖2的button,已在GitHub上更新。
參考資料:
http://www.docin.com/p-387777241.html
https://developer.apple.com/library/mac/documentation/graphicsimaging/conceptual/CoreImaging/ci_intro/ci_intro.html
原文地址:http://blog.csdn.net/zhangao0086/article/details/39120331
總結(jié)
以上是生活随笔為你收集整理的iOS Core Image 复杂的滤镜的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 监控圈子行业黑话
- 下一篇: 【整理完毕】荣誉证书、奖状素材合集,独家