具有自定义金属内核的核心图像过滤器不起作用
Core image filter with custom metal kernel doesn't work
我已经根据自定义内核制作了自定义 CIFilter
,我无法使其工作,输出图像充满黑色,我不明白为什么。
这是着色器:
// MARK: Custom kernels
float4 eight_bit(sampler image, sampler palette_image, float paletteSize) {
float4 color = image.sample(image.coord());
float dist = distance(color, palette_image.sample(float2(0,0)));
float4 returnColor = palette_image.sample(float2(0,0));
for (int i = 1; i < floor(paletteSize); ++i) {
float tempDist = distance(color, palette_image.sample(float2(i,0)));
if (tempDist < dist) {
dist = tempDist;
returnColor = palette_image.sample(float2(i,0));
}
}
return returnColor;
}
第一个采样器是需要详细说明的图像,第二个图像是包含必须在该图像中使用的特定调色板颜色的图像。
调色板图像是从 RGBA
值的数组创建的,传递到 Data
缓冲区,并使用此 CIImage 初始值设定项 init(bitmapData data: Data, bytesPerRow: Int, size: CGSize, format: CIFormat, colorSpace: CGColorSpace?)
创建。图片的高度为 1px,宽度为 color 数量。图片获取正确,看起来是这样的:
尝试检查我发现的着色器:
- 如果我return
color
得到的是原图,那么意味着采样器image
是正确通过的
- 如果我尝试 return 来自
palette_image
中任何像素的颜色,则滤镜生成的图像为黑色
我开始认为 palette_image
以某种方式未正确通过。这里图像是如何通过过滤器的:
override var outputImage: CIImage? {
guard let inputImage = inputImage else
{
return nil
}
let palette = EightBitColorFilter.palettes[Int(0)]
let paletteImage = EightBitColorFilter.image(from: palette)
let extent = inputImage.extent
let pixellateImage = inputImage.applyingFilter("CIPixellate", parameters: [kCIInputScaleKey: inputScale])
// let sampler = CISampler(image: paletteImage)
let arguments = [pixellateImage, paletteImage, Float(palette.count)] as [Any]
let final = kernel.apply(extent: extent, roiCallback: {
(index, rect) in
return rect
}, arguments: arguments)
return final
}
你的采样坐标不对。
采样器在Core Image中使用相对坐标,即(0,0)
对应整个输入图像的左上角,(1,1)
右下角 .
所以尝试这样的事情:
float4 eight_bit(sampler image, sampler palette_image, float paletteSize) {
float4 color = image.sample(image.coord());
// initial offset to land in the middle of the first pixel
float2 firstPaletteCoord = float2(1.0 / (2.0 * palletSize), 0.5);
float dist = distance(color, palette_image.sample(firstPaletteCoord));
float4 returnColor = palette_image.sample(firstPaletteCoord);
for (int i = 1; i < floor(paletteSize); ++i) {
// step one pixel further
float2 paletteCoord = firstPaletteCoord + float2(1.0 / paletteSize, 0.0);
float4 paletteColor = palette_image.sample(paletteCoord);
float tempDist = distance(color, paletteColor);
if (tempDist < dist) {
dist = tempDist;
returnColor = paletteColor;
}
}
return returnColor;
}
我已经根据自定义内核制作了自定义 CIFilter
,我无法使其工作,输出图像充满黑色,我不明白为什么。
这是着色器:
// MARK: Custom kernels
float4 eight_bit(sampler image, sampler palette_image, float paletteSize) {
float4 color = image.sample(image.coord());
float dist = distance(color, palette_image.sample(float2(0,0)));
float4 returnColor = palette_image.sample(float2(0,0));
for (int i = 1; i < floor(paletteSize); ++i) {
float tempDist = distance(color, palette_image.sample(float2(i,0)));
if (tempDist < dist) {
dist = tempDist;
returnColor = palette_image.sample(float2(i,0));
}
}
return returnColor;
}
第一个采样器是需要详细说明的图像,第二个图像是包含必须在该图像中使用的特定调色板颜色的图像。
调色板图像是从 RGBA
值的数组创建的,传递到 Data
缓冲区,并使用此 CIImage 初始值设定项 init(bitmapData data: Data, bytesPerRow: Int, size: CGSize, format: CIFormat, colorSpace: CGColorSpace?)
创建。图片的高度为 1px,宽度为 color 数量。图片获取正确,看起来是这样的:
尝试检查我发现的着色器:
- 如果我return
color
得到的是原图,那么意味着采样器image
是正确通过的 - 如果我尝试 return 来自
palette_image
中任何像素的颜色,则滤镜生成的图像为黑色
我开始认为 palette_image
以某种方式未正确通过。这里图像是如何通过过滤器的:
override var outputImage: CIImage? {
guard let inputImage = inputImage else
{
return nil
}
let palette = EightBitColorFilter.palettes[Int(0)]
let paletteImage = EightBitColorFilter.image(from: palette)
let extent = inputImage.extent
let pixellateImage = inputImage.applyingFilter("CIPixellate", parameters: [kCIInputScaleKey: inputScale])
// let sampler = CISampler(image: paletteImage)
let arguments = [pixellateImage, paletteImage, Float(palette.count)] as [Any]
let final = kernel.apply(extent: extent, roiCallback: {
(index, rect) in
return rect
}, arguments: arguments)
return final
}
你的采样坐标不对。
采样器在Core Image中使用相对坐标,即(0,0)
对应整个输入图像的左上角,(1,1)
右下角 .
所以尝试这样的事情:
float4 eight_bit(sampler image, sampler palette_image, float paletteSize) {
float4 color = image.sample(image.coord());
// initial offset to land in the middle of the first pixel
float2 firstPaletteCoord = float2(1.0 / (2.0 * palletSize), 0.5);
float dist = distance(color, palette_image.sample(firstPaletteCoord));
float4 returnColor = palette_image.sample(firstPaletteCoord);
for (int i = 1; i < floor(paletteSize); ++i) {
// step one pixel further
float2 paletteCoord = firstPaletteCoord + float2(1.0 / paletteSize, 0.0);
float4 paletteColor = palette_image.sample(paletteCoord);
float tempDist = distance(color, paletteColor);
if (tempDist < dist) {
dist = tempDist;
returnColor = paletteColor;
}
}
return returnColor;
}