Сглаживание краев хроматического ключа -CoreImage - PullRequest
0 голосов
/ 16 ноября 2018

Я использую следующий код для удаления зеленого фона с изображения. Но края изображения имеют зеленый оттенок и некоторые пиксели повреждены. Как можно сгладить это и сделать идеальный вырез.

 func chromaKeyFilter(fromHue: CGFloat, toHue: CGFloat) -> CIFilter?
    {
        // 1
        let size = 64
        var cubeRGB = [Float]()

        // 2
        for z in 0 ..< size {
            let blue = CGFloat(z) / CGFloat(size-1)
            for y in 0 ..< size {
                let green = CGFloat(y) / CGFloat(size-1)
                for x in 0 ..< size {
                    let red = CGFloat(x) / CGFloat(size-1)

                    // 3
                    let hue = getHue(red: red, green: green, blue: blue)
                    let alpha: CGFloat = (hue >= fromHue && hue <= toHue) ? 0: 1

                    // 4
                    cubeRGB.append(Float(red * alpha))
                    cubeRGB.append(Float(green * alpha))
                    cubeRGB.append(Float(blue * alpha))
                    cubeRGB.append(Float(alpha))
                }
            }
        }



  @IBAction func clicked(_ sender: Any) {
          let a = URL(fileURLWithPath:"green.png")
          let b = URL(fileURLWithPath:"back.jpg")

        let image1 = CIImage(contentsOf: a)
        let image2 = CIImage(contentsOf: b)





        let chromaCIFilter = self.chromaKeyFilter(fromHue: 0.3, toHue: 0.4)
        chromaCIFilter?.setValue(image1, forKey: kCIInputImageKey)
        let sourceCIImageWithoutBackground = chromaCIFilter?.outputImage

        /*let compositor = CIFilter(name:"CISourceOverCompositing")
        compositor?.setValue(sourceCIImageWithoutBackground, forKey: kCIInputImageKey)
        compositor?.setValue(image2, forKey: kCIInputBackgroundImageKey)
        let compositedCIImage = compositor?.outputImage*/

        var rep: NSCIImageRep = NSCIImageRep(ciImage: sourceCIImageWithoutBackground!)
        var nsImage: NSImage = NSImage(size: rep.size)
        nsImage.addRepresentation(rep)

        let url = URL(fileURLWithPath:"file.png")

        nsImage.pngWrite(to: url)
        super.viewDidLoad()
    }

Введите:

enter image description here

Выход: enter image description here

Обновление: enter image description here

Обновление 2: enter image description here

Обновление 3: enter image description here

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Мой (живой) манипулятор работает так (с улучшениями, описанными пользователем 1118321), и, используя его анализатор, я быстро заметил, что это, скорее всего, не совсем зеленое изображение на экране.Это один из многих поддельных, где зеленый экран, кажется, был заменен насыщенным монохромным зеленым.Хотя это может показаться хорошим, оно вводит артефакты, в которых объект, на который нанесен ключ (с полосами первоначально использованного зеленого цвета), встречает монохромный зеленый.Вы можете увидеть, что был использован единственный зеленый, посмотрев на гистограмму.Настоящий зеленый экран всегда имеет (в) видимые оттенки зеленого.Мне удалось получить приличный ключ, но пришлось вручную подправить некоторые настройки.С NLE вы, вероятно, сможете получить гораздо лучшие результаты, но они также будут намного более сложными.Итак, чтобы вернуться к вашей проблеме, ваш код, вероятно, работает как сейчас (обновление № 3), вам просто нужно использовать правильное реальное изображение зеленого экрана.enter image description here

0 голосов
/ 16 ноября 2018

Профессиональные инструменты для хроматизации обычно включают в себя то, что называется подавителем разливов. Подавитель разлива находит пиксели, которые содержат небольшое количество цвета хроматического ключа, и смещает цвет в противоположном направлении. Таким образом, зеленые пиксели будут двигаться в пурпурный цвет. Это уменьшает зеленую окантовку, которую вы часто видите вокруг кадров с кадрами.

Пиксели, которые вы называете поврежденными, - это просто пиксели, у которых есть некоторый уровень цвета насыщенности, и которые выбираются вашей ключевой функцией. Вместо того, чтобы выбирать жесткие 0 или 1, вы можете рассмотреть функцию, которая возвращает значение от 0 до 1 в зависимости от цвета пикселя. Например, вы можете найти угловое расстояние оттенка текущего пикселя до fromHue и toHue и, возможно, сделать что-то вроде этого:

// Get the distance from the edges of the range, and convert to be between 0 and 1
var distance: CGFloat
if (fromHue <= hue) && (hue <= toHue) {
    distance = min(abs(hue - fromHue), abs(hue - toHue)) / ((toHue - fromHue) / 2.0)
} else {
    distance = 0.0
}
distance = 1.0 - distance
let alpha = sin(.pi * distance - .pi / 2.0) * 0.5 + 0.5

Это даст вам плавное изменение от краев диапазона к центру диапазона. (Обратите внимание, что я остановился на том факте, что оттенок оборачивается на 360 °. Это то, с чем вам придется справиться.) График спада выглядит следующим образом:

A sine function scaled and offset so that it smoothly goes from 0 to 1 over the range 0 to 1

Еще одна вещь, которую вы можете сделать, это ограничить наложение только теми пикселями, у которых насыщенность выше некоторого порога, а значение выше некоторого порога. Для очень темных и / или ненасыщенных цветов вы, вероятно, не хотите выключать это. Я думаю, что это поможет решить проблемы, которые вы видите, например, с жакетом модели.

...