使用Metal编写自定义CIKernel返回固定颜色,实际输出颜色不符如何解决
自定义CIKernel颜色偏差问题修复方案
问题原因
Core Image 默认所有内核运算都在线性RGB颜色空间中执行,你在CIKernel中返回的float4数值会被识别为线性空间颜色。当最终渲染输出到屏幕、生成CGImage/UIImage时,Core Image会自动将线性空间颜色转换为适配显示的sRGB伽马编码空间,这个伽马转换步骤就是你看到的数值偏差的来源。你测试得到的曲线就是典型的Gamma 2.4(sRGB标准伽马值)校正曲线,线性值0.0627(16/255.0)经过伽马转换后得到的sRGB编码值约等于0.243,乘以255就是你实际拿到的62。
修复方案
方案1:Shader内手动做sRGB转线性运算(最稳妥,不影响全局CIContext配置)
在Metal Shader中增加sRGB值转线性空间值的工具函数,你期望的sRGB数值先转成线性值再返回,Core Image后续做伽马转换后就会得到你预期的数值,示例代码如下:
// 输入为0-255的sRGB通道值,输出对应的线性空间值 float sRGBToLinear(uint channelVal) { float val = float(channelVal) / 255.0; if (val <= 0.04045) { return val / 12.92; } return pow((val + 0.055) / 1.055, 2.4); } float4 test(sample_t s) { return float4( sRGBToLinear(16), sRGBToLinear(16), sRGBToLinear(16), 1.0 ); }
方案2:全局修改CIContext的颜色空间配置(适合全链路需要线性运算的场景)
如果你的整个滤镜处理链路都不需要自动伽马转换,可以在创建CIContext时指定工作和输出颜色空间都为线性空间,此时Kernel内直接返回16/255.0即可得到对应数值,iOS端创建示例:
let context = CIContext(options: [ .workingColorSpace: CGColorSpace(name: CGColorSpace.genericRGBLinear)!, .outputColorSpace: CGColorSpace(name: CGColorSpace.genericRGBLinear)! ])
macOS端创建示例:
CIContext *context = [CIContext contextWithOptions:@{ kCIContextWorkingColorSpace: [NSColorSpace genericRGBLinearColorSpace], kCIContextOutputColorSpace: [NSColorSpace genericRGBLinearColorSpace] }];
内容的提问来源于stack exchange,提问作者krosshj
相关产品推荐
相关产品推荐

