Как использовать CoreImage для создания сглаженного порогового фильтра?

Существуют ли фильтры, которые можно использовать как плавный порог? Под этим я подразумеваю, что значения пикселей должны быть пороговыми между двумя значениями, но промежуточные значения интерполируются.

По сути, я пытаюсь реализовать это:

https://www.filterforge.com/wiki/index.php/Thresholds

2 ответа

Решение

Вам нужно будет написать свой собственный, используя Core Image Kernel Language и 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

Ура!

Саймон

Это сработало для меня:

[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}"];
Другие вопросы по тегам