Swift 개발

[swift] Chroma key filter

글른 2021. 4. 30. 14:53

Overview

  • chroma key 효과는 greenscreening이나 bluescreening으로도 알려져 있는데, 투명하게 만들 색상을 정해서 target image에서 해당 색상 부분의 alpha value를 0으로 변경하고 background image와 합치는 것을 의미한다.

  • 과정 (filter 두번 먹여주면 끝이다!!!!)
    1. Cube map 생성 : CIColorCube filter를 생성해서 투명하게 설정할 대상이 되는 색상을 결정한다
    2. CIColorFilter 적용 : source image의 모든 pixel에 대해서 CIColorCube filter를 적용한다
    3. source + background : CISourceOverCompositing filter를 사용해서 source와 background image를 합친다

 

Step1. Create a Cube Map

  • Color cube란?
    • RGB 색상에 투명도를 할당하는 3D color-loopup table이다
    • 예를 들어 위의 사진처럼 input image에서 녹색을 제거하기 위해서, 녹색 부분에 대해 value를 0으로 설정하는 custom color cube를 생성하면 된다.
  • HSC (hue-saturation-brightness) representation
    • 특정한 색상의 범주를 정하기 위해서 HSV 표현법으로 모델링 한다.
    • HSV는 hue(색상)을 각도로 나타내는데, screening color에 해당하는 영역에 대한 lookup table value를 0으로 설정하면 된다.

  • 녹색에 해당하는 영역은 108도~144도로, greenscreening을 위해서는 color cube에서 이 범위에 투명도 값을 0으로 설정하면 된다.
func chromaKeyFilter(fromHue: CGFloat, toHue: CGFloat) -> CIFilter?
{
    // 1. 3차원 Memory 할당해주기 (각 element는 RGBA로 구성됨)
    let size = 64
    var cubeRGB = [Float]()
        
    // 2. RGB color combinatoin 만들기
    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. RGB를 HSV로 변환하기. (getHue 함수를 활용)
                let hue = getHue(red: red, green: green, blue: blue)
                //    green 영역에 해당하는 hue의 transparency 설정하기 (108~144)
                let alpha: CGFloat = (hue >= fromHue && hue <= toHue) ? 0: 1
                    
                // 4. CIColorCube filter는 미리 alpah value와 곱해져 있어야함 
                //    (그래서 transparency 포함한 lookup table)이라고 함)
                cubeRGB.append(Float(red * alpha))
                cubeRGB.append(Float(green * alpha))
                cubeRGB.append(Float(blue * alpha))
                cubeRGB.append(Float(alpha))
            }
        }
    }

    let data = Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))

    // 5. cube data로부터 Color image filter 생성하기 
    let colorCubeFilter = CIFilter(name: "CIColorCube", withInputParameters: ["inputCubeDimension": size, "inputCubeData": data])
    return colorCubeFilter
}
// RGB representation -> HSV representation 을 위한 함수
func getHue(red: CGFloat, green: CGFloat, blue: CGFloat) -> CGFloat 
{
    let color = UIColor(red: red, green: green, blue: blue, alpha: 1)
    var hue: CGFloat = 0
    color.getHue(&hue, saturation: nil, brightness: nil, alpha: nil)
    return hue
}

 

Step2. Remove Green from the Source Image

  • source image에 step1에서 생성한 colorCubeFilter를 먹여서 모든 green pixel이 투명해진 output image를 얻는다.
    • 이때 108도가 0.3에 해당하고 144도가 0.4에 해당한다고 한다. (왜인지는 잘 모르겠다)
let chromaCIFilter = self.chromaKeyFilter(fromHue: 0.3, toHue: 0.4)
chromaCIFilter?.setValue(foregroundCIImage, forKey: kCIInputImageKey)
let sourceCIImageWithoutBackground = chromaCIFilter?.outputImage

 

Step3. Composite over a Background Image

  • step2의 결과로 얻은 output image에 CISourceOverCompositing filter를 먹여서 background image를 greenscreened output image와 합성한다.
let compositor = CIFilter(name:"CISourceOverCompositing")
compositor?.setValue(sourceCIImageWithoutBackground, forKey: kCIInputImageKey)
compositor?.setValue(backgroundCIImage, forKey: kCIInputBackgroundImageKey)
let compositedCIImage = compositor?.outputImage

 

참고 사이트 : developer.apple.com/documentation/coreimage/applying_a_chroma_key_effect

 

Apple Developer Documentation

 

developer.apple.com