Colour Models
Skin Data Set: you can download the skin data set here.
--------------------------
Dear readers,
Here you can find most of the colour transformations that we used in the papers:
G. Gomez
On selecting colour components for skin detection Proc. of the ICPR, vol. 2: 961-964, 2002. G. Gomez, E. Morales Automatic feature construction and a simple rule induction algorithm for skin detection Proc. of the ICML Workshop on Machine Learning in Computer Vision, pp. 31-38, 2002. G. Gomez, M. Sanchez, L. E. Sucar On selecting an appropriate colour space for skin detection Proc. of the 2nd MICAI, Springer-Verlag: LNCS, 2313: 3-18, 2002. --------------------------
Notice that we merged several thousand small patches into larger files of 500x500 pixels. Therefore, the visual pattern of every file seems to be strange, i.e. a colourful collage! Skin samples come from different racial origin, age and gender, and under different illumination conditions. A number of digital and video cameras were used to prepare the data sets, no scanners were employed. The full description appears in the ICPR paper.
HSV
/*** h: chroma as an angle; s: saturation; v: value ~= intensity ***/
void rgb2hsv(r,g,b, hr, sr, vr)
int r, g, b;
double *hr, *sr, *vr;
{
double rn, gn, bn, h, s, max, min, del;
/* scaling r,g,b */
rn = r / 255.0;
gn = g / 255.0;
bn = b / 255.0;
/* compute maximum of rn,gn,bn */
if (rn>=gn) { if (rn>=bn) max = rn; else max = bn; }
else { if (gn>=bn) max = gn; else max = bn; }
/* compute minimum of rn,gn,bn */
if (rn<=gn) { if (rn<=bn) min = rn; else min = bn; }
else { if (gn<=bn) min = gn; else min = bn; }
del = max - min;
*vr = max;
if (max != 0.0)
s = (del) / max;
else
s = 0.0; /* r = g = b */
h = NODEF;
if (s != 0.0) {
if (rn==max) h = (gn - bn) / del; /* between yellow & magenta */
else if (gn==max) h = 2 + ((bn - rn) / del); /* between cyan & yellow */
else if (bn==max) h = 4 + ((rn - gn) / del); /* between magenta & cyan */
/* Typo in the paper, Hue should be: -60 < h < 300. Apologies! */
h = h * 60;
}
*hr = h; *sr = s;
}
YIQ
/*** y: luminance, i:fase, q:quadrature ***/
void rgb2yiq (int r, int g, int b, double *y, double *i, double *q){
*y = 0.299*r + 0.587*g + 0.114*b;
*i = 0.596*r - 0.275*g - 0.321*b; /* sometimes found as +0.275*g */
*q = 0.212*r - 0.523*g + 0.311*b;
}
RGB-Y
/*** Red/Green/Blue - Yellow ***/
void rgb2rgby (int r, int g, int b, double *ry, double *gy, double *by){
*ry = 0.70*r - 0.59*g - 0.11*b;
*gy = -0.30*r + 0.41*g - 0.11*b;
*by = -0.30*r - 0.59*g + 0.89*b;
}
YES
/*** E. Saber, A. M. Telkap, PRL, vol 19, pp. 669-680, 1998 ***/
void rgb2yes(int r, int g, int b, double *y, double *e, double *s){
*y = r*0.253 + g*0.684 + b*0.063;
*e = r*0.5 - g*0.5;
*s = r*0.25 + g*0.25 - b*0.5;
}
CIE YUV
/*** CIE YUV ***/
void rgb2yuv(int r, int g, int b, double *y, double *u, double *v){
double rn, gn, bn;
rn = r / 255.0;
bn = b / 255.0;
gn = g / 255.0;
*y = (rn + 2*gn + bn) / 4.0;
*u = (rn - gn) / 2.0;
*v = (bn - gn) / 2.0;
}
CIE XYZ
/*** CIE XYZ ***/
void rgb2xyz(int r, int g, int b, double *x, double *y, double *z){
double rn = r / 255.0;
double gn = g / 255.0;
double bn = b / 255.0;
*x = 0.621*rn + 0.113*gn + 0.194*bn;
*y = 0.297*rn + 0.563*gn + 0.049*bn;
*z = -0.009*rn + 0.027*gn + 1.105*bn;
}
CIE L*a*b
/*** CIE XYZ to CIE L*a*b. White RGB set to 240,240,240 ***/
void rgb2lab(int rd, int gr, int bl, double *l, double *a, double *b){
double fx, fy, fz;
double x, y, z;
/* we do need XYZ */
rgb2xyz(rd, gr, bl, &x, &y, &z);
fx = x / WHITE_X;
fy = y / WHITE_Y;
fz = z / WHITE_Z;
/* L */
if ( fy > 0.008856 )
*l = 116.0 * pow(fy, 0.33333333) - 16.0;
else
*l = 903.3 * fy;
/* a */
if ( fx > 0.008856 )
*a = pow (fx, 0.33333333);
else
*a = (7.787 * fx) + 16/116.0;
if ( fy > 0.008856 )
*a = *a - pow(fy, 0.33333333);
else
*a = *a - ((7.787 * fy) + 16/116.0);
*a = *a * 500.0;
/* b */
if ( fy > 0.008856 )
*b = pow(fy, 0.33333333);
else
*b = (7.787 * fy) + 16/116.0;
if ( fz > 0.008856 )
*b = *b - pow(fz, 0.33333333);
else
*b = *b - ((7.787 * fz) + 16/116.0);
*b = *b * 200.0;
}
CIE u'v'w'
/*** CIE u'v'w' ***/
void xyz2uvwprime(x, y, z, up, vp, wp)
double x, y, z, *up, *vp, *wp;
{
double denom;
denom = x + 15.0 * y + 3.0 * z;
if (denom > 0){
*up = 4.0 * x / denom;
*vp = 9.0 * y / denom;
*wp = (-3.0*x + 6.0*y + 3.0*z) / denom;
}else{
*up = 4.0;
*vp = 9.0;
*wp = 3.0;
}
}
CIE L*u*v
/*** CIE L*u*v ***/
void rgb2luv(int r, int g, int b, double *l, double *u, double *v){
double unprime, vnprime, wnprime; /* white reference */
double uprime, vprime, wprime;
double x, y, z, fx, fy;
rgb2xyz(r, g, b, &x, &y, &z);
fx = x / WHITE_X;
fy = y / WHITE_Y;
if ( fy > 0.008856 )
*l = 116.0 * pow(fy, 0.33333333) - 16.0;
else
*l = 903.3 * fy;
xyz2uvwprime(WHITE_X, WHITE_Y, WHITE_Z, &unprime, &vnprime, &wnprime);
xyz2uvwprime(x, y, z, &uprime, &vprime, &wprime);
*u = *l * 13.0 * (uprime - unprime);
*v = *l * 13.0 * (vprime - vnprime);
}
CIE xyY
/*** CIE xyY ***/
void rgb2xyY(int r, int g, int b, double *x, double *y, double *Y){
double denom, z, x1, y1;
rgb2xyz(r, g, b, &x1, &y1, &z);
denom = x1 + y1 + z;
*Y = r*0.2126/255.0 + g*0.7152/255.0 + b*0.0722/255.0;
if (denom > 0){
*x = x1 / denom;
*y = y1 / denom;
}else{
*x = 0;
*y = 0;
}
}
YCrCb
/*** Chrominance red and blue ***/
void rgb2ycrcb(int r, int g, int b, double *Y, double *Cr, double *Cb){
double rn, gn, bn;
rn = r / 255.0;
gn = g / 255.0;
bn = b / 255.0;
*Y = 65.481*rn + 128.553*gn + 24.966*bn + 16.0;
*Cr = 112.000*rn - 93.7860*gn - 18.214*bn + 128.0;
*Cb = -37.797*rn - 74.2030*gn + 112.00*bn + 128.0;
}
Wr (M.Soriano et al. ICPR 2000)
/*** M. Soriano's paper in the ICPR 2000 ***/
void rgb2wr(int r, int g, int b, double *wr){
double n;
n = r + g + b;
if ( n > 0 )
*wr = (r/n - 0.33333) * (r/n - 0.33333) \
+ (g/n - 0.33333) * (g/n - 0.33333);
else
*wr = NODEF;
}