如何使用CoreImage创建平滑阈值滤镜?

3
2个回答

9

您需要使用Core Image Kernel语言和CIColorKernel编写自己的代码。

我建议使用smoothstep,并传入两个边缘值以及当前像素的亮度。CIKL可能如下所示:

kernel vec4 color(__sample pixel, float inputEdgeO, float inputEdge1)
{
    float luma = dot(pixel.rgb, vec3(0.2126, 0.7152, 0.0722));
    float threshold = smoothstep(inputEdgeO, inputEdge1, luma);
    return vec4(threshold, threshold, threshold, 1.0);
}

你可以使用以下代码将其包装为 CIFilter
class SmoothThreshold: CIFilter
{
    var inputImage : CIImage?
    var inputEdgeO: CGFloat = 0.25
    var inputEdge1: CGFloat = 0.75

    var colorKernel = CIColorKernel(string:
        "kernel vec4 color(__sample pixel, float inputEdgeO, float inputEdge1)" +
        "{" +
        "    float luma = dot(pixel.rgb, vec3(0.2126, 0.7152, 0.0722));" +
        "    float threshold = smoothstep(inputEdgeO, inputEdge1, luma);" +
        "    return vec4(threshold, threshold, threshold, 1.0);" +
        "}"
    )

    override var outputImage: CIImage!
    {
        guard let inputImage = inputImage,
            colorKernel = colorKernel else
        {
            return nil
        }

        let extent = inputImage.extent
        let arguments = [inputImage,
                         inputEdgeO,
                         inputEdge1]

        return colorKernel.applyWithExtent(extent,
                                           arguments: arguments)
    }
}

请注意,您需要确保inputEdge0小于inputEdge1,否则smoothstep会有些疯狂。您还可以使用saturate将它们限制在0到1之间。请参考CIFilter.registerFilterName,它将允许您使用熟悉的语法创建SmoothThreshold的实例,虽然以下方法也可以正常工作:
let image = CIImage(image: UIImage(named: "monalisa.jpg")!)!

let filter = SmoothThreshold()
filter.inputImage = image

let final = filter.outputImage

干杯!

西蒙


谢谢!我主要对算法感兴趣,因为我熟悉创建内核。为什么要比较亮度通道?(我只对比较RGB值的平均值感兴趣,但我仍然好奇亮度背后的原因)。 - joelg
1
根据使用情况而定:如果是通过感知亮度进行阈值处理,则平均值并不完全正确。纯绿色(0,1,0)比纯蓝色(0,0,1)要亮得多,但其平均值相同。 - Flex Monkey
是的,完全有道理。归根结底,我只是试图完成这里描述的内容:https://www.filterforge.com/wiki/index.php/Thresholds#Interpolation_.28.22Blending.22.29 - joelg

1
这对我来说最终起作用了:

[CIColorKernel kernelWithString:
              @"kernel vec4 threshold(__sample s, float thresh) {\n"
                "float avg = (s.r + s.g + s.b) / 3.0;\n"
                "float val = smoothstep(0.0, thresh, avg);"
                "return vec4(val, val, val, 1.0);\n}"];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接