Metal Core Image Sampler 像素格式

Metal Core Image Sampler pixel format

提问人:Deepak Sharma 提问时间:11/7/2023 最后编辑:Deepak Sharma 更新时间:11/7/2023 访问量:47

问:

我有这个 Metal 代码,我想将其转换为 Metal CoreImage 内核。

    fragment half4 fragmentShaderThreshold ( MappedVertex in [[ stage_in ]],
                                 texture2d<half, access::sample> inputTexture [[ texture(0) ]]
                                 )
  {
  constexpr sampler s(s_address::clamp_to_edge, t_address::clamp_to_edge, min_filter::linear, mag_filter::linear);

  half3 rgb = inputTexture.sample(s, in.textureCoordinate).rgb; 
  half3 weights = half3(0.2126, 0.7152, 0.0722);

  float intensity = dot(rgb, weights);

  if (intensity >= 0.95) {
     rgb = half3(1.0, 0.0, 0.0);
  } else if (intensity <= 0.05) {
     rgb = half3(0.0, 0.0, 1.0);
  }

    return half4(rgb, 1.h);
 }

要在 Metal Core Image 内核中做同样的事情,我认为这是可以使用内置过滤器完成的事情。因为内置滤镜可以在各种色彩空间(例如 BT.2020)中工作。请评论如何使用内置过滤器实现这一点。

如果无法使用内置滤镜,我正在考虑将图像转换为灰度并在 Metal Core Image 内核中读取强度(灰度值)。看起来 Metal Core Image 采样器仅支持基于 RGB 的像素格式(与 Metal 不同,Metal 的纹理可以具有像素格式,例如 r8)。这是对的吗?

IOS 核心-镜像 金属套件

评论


答:

1赞 Frank Rupprecht 11/7/2023 #1

不幸的是,没有简单的内置过滤器可以将图像转换为灰度。 确实如此,但它在引擎盖下使用了一个颜色立方体/查找表,并且没有记录它是如何定义的。CIPhotoEffectNoir

你可以用它来做内核的第一部分:CIColorMatrix

let colorMatrixFilter = CIFilter.colorMatrix()
let lumaCoefficients = CIVector(x: 0.2126, y: 0.7152, z: 0.0722, w: 0.0)
colorMatrixFilter.rVector = lumaCoefficients
colorMatrixFilter.bVector = lumaCoefficients
colorMatrixFilter.gVector = lumaCoefficients

您可以进一步调整亮度系数以匹配您正在使用的色彩空间,尽管 Core Image 默认将所有内容转换为扩展的线性 sRGB,因此这些应该是正确的。

对于强度阈值,您可能可以使用一些巧妙的组合 和 ,但老实说,我会为此编写一个简单的自定义颜色内核。它在运行时也应该更快。CIColorThresholdCIBlendWithMask

是的,Core Image 始终适用于 4 通道纹理。在仅生成单通道输出的自定义内核中,通常在所有 3 个颜色通道中写入相同的值。或者,您也可以指定一个单通道,例如在初始化内核时使用 ,但 CI 会在将其作为输入传递给下一个过滤器之前将其转回 4 通道映像(除非该处理器明确使用单通道输入,但这种情况很少见)。outputPixelFormat.Rhinit(functionName: String, fromMetalLibraryData: Data, outputPixelFormat: CIFormat)

评论

0赞 Deepak Sharma 11/7/2023
谢谢你的回答。这里有几个疑问。首先,文档说“每像素 128 位,线性光,使用 GenericRGB 颜色空间的预乘 RGBA 浮点值”。这和扩展的线性sRGB一样吗?其次,如果将 BT2020 图像转换为 sRGB,强度阈值将发生变化。它可能是 2.0 或 5.0 而不是 0.95,我不知道。workingColorSpace
1赞 Frank Rupprecht 11/7/2023
是的,该文档非常陈旧且过时。它是在 Core Image 是仅限 Mac 的框架的时代编写的。我非常肯定默认的工作空间是线性光、扩展(允许的值超出 0..1)、预乘 sRGB 和 16 位浮点(每像素 64 位)工作格式(在 iOS 上)。
1赞 Frank Rupprecht 11/7/2023
你是对的,BT.2020 的亮度计算方式会有所不同。我认为您可以将输入转换为 BT.2020 色彩空间,然后再将其传递给 ,并相应地调整亮度系数。CIColorMatriximage.matchedFromWorkingSpace(to: bt2020ColorSpace)
0赞 Deepak Sharma 11/7/2023
我的输入已经是BT.2020。但是如何知道相同的亮度系数呢?
1赞 Frank Rupprecht 11/7/2023
如果维基百科页面正确,则 BT.2020 的系数应为 。是的,如果您将视图设置为在该颜色空间中显示,它将起作用。工作空间是扩展的sRGB,因此即使是常规sRGB之外的值也会被保留。(0.2126, 0.7152, 0.0722)