Article

Applying a Chroma Key Effect

Replace a color in one image with the background from another.

Overview

The chroma key effect, also known as bluescreening or greenscreening, sets a color or range of colors in an image to transparent (alpha = 0) so that you can substitute a different background image.

Figure 1

Applying a chroma key effect to swap background images

The chroma key effect replaces the greenscreen background behind a paper airplane foreground with the image of a beach landscape to show paper airplane flying on a beach.

You apply this technique in three steps:

  1. Create a cube map that the CIColorCube filter will consult to determine which colors to set transparent.

  2. Make all pixels of the specified color in the source image transparent by applying a CIColorCube filter based on the cube map.

  3. Composite the source and the background image with the CISourceOverCompositing filter.

Create a Cube Map

A color cube is a 3D color-lookup table that assigns a transparency value to RGB colors. For example, to filter out green from the input image, create a custom color cube with the green portion of its values set to 0.

To specify a range of colors to exclude, model colors with an HSV (hue-saturation-brightness) representation. HSV represents hue as an angle around the central axis, as in a color wheel. In order to make a chroma key color from the source image transparent, set its lookup table value to 0 when its hue is in the screen color's range.

Figure 2

Color wheel showing the hue values to filter out of a source image with green background

A hue color wheel highlighting hues between 108° and 144° to show the slice of green to filter out of the source image

The value for green in the source image falls within the slice beginning at 108° (108/360 = 0.3) and ending at 144° (144/360 = 0.4). You will set transparency to 0 for this range in the color cube.

The value for green in the source image falls within the slice beginning at 108° (108/360 = 0.3) and ending at 144° (144/360 = 0.4). You will set transparency to 0 for this range in the color cube.

To create the color cube, iterate across all values of red, green, and blue, entering a value of 0 for combinations that the filter should make transparent. Refer to the numbered list for details on each step to the routine.

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))
            }
        }
    }

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

    // 5
    let colorCubeFilter = CIFilter(name: "CIColorCube", withInputParameters: ["inputCubeDimension": size, "inputCubeData": data])
    return colorCubeFilter
}
  1. Allocate memory. The color cube has three dimensions, each with four elements of data (RGBA).

  2. Use a for-loop to iterate through each color combination of red, green, and blue, simulating a color gradient.

  3. Convert RGB to HSV, as in Listing 2. Even though the color cube exists in RGB color space, it is easier to isolate and remove color based on hue. Input 0 for green hues to indicate complete removal; use 1 for other hues to leave those colors intact. To specify green as a hue value, convert its angle in the hue pie chart to a range of 0 to 1. The green in the sample image has hue between 0.3 (108 out of 360 degrees) and 0.4 (144 out of 360 degrees). Your shade of green may differ, so adjust the range accordingly.

  4. The CIColorCube filter requires premultiplied alpha values, meaning that the values in the lookup table have their transparency baked into their stored entries rather than applied when accessed.

  5. Create a Core Image filter from the cube data by invoking the name CIColorCube.

Listing 2

Converting RGB to HSV

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
}

Remove Green from the Source Image

Apply the color cube filter to a foreground image by setting its inputImage parameter and then accessing the outputImage.

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

The output image contains the foreground with all green pixels made transparent.

The filter passes through each pixel in the input image, looks up its color in the color cube, and replaces the source color with the color in the color cube at the nearest position.

Composite over a Background Image

Chain a CISourceOverCompositing filter to the color cube filter to composite a background image to the greenscreened output. The transparency in the colorcube-filtered image allows the composited background image to show through.

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

The foreground of the source image now appears in front of the background landscape without any trace of the green screen.

See Also

Filter Recipes

Selectively Focusing on an Image

Focus on a part of an image by applying Gaussian blur and gradient masks.

Customizing Image Transitions

Transition between images in creative ways using Core Image filters.

Simulating Scratchy Analog Film

Degrade the quality of an image to make it look like dated, scratchy analog film.