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
YIQ
RGB-Y
YCrCb
YES
CIE YUV
Wr
CIE XYZ
CIE L*a*b
CIE u'v'w'
CIE L*u*v
CIE xyY


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