Core Image 是蘋(píng)果自帶的圖像處理庫(kù)胡嘿,能夠非常簡(jiǎn)單的實(shí)現(xiàn)基本的濾鏡效果匀谣,最新的iOS 10 已經(jīng)自帶超過(guò)180種濾鏡倒信,基本可以滿足絕大部分的濾鏡需求科贬。
基本濾鏡
基本使用
System Filter的使用是非常簡(jiǎn)單的,都是通過(guò)CIFilter這個(gè)類來(lái)生成濾鏡實(shí)例鳖悠。
例如系統(tǒng)濾鏡Chrome的創(chuàng)建如下:
let filterClassName = "CIPhotoEffectChrome"
let filterContext = [String:Any]()
let filter = CIFilter(name: filterClassName, withInputParameters: filterContext)
不用傳參的自帶濾鏡效果
- CIPhotoEffectChrome
- CIPhotoEffectFade
- CIPhotoEffectInstant
- CIPhotoEffectMono
- CIPhotoEffectNoir
- CIPhotoEffectProcess
- CIPhotoEffectTonal
- CIPhotoEffectTransfer
- CILinearToSRGBToneCurve
- CISRGBToneCurveToLinear
高級(jí)濾鏡
僅僅使用System的基本濾鏡是不夠的榜掌,特別對(duì)于一些高級(jí)效果,只靠一個(gè)基本濾鏡是沒(méi)辦法創(chuàng)建的乘综。因此憎账,使用可以考慮使用基本濾鏡的組合,即濾鏡鏈來(lái)實(shí)現(xiàn)一些基本濾鏡不能實(shí)現(xiàn)的效果卡辰。例如Chiper中19th的效果胞皱,就是好幾個(gè)基本濾鏡組合而成的。
一般來(lái)說(shuō)九妈,濾鏡鏈的實(shí)現(xiàn)都是將一個(gè)濾鏡的輸出朴恳,作為另一個(gè)濾鏡的輸入,通過(guò)這種串聯(lián)的方式允蚣,來(lái)實(shí)現(xiàn)濾鏡的的疊加的于颖。但是當(dāng)串聯(lián)的濾鏡數(shù)越來(lái)越多的時(shí)候,勢(shì)必會(huì)影響整個(gè)濾鏡鏈的性能嚷兔,所以不建議串聯(lián)太多濾鏡森渐。
3D-LUTs 濾鏡
基本概念
除了濾鏡鏈的方式外做入,還有一種更便捷的濾鏡實(shí)現(xiàn)方式 --- LUT。
如下圖所示同衣,這是一張Original Lookup Table竟块,所有顏色都沒(méi)進(jìn)行變換。
經(jīng)過(guò)一系列調(diào)整后耐齐,LUT色彩變換成這樣:

使用 & 原理
使用LUT的濾鏡是如何工作的浪秘?
LUT其實(shí)是一張顏色映射表,執(zhí)行濾鏡算法的時(shí)候埠况,此算法會(huì)對(duì)Image的每個(gè)像素執(zhí)行顏色映射(根據(jù)Image的R,G,B,A在LUT上進(jìn)行顏色查找)耸携,這樣就能對(duì)整個(gè)圖像的色調(diào)進(jìn)行改變,達(dá)到濾鏡的效果辕翰。
LUT的核心算法如下:
public static func createColorCubeData(inputImage image: UIImage, cubeDimension: Int) throws -> Data {
let imageSize = image.size
let dim = Int(imageSize.width)
let pixels = dim * dim
let channels = 4 //r,g,b,a (4 channels)
guard pixels == cubeDimension * cubeDimension * cubeDimension else {
throw ColorCubeError.incorrectImageSize
}
let memSize = pixels * channels
guard let img = image.cgImage else {
throw ColorCubeError.missingImageData
}
guard let inProvider = img.dataProvider else {
throw ColorCubeError.unableToCreateDataProvider
}
let inBitmapData = inProvider.data
guard let inBuffer = CFDataGetBytePtr(inBitmapData) else {
throw ColorCubeError.unableToGetBitmpaDataBuffer
}
let floatSize = memSize * MemoryLayout<Float>.size
let finalBuffer = unsafeBitCast(malloc(floatSize), to:UnsafeMutablePointer<Float>.self)
let width = image.cgImage!.width
let height = image.cgImage!.height
let rowNum = width / cubeDimension
let columnNum = height / cubeDimension
var bitmapOffest: Int = 0
var z: Int = 0
var array = Array<Float>(repeating: 0, count: floatSize)
let bitmap = inBuffer
for _ in stride(from: 0, to: rowNum, by: 1) {
for y in stride(from: 0, to: cubeDimension, by: 1) {
let tmp = z
for _ in stride(from: 0, to: columnNum, by: 1) {
for x in stride(from: 0, to: cubeDimension, by: 1) {
let dataOffset = (z * cubeDimension * cubeDimension + y * cubeDimension + x) * 4
let position = bitmap
.advanced(by: bitmapOffest)
array[dataOffset + 0] = Float(position
.advanced(by: 0)
.pointee) / 255
array[dataOffset + 1] = Float(position
.advanced(by: 1)
.pointee) / 255
array[dataOffset + 2] = Float(position
.advanced(by: 2)
.pointee) / 255
array[dataOffset + 3] = Float(position
.advanced(by: 3)
.pointee) / 255
bitmapOffest += 4
}
z += 1
}
z = tmp
}
z += columnNum
}
let data = Data.init(bytes: array, count: floatSize)
return data
}
將變換后的Data傳入CIColorCube
濾鏡中夺衍,即可實(shí)現(xiàn)濾鏡效果。
參考
GPUImage - 顏色查找表(Color Lookup Table) 為圖片添加濾鏡
[iOS] 使用CIColorCube快速製作濾鏡