【问题标题】:Metal Core Image Kernel use of DOD使用 DOD 的 Metal Core Image Kernel
【发布时间】:2022-02-06 22:23:24
【问题描述】:

我编写了以下 Metal Core Image Kernel 来产生恒定的红色。

extern "C" float4 redKernel(coreimage::sampler inputImage, coreimage::destination dest)
{
  return float4(1.0, 0.0, 0.0, 1.0);
}

然后我在 Swift 代码中有这个:

class CIMetalRedColorKernel: CIFilter {
  var inputImage:CIImage?
  
  static var kernel:CIKernel = { () -> CIKernel in
     let bundle = Bundle.main
     let url = bundle.url(forResource: "Kernels", withExtension: "ci.metallib")!
     let data = try! Data(contentsOf: url)
     return try! CIKernel(functionName: "redKernel", fromMetalLibraryData: data)
  }()

 override var outputImage: CIImage? {
    guard let inputImage = inputImage else {
        return nil
    }

    let dod = inputImage.extent
    return CIMetalRedColorKernel.kernel.apply(extent: dod, roiCallback: { index, rect in
        return rect
    }, arguments: [inputImage])
 }
}

如您所见,dod 是输入图像的范围。但是当我运行过滤器时,我得到一个超出输入图像范围(DOD)的整个红色图像,为什么?我有多个过滤器链接在一起,整体尺寸为 1920x1080。红色滤镜不应该只对传入的 DOD 矩形运行,并为 DOD 之外的任何内容生成清晰的像素吗?

【问题讨论】:

    标签: ios metal core-image cifilter


    【解决方案1】:

    通过内核调用的extent 参数,您可以向内核产生有意义结果的区域发出信号,或者,正如您正确命名的那样,定义域。 然而,这也意味着它在这个区域之外产生的任何东西基本上是未定义的,由你作为内核开发者来决定。

    像您编写的那样的生成器内核通常具有无限 定义域,因为无论输入如何,它都会产生红色。要将输出限制在特定区域,您可以对其应用裁剪:

    let dod = inputImage.extent
    let result = CIMetalTestRenderer.kernel.apply(extent: .infinite, roiCallback: { index, rect in
        return rect
    }, arguments: [inputImage])
    return result.cropped(to: dod)
    

    裁剪后,dod 之外的所有内容都将是透明的。


    更新:

    事实证明,您必须将内核调用的extent 参数设置为.infinite 才能使其工作。我怀疑cropped(to:) 检查图像是否已经具有给定的范围,并且在这种情况下不会执行任何操作。因此,要使 CI 真正应用裁剪,您必须指定内核实际生成的定义域。

    我认为这里违反直觉的事情是 CI 不会将您的内核应用于只是您指定的 extent 的像素。当结果没有正确裁剪时,似乎有一些自动钳制到范围,但老实说,我也对此感到困惑......

    【讨论】:

    • 我希望着色器不会在其定义域之外执行任何操作。但它似乎在每个可能的像素上执行(就像无限范围一样)。这就提出了一个问题——执行着色器的计算区域是如何决定的?
    • 基本上按目的地。目标中的每个像素都需要生成,并且对于该核心图像,它会沿着过滤器链上升。您可以使用cropped(to:) 告诉 CI 它不应该为该区域之外的像素执行您的内核。
    • 我不明白的是,extent 参数的用途是什么?范围参数的文档显示 - “输出图像的范围。”....cropped(to:) 也将获得与设置输出图像范围相同的结果。
    • 更新:cropped(to:) 也给出了相同的结果,没有变化!如果您需要示例项目,请告诉我(代码已经发布,但为方便起见,请告诉我)。
    • 已更新。我也对这种行为感到有些困惑。有时似乎需要相当刻意地避免钳制到范围的行为。 ?‍♂️
    猜你喜欢
    • 1970-01-01
    • 2020-10-28
    • 2021-06-28
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 2020-01-05
    相关资源
    最近更新 更多