1

我已经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?)。图像高度为 1 像素,颜色宽度为 1 像素。正确获得了图像,看起来像这样: 尝试检查我发现的着色器:
调色板中的图像

  • 如果我返回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
    }
4

1 回答 1

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;
}
于 2019-09-17T13:09:25.307 回答