Управляйте черно-белой окраской с помощью фильтра CIImage в swift - PullRequest
1 голос
/ 24 мая 2019

Мой код преобразует цветной NSImage в оттенки серого. Затем он преобразует оттенки серого в чисто черно-белое изображение. Есть ли способ создать фильтр, который может указать, как преобразовать серые пиксели в черный / белый? Например - 1. Если значение пикселя> 100, превратить его в черный. 2. Иначе превратите пиксель в белый.

Какие настройки фильтра я могу использовать для достижения этой цели?

Обновлено с помощью пользовательского фильтра CIKernel:

func applyCustomCIFilter( path: String )->NSImage{
    let url = URL(fileURLWithPath: path)
    let origImage = CIImage(contentsOf: url)!

    // Convert image into grayscale
    let grayImage = CIFilter(name: "CIPhotoEffectNoir", parameters: [kCIInputImageKey: origImage])?.outputImage
    print("convert into black and white")

    // custom filter to convert light gray to white and dark gray to black
    let replaceGrayKernel = CIColorKernel( source:
        "kernel vec4 replaceGrayWithBlackOrWhite(sampler grayImage) {" +
            "if( sample(grayImage, samplerCoord(grayImage)).rgb > 0.7  ){" +
            "return vec4(0.0,0.0,0.0,1.0);" +
            "}" +
            "else" +
            "{" +
            "return vec4(1.0,1.0,1.0,1.0);" +
            "}" +
        "}"
    )

    //Apply custom filter to grayscale image. 
    //ERROR: blackAndWhiteImage is nil causing runtime failure
    let blackAndWhiteImage = replaceGrayKernel?.apply(extent: (grayImage!.extent), arguments: [grayImage as Any])

    //Convert CIImage to NSImage
    let rep = NSCIImageRep(ciImage: blackAndWhiteImage!)
    let nsImage = NSImage(size: rep.size)
    nsImage.addRepresentation(rep)

    return nsImage;
}

1 Ответ

0 голосов
/ 25 мая 2019

У вас было 2 ошибки в коде вашего ядра. Вот правильный код:

let kernel = CIColorKernel( source:
    "kernel vec4 replaceGrayWithBlackOrWhite(__sample s) {" +
        "if (s.r > 0.25 && s.g > 0.25 && s.b > 0.25) {" +
        "    return vec4(0.0,0.0,0.0,1.0);" +
        "} else {" +
        "    return vec4(1.0,1.0,1.0,1.0);" +
        "}" +
    "}"
)
  • Изменение с sampler на __ sample связано с тем, что CIColorKernel, который оптимизирован для работы с одним пикселем за раз, просто проходит в ядро ​​этого пикселя. Таким образом, также нет необходимости звонить sample(samplerCoord()). CIWarpKernel и CIKernel используют sampler, поскольку вы отправляете в ядро ​​RIO (область интереса), и эти ядра могут получать доступ к окружающим пикселям ... думаю, эффекты размытия.

  • Второе изменение касалось оператора if. if (s.rgb > 0.7) сравнивает vec3 (или три поплавка) с одним поплавком. Мне пришлось поиграться со значениями, как только я их исправил, и подумал, что (a) использование вместо этого И (&&) или ИЛИ (||) вместе с (б) снижением порога до 0,25 делает более близкое черно-белое изображение , Поэкспериментируйте с этим, чтобы увидеть, чего вы хотите.

Я создал небольшой проект Swift 5 (с использованием жестко запрограммированного изображения), который использует это ядро.

Там нет комментариев, и он содержит различные расширения (и подкласс GLKView), потому что я почерпнул вещи из производственного проекта. Помимо того, что нужно сосредоточиться на проблеме кода вашего ядра, одно слово предупреждения о коде - оно содержит несколько принудительных развертываний, которые следует удалить для «готового к использованию» кода.

...