我 试图 通过 使用 Core Image 的 金属 着色 语言 从 这个 source 移植 一些 CIFilter
。
我 有 一 个 由 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 似乎 还 不够 。
我 看到 了 一些 例子 , 但 他们 使用 的 是 " 完整 " 着色 语言 , 这 是 一 种 subset , 仅 用于 处理 碎片 的 Core Image 所 无法 使用 的 。
2条答案
按热度按时间0pizxfdo1#
更新
CIImage
,但仍然可以使用。*假设原始数据是
NSData
,那么只需在调用时将其传递给内核即可:Data
也可以工作,但我知道NSData
是一个参数类型,它允许Core Image缓存基于输入参数的筛选结果。因此,如果不确定,最好强制转换为NSData
。*然后,在内核函数中,只需使用适当的
constant
类型声明参数:上一个答案
Core Image内核似乎不支持指针或数组参数类型。尽管iOS 13似乎有一些功能。
Metal CIKernel示例支持具有任意结构化数据的参数。
但是,正如经常与核心形象,似乎没有进一步的文档,这一点...
但是,您仍然可以使用传递缓冲区数据的“老方法”,即将其 Package 在
CIImage
中,然后在内核中对其进行采样。请注意,由于GPU不支持3通道图像,因此没有
CIFormat
。因此,您必须使用单通道.Rf
,并将内核中的值重新打包为float3
,或者向数据添加一些步长,并分别使用.RGBAf
和float4
(我建议这样做,因为它可以减少纹理提取)。当您将该图像传递到内核中时,可能需要将采样模式设置为
nearest
,否则在两个像素之间采样时可能会得到插值:在(Metal)内核中,您可以像处理普通输入图像一样通过
sampler
:请注意,我将
0.5
添加到坐标中,以便它们指向数据图像中像素的 * 中间 *,以避免模糊和插值。还要注意,从
sampler
中获取的像素值总是有4个通道。因此,即使您使用formate.Rf
创建数据图像,在采样时也会得到float4
(其他值用0.0
填充G和B,用1.0
填充alpha)。在这种情况下,您只需编辑
我之前忘了把采样坐标从绝对像素空间(
(0.5, 0.5)
是第一个像素的中间)转换到相对采样空间((0.5, 0.5)
是整个缓冲区的中间),现在已经修复了。velaa5lx2#
我做了它,事件,如果答案是好的,也部署到较低的目标,结果并不完全是我所期望的.原始内核写为字符串和上面的方法之间的差异创建一个图像作为数据源是一种大.
没有得到确切的原因,但我传递的图像作为调色板的来源是一种不同的大小和颜色(可能是由于颜色空间)创建的一个。
由于没有关于此语句的文档:
Metal CIKernel示例支持具有任意结构化数据的参数。
我在业余时间试了很多次,最后终于找到了这个。
首先是着色器:
其次将调色板转换为
SIMD3<Float>
:第一次我尝试将SIMD3附加到Data对象,但可能是由于内存对齐的原因,没有工作。记住在使用它之后取消分配所创建的内存。
希望能帮到别人。