The aim of this code example is to extract the green background, also called chroma key, and replace it with the background from a different image. In fact what we’re doing is keying out a black and white mask from the green component of the foreground image and using it to mask any other background image.

% Read any two images for background (bg) and foreground (fg)

% extract 3 different color channels
% and luminance matrix
fgR = fg(:,:,1);
fgG = fg(:,:,2);
fgB = fg(:,:,3);
fgY = 0.3*fgR+0.59*fgG+0.11*fgB;

% subtract luminance from green

% Calculate and plot histogram

% Define and normalise a reasonable threshold to try to avoid the spills
% too high will trim the image
% too low will let some green through the borders
thres = 80/255;

% set to 1 in your mask all those values where 
% fg(G-Y) is lower than the threshold
mask = fgG_Y < thres;

% finally, save channel by channel the foreground where mask = 1
% and the background where mask = 0 (1-mask = 1)
final(:,:,1)=fg(:,:,1).*mask + bg(:,:,1).*(1-mask);
final(:,:,2)=fg(:,:,2).*mask + bg(:,:,2).*(1-mask);
final(:,:,3)=fg(:,:,3).*mask + bg(:,:,3).*(1-mask);

The result is something like this:

Screen Shot 2014-11-13 at 11.08.36

But what about casting a shadow?

Let’s observe the histogram:


We can clearly distinguish 3 entities from it: the person, the shadow cast and the background.

By placing a threshold at a value of 150 we would be extracting the person only. If we want to keep the shadow we should plan a threshold at about 200. So the answer is to create two different masks this time to be able to distinguish between 3 different areas: foreground, shadow, background.


– Mask 1 is active (= 1)
This means it’s getting it’s source from the foreground image.


– Mask 1 is not active (= 0)
This means it’s getting it’s source from the background image.
– Mask 2 is active at 0.5
This means it will only be half as bright as the original image.


– Mask 1 is not active (= 0)
This means it’s getting it’s source from the background image.
– Mask 2 is not active (= 0=
So that it doesn’t interfere with the shadow.

fgR = fg(:,:,1);
fgG = fg(:,:,2);
fgB = fg(:,:,3);
fgY = 0.3*fgR+0.59*fgG+0.11*fgB;
thres1 = 150/255;
thres2 = 200/255;
mask1 = fgG_Y < thres1;
mask2 = fgG_Y < thres2;
final(:,:,1)=fg(:,:,1).*mask1 + bg(:,:,1).*(1-mask1).*(mask2)*0.5 + bg(:,:,1).*(1-mask1).*(1-mask2);
final(:,:,2)=fg(:,:,2).*mask1 + bg(:,:,2).*(1-mask1).*(mask2)*0.5 + bg(:,:,2).*(1-mask1).*(1-mask2);
final(:,:,3)=fg(:,:,3).*mask1 + bg(:,:,3).*(1-mask1).*(mask2)*0.5 + bg(:,:,3).*(1-mask1).*(1-mask2);

Screen Shot 2014-11-13 at 11.07.03

Softening the shadow

For a more realistic effect we would want to soften out the shadow a little bit. This is simply done by averaging the shadow mask.

H=fspecial(‘average’, [20,20]);

and using mask_av instead of mask2.

This is the result:

Screen Shot 2014-11-13 at 11.08.04

Author: Bea Cabrera

Freelance Filmmaker with a passion for big cities, snowboard, cinema and a weakness for the smell of freshly ground coffee. Engineer & Graphic Designer in a previous life, loving and living both: art and technology.  

One Reply to “Chromakeying in Matlab”

  1. nadya safitri says: June 29, 2015 at 9:59 am

    when i use the code program in here , notifed : Undefined function ‘mat2gray’ for input arguments of type ‘double’.
    how solve it? please help me :(

Leave a Reply

Your email address will not be published.

You may use these <abbr title="HyperText Markup Language">html</abbr> tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


This site uses Akismet to reduce spam. Learn how your comment data is processed.