本案例的目的是理解如何用Metal实现LUT颜色查找表滤镜,通过将颜色值存储在一张表中,在需要的时候通过索引在这张表上找到对应的颜色值,将原有色值替换成查找表中的色值;
总结就是一种针对色彩空间的管理和转换技术,LUT 就是一个 RGB 组合到另一个 RGB 组合的映射关系表;
Demo
实操代码
// LUT查找滤镜
let filter = C7LookupTable.init(image: R.image("lut_abao"))
// 方案1:
let dest = BoxxIO.init(element: originImage, filter: filter)
ImageView.image = try? dest.output()
dest.filters.forEach {
NSLog("%@", "\($0.parameterDescription)")
}
// 方案2:
ImageView.image = try? originImage.make(filter: filter)
// 方案3:
ImageView.image = originImage ->> filter
实现原理
- 过滤器
这款滤镜采用并行计算编码器设计.compute(kernel: "C7LookupTable")
,参数因子[intensity]
对外开放参数
intensity
: 强度,其实就是调整mix混合平均值。
/// LUT映射滤镜
public struct C7LookupTable: C7FilterProtocol {
public let lookupImage: C7Image?
public let lookupTexture: MTLTexture?
public var intensity: Float = 1.0
public var modifier: Modifier {
return .compute(kernel: "C7LookupTable")
}
public var factors: [Float] {
return [intensity]
}
public var otherInputTextures: C7InputTextures {
return lookupTexture == nil ? [] : [lookupTexture!]
}
public init(image: C7Image?) {
self.lookupImage = image
self.lookupTexture = image?.cgImage?.mt.newTexture()
}
public init(name: String) {
self.init(image: R.image(name))
}
}
- 着色器
1、用蓝色值计算正方形的位置,得到quad1和quad2;
2、根据红色值和绿色值计算对应位置在整个纹理的坐标,得到texPos1和texPos2;
3、根据texPos1和texPos2读取映射结果newColor1和newColor2,再用蓝色值的小数部分进行mix操作;
kernel void C7LookupTable(texture2d<half, access::write> outputTexture [[texture(0)]],
texture2d<half, access::read> inputTexture [[texture(1)]],
texture2d<half, access::sample> lookupTexture [[texture(2)]],
constant float *intensity [[buffer(0)]],
uint2 grid [[thread_position_in_grid]]) {
const half4 inColor = inputTexture.read(grid);
const half