You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CIImage存储LUT后在Metal Shader中采样失败问题求助

基于CIFilter的色调映射器LUT采样问题

我正在基于CIFilter实现一款色调映射器,在simplerFirstStep分支中,我将参数存储在CIImage中,传入Metal Shader以校正图像亮度。

Swift实现代码

// calc my parameters here (these are correct)
let f_G = calcToneCurve(globLuminance: globLuminance,
                        segBorders: segmentationBorders,
                        means: means)
     
// store in a Databuffer   
let lut = f_G.withUnsafeBufferPointer { Data(buffer: $0) }

// create CIImage with dims 256x1 pixel containing the data 
let lutImage = CIImage(bitmapData: lut,
                       bytesPerRow: MemoryLayout<Float32>.size * f_G.count,
                       size: CGSize(width: f_G.count, height: 1), // 256x1 pixel
                       format: .Rf,
                       colorSpace: nil)


        
// tonemap on GPU
let result = Self.kernel1.apply(
    extent: input.extent,
    roiCallback: { _, rect in rect },
    arguments: [input,
                colorMonochromeFilter.outputImage!,
                lutImage,
                globLuminance.min,
                globLuminance.max
               ]
)!

Metal Shader代码

float4 tonemap(coreimage::sample_t color,       // primary RGB image
               coreimage::sample_t luminance,   // luminance image
               coreimage::sampler lightnessLUT, // a 256 x 1 image
               const float minLuminance,
               const float maxLuminance)
{
    // luminance is in range [0,1] like the sampler coordinate system
    const float lutPos = (luminance.r - minLuminance) / (maxLuminance - minLuminance);
    
    // y=0.5 so we are dead center on the LUT's y axis
    float f_G = lightnessLUT.sample({lutPos, 0.5f}).r;
    
    // this calculates the new RGB values
    float3 rgb = color.rgb;
    float3 toneMapped = rgb / (rgb + f_G + 1e-8);
    
    return float4(toneMapped, color.a);
}

我尝试过用sampler extent确保坐标正确,但依然无效:

// sampler extent (x, y, width, height)
float4 extent = samplerExtent(lightnessLUT);

// luminance is in range [0,1] like the sampler coordinate system
const float lutPos = ((luminance.r - minLuminance) / (maxLuminance - minLuminance)) * extent.z;
            
// y=0.5 so we are dead center on the LUT's y axis
float f_G = lightnessLUT.sample(float2(lutPos, 0.5f * extent.w) + extent.xy).r;

问题现象

上述代码返回全白图像,仿佛采样器始终读取0.0。我尝试直接返回亮度感知参数f_G,发现仅图像下半部分有效,其余为黑色。

对比结果

  • 主分支全GPU计算的预期结果:
    预期结果

  • LUT方式的错误结果:
    LUT采样错误结果

计算出的参数是正确的,生成的色调曲线符合论文预期:
正确的色调曲线

希望有人能指出采样失败的原因。

内容的提问来源于stack exchange,提问作者Philli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 03:32:30