gpt4 book ai didi

ios - Core Image 颜色内核的 Metal 着色语言,如何传递 float3 数组

转载 作者:行者123 更新时间:2023-11-28 23:28:28 25 4
gpt4 key购买 nike

我正在尝试移植一些 CIFilter来自这个source通过为 Core Image 使用 Metal 着色语言。
我有一个由 RGB 数组组成的调色板结构,我想将它们作为参数传递给自定义 CI 彩色图像内核。
RGB 结构被转换为 SIMD3<Float> 的数组.

 static func SIMD3Palette(_ palette: [RGB]) -> [SIMD3<Float>] {
return palette.map{$0.toFloat3()}
}

内核应该采用 simd_float3 的数组值,问题是当我启动过滤器时它告诉我索引 1 处的参数需要一个 NSData .

override var outputImage: CIImage? {
guard let inputImage = inputImage else
{
return nil
}
let palette = EightBitColorFilter.palettes[Int(inputPaletteIndex)]
let extent = inputImage.extent
let arguments = [inputImage, palette, Float(palette.count)] as [Any]

let final = colorKernel.apply(extent: extent, arguments: arguments)

return final
}

这是内核:

float4 eight_bit(sample_t image, simd_float3 palette[], float paletteSize, destination dest) {
float dist = distance(image.rgb, palette[0]);
float3 returnColor = palette[0];
for (int i = 1; i < floor(paletteSize); ++i) {
float tempDist = distance(image.rgb, palette[i]);
if (tempDist < dist) {
dist = tempDist;
returnColor = palette[i];
}
}
return float4(returnColor, 1);
}

我想知道如何将数据缓冲区传递给内核,因为将其转换为 NSData 似乎还不够。
我看到了一些例子,但他们使用的是“完整”着色语言,这种语言不适用于 Core Image,这是一种 subset只处理片段。

最佳答案

更新

我们现在已经弄清楚了如何将数据缓冲区直接传递到 Core Image 内核中。使用 CIImage如下所述不需要,但仍然可行。

假设您的原始数据为 NSData ,您可以在调用时将其传递给内核:

kernel.apply(..., arguments: [data, ...])

注意:Data可能也有效,但我知道 NSData是一种参数类型,它允许 Core Image 根据输入参数缓存过滤结果。因此,当有疑问时,最好将其转换为 NSData .

然后在内核函数中,只需要用合适的 constant 来声明参数即可输入:

extern "C" float4 myKernel(constant float3 data[], ...) {
float3 data0 = data[0];
// ...
}

上一个答案

Core Image 内核似乎不支持指针或数组参数类型。尽管 iOS 13 似乎带来了一些东西。来自发行说明:

Metal CIKernel instances support arguments with arbitrarily structured data.

但是,与 Core Image 一样,似乎没有进一步的文档......

但是,您仍然可以使用传递缓冲区数据的“旧方法”,将其包装在 CIImage 中。并在内核中对其进行采样。例如:

    let array: [Float] = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }
let dataImage = CIImage(bitmapData: data, bytesPerRow: data.count, size: CGSize(width: array.count/4, height: 1), format: .RGBAf, colorSpace: nil)

请注意,没有 CIFormat对于 3 channel 图像,因为 GPU 不支持这些图像。所以你要么必须使用单 channel .Rf并将内核中的值重新打包为 float3再次,或者向您的数据添加一些步幅并使用 .RGBAffloat4分别(我推荐这样做,因为它减少了纹理获取)。

当您将该图像传递到内核时,您可能希望将采样模式设置为 nearest ,否则在两个像素之间采样时可能会得到插值:

kernel.apply(..., arguments: [dataImage.samplingNearest(), ...])

在您的(Metal)内核中,您可以像使用普通输入图像一样通过 sampler 评估数据。 :

extern "C" float4 myKernel(coreimage::sampler data, ...) {
float4 data0 = data.sample(data.transform(float2(0.5, 0.5))); // data[0]
float4 data1 = data.sample(data.transform(float2(1.5, 0.5))); // data[1]
// ...
}

请注意,我添加了 0.5到坐标,以便它们指向数据图像中像素的中间,以避免模糊和插值。

另请注意,您从 sampler 获得的像素值总是有4个 channel 。因此,即使您使用甲酸盐.Rf创建数据图像, ,您将得到 float4采样时(其他值用 0.0 填充 G 和 B,用 1.0 填充 alpha)。在这种情况下,你可以这样做

float data0 = data.sample(data.transform(float2(0.5, 0.5))).x;

编辑

我之前忘记将样本坐标从绝对像素空间(其中 (0.5, 0.5) 是第一个像素的中间)转换为相对采样器空间(其中 (0.5, 0.5) 是整个缓冲区的中间)。现在已经修复了。

关于ios - Core Image 颜色内核的 Metal 着色语言,如何传递 float3 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57751660/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com