Chroma Key Image Processing
Chroma key composing is a post-production technique for composing two images or video streams together based on color hues. This example demonstrates how to remove the background (the green backdrop) and to deal with some noise and reflection that may add some green shade to scene elements. Below is presented the input image used in this example. It presents many shades of green in the backdrop as well as some noise due to compression.The process has three steps as described as follows: 1. Converts green pixels to transparencyIn this step all pixels are processed in the HSV color space. Green pixels are converted to transparent. Given a pixel p, it's is considered "green" if:p.hue >= 60 AND p.hue <= 130 AND p.saturation >= 0.4 AND p.lightness >= 0.3 result: 2. Process remaining green pixels due to reflection and compression noiseSome green pixels remain in the image but it cannot be removed since it's a part of the foreground object. This is very common to happen to hair:In this case this pixels are filtered and its color is balanced to reduce the green shade. 3. Alpha BoundaryThe last step adds gradient transparency to every pixel and its neighbors that are not transparent and are in the boundary of the foreground element. Result:package chromaToTransparency; import marvin.color.MarvinColorModelConverter; import marvin.image.MarvinImage; import marvin.io.MarvinImageIO; import static marvin.MarvinPluginCollection.*; public class ChromaToTransparency { public ChromaToTransparency(){ MarvinImage image = MarvinImageIO.loadImage("./res/person_chroma.jpg"); MarvinImage imageOut = new MarvinImage(image.getWidth(), image.getHeight()); // 1. Convert green to transparency greenToTransparency(image, imageOut); MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out1.png"); // 2. Reduce remaining green pixels reduceGreen(imageOut); MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out2.png"); // 3. Apply alpha to the boundary alphaBoundary(imageOut, 6); MarvinImageIO.saveImage(imageOut, "./res/person_chroma_out3.png"); } private void greenToTransparency(MarvinImage imageIn, MarvinImage imageOut){ for(int y=0; y<imageIn.getHeight(); y++){ for(int x=0; x<imageIn.getWidth(); x++){ int color = imageIn.getIntColor(x, y); int r = imageIn.getIntComponent0(x, y); int g = imageIn.getIntComponent1(x, y); int b = imageIn.getIntComponent2(x, y); double[] hsv = MarvinColorModelConverter.rgbToHsv(new int[]{color}); if(hsv[0] >= 60 && hsv[0] <= 130 && hsv[1] >= 0.4 && hsv[2] >= 0.3){ imageOut.setIntColor(x, y, 0, 127, 127, 127); } else{ imageOut.setIntColor(x, y, color); } } } } private void reduceGreen(MarvinImage image){ for(int y=0; y<image.getHeight(); y++){ for(int x=0; x<image.getWidth(); x++){ int r = image.getIntComponent0(x, y); int g = image.getIntComponent1(x, y); int b = image.getIntComponent2(x, y); int color = image.getIntColor(x, y); double[] hsv = MarvinColorModelConverter.rgbToHsv(new int[]{color}); if(hsv[0] >= 60 && hsv[0] <= 130 && hsv[1] >= 0.15 && hsv[2] >= 0.15){ if((r*b) !=0 && (g*g) / (r*b) > 1.5){ image.setIntColor(x, y, 255, (int)(r*1.4), (int)g, (int)(b*1.4)); } else{ image.setIntColor(x, y, 255, (int)(r*1.2), g, (int)(b*1.2)); } } } } } public static void main(String[] args) { new ChromaToTransparency(); } } |
||