As you know (or may not) OpenCV is a much featured computer vision library. But unfortunately the developers were unable to offer functionalities like shadow removing. So, if we need it then we have to do it ourselves.
When I needed it, I searched for a code all over the internet but couldn’t find one. Therefore I had to go through some research papers and develop a shadow removing algorithm with OpenCV myself. To avoid you for searching like that again (and wasting time also), here I’ll give you my implementation.
“A shadow is normally an area that is not or only partially irradiated or illuminated because of the interception of radiation by an opaque object between the area and the source of radiation. Assuming that the irradiation consists only of white light, the chromaticity in a shadowed region should be the same as when it is directly illuminated.”
- Shadow Removal with Morphological Reconstruction
“Important physical properties of the surface in color vision are surface spectral reflectance properties, which are invariant to changes of illumination, scene composition or geometry. On Lambertain, or perfectly matte surfaces, the perceived color is the product of illumination and surface spectral reflectance.”
- A Statistical Approach for Real-time Robust Background Subtraction and Shadow Detection
So, here we decomposed the background and foreground pixels into brightness and chromaticity components.
Then we only have to do the threshold the X and W. (W can obtain from the derivation of that first expression means,
W = Foreground x Background / Background x Background)
/* Here I used my own, IplImage wrappers called,
* CytImage –> 8 bit (uchar), 3 channels IplImage wrapper
* CytBWImage –> 8 bit (uchar), 1 channel(as a binay image)
* IplImage wrapper
* They both have a function called, Pixel(int x, int y, int channel)
* to get the channel values in pixel at i, j position.
* So, you should make your own wrappers for this.
float back_r, back_g, back_b, back_sum;
float fore_r, fore_g, fore_b,fore_sum;
float product_r, product_g, product_b;
float product_back_r, product_back_g, product_back_b;
float BD = 0.0f;
float CD_r, CD_g, CD_b, CD_squared;
for ( int i = 0; i < coloredBackground.Width; ++i)
for ( int j = 0; j < coloredBackground.Height; ++j)
back_r = ( float )coloredBackground.Pixel(i , j, 0);
back_g = ( float )coloredBackground.Pixel(i , j, 1);
back_b = ( float )coloredBackground.Pixel(i , j, 2);
back_sum = back_r + back_g + back_b;
fore_r = ( float )coloredForeground.Pixel(i , j, 0);
fore_g = ( float )coloredForeground.Pixel(i , j, 1);
fore_b = ( float )coloredForeground.Pixel(i , j, 2);
fore_sum = fore_r + fore_g + fore_b;
product_r = fore_r * back_r;
product_g = fore_g * back_g;
product_b = fore_b * back_b;
product_back_r = back_r * back_r;
product_back_g = back_g * back_g;
product_back_b = back_b * back_b;
BD = (product_r + product_g + product_b) /
(product_back_r + product_back_g + product_back_b);
CD_r = fore_r – BD * back_r;
CD_g = fore_g – BD * back_g;
CD_b = fore_b – BD * back_b;
CD_squared = CD_r * CD_r + CD_g * CD_g + CD_b * CD_b;
des(i, j) = (CD_squared < 120.0f && BD < 1.0f && BD > 0.5f)
? 0 /*Background*/ : 255 /*Foreground*/ ;
// You can play with these 2 values.