具有自定义金属内核的核心图像滤镜不起作用

时间:2019-09-17 12:20:40

标签: ios swift metal core-image cikernel

我已经基于自定义内核创建了一个自定义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个值的数组创建的,并传递到使用此CIImage初始化程序Data创建的init(bitmapData data: Data, bytesPerRow: Int, size: CGSize, format: CIFormat, colorSpace: CGColorSpace?)缓冲区中。图像的高度为1px,颜色数为宽。图像正确获取,看起来像这样:
Image from palette
尝试检查我发现的着色器:

  • 如果我返回color,则会得到原始图像,因此意味着采样器image已正确传递
  • 如果我尝试从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
    }

1 个答案:

答案 0 :(得分:1)

您的采样坐标已关闭。

样品在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;
}