金属核心图像采样器像素格式

问题描述 投票:0回答:1

我有这个 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 图像采样器仅支持基于 RGB 的像素格式(与 Metal 不同,其中纹理可以具有 r8 等像素格式)。这是正确的吗?

ios metal core-image metalkit
1个回答
0
投票

不幸的是,没有简单的内置过滤器可以将图像转换为灰度。

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,因此这些应该是正确的。

对于强度阈值,您可能可以使用

CIColorThreshold
CIBlendWithMask
的一些巧妙组合,但老实说,我会为此编写一个简单的自定义颜色内核。它在运行时也应该更快。

是的,Core Image 始终适用于 4 通道纹理。在仅产生单通道输出的自定义内核中,您通常在所有 3 个颜色通道中写入相同的值。或者,您也可以在使用

outputPixelFormat
初始化内核时指定单通道
.Rh
,例如
init(functionName: String, fromMetalLibraryData: Data, outputPixelFormat: CIFormat)
,但 CI 无论如何都会将其调配回 4 通道图像,然后再将其作为输入传递给下一个过滤器(除非这是一个明确使用单通道输入的处理器,但这种情况很少见)。

© www.soinside.com 2019 - 2024. All rights reserved.