// ---------------------------------------------------------------------- // color_conv.c // 21.02.2005, Jens Ahrensfeld // ---------------------------------------------------------------------- #include #include #include "color_conv.h" #include "colortypes.h" #include "mutil.h" // ---------------------------------------------------------------------- void rgb2hsv(color_vector_t *pRGB, color_vector_t *pHSV, int len) { int i; double *rgb, *hsv, v_min, v_max, diff_max, diff_max_r, diff_r, diff_g, diff_b; for (i=0; i < len; i++) { rgb = (double*)&pRGB[i]; hsv = (double*)&pHSV[i]; v_min = smin(rgb[0], rgb[1]); v_min = smin(v_min, rgb[2]); v_max = smax(rgb[0], rgb[1]); v_max = smax(v_max, rgb[2]); diff_max = v_max - v_min; hsv[2] = v_max; if (diff_max == 0) { hsv[0] = diff_max; hsv[1] = diff_max; } else { diff_max_r = 1.0/diff_max; hsv[1] = diff_max/v_max; diff_r = (((v_max - rgb[0])*(1.0/6)) + (0.5*diff_max))*diff_max_r; diff_g = (((v_max - rgb[1])*(1.0/6)) + (0.5*diff_max))*diff_max_r; diff_b = (((v_max - rgb[2])*(1.0/6)) + (0.5*diff_max))*diff_max_r; if (rgb[0] == v_max) { hsv[0] = diff_b - diff_g; } else { if (rgb[1] == v_max) { hsv[0] = 1.0/3 + diff_r - diff_b; } else { if (rgb[2] == v_max) { hsv[0] = 2.0/3 + diff_g - diff_r; } } } if (hsv[0] < 0) hsv[0] += 1; if (hsv[0] > 1.0) hsv[0] -= 1; } } } // ---------------------------------------------------------------------- void hsv2rgb(color_vector_t *pHSV, color_vector_t *pRGB, int len) { int i, j; double h, t1, t2, t3, *rgb, *hsv; for (i=0; i < len; i++) { rgb = (double*)&pRGB[i]; hsv = (double*)&pHSV[i]; if (hsv[1] == 0) { rgb[0] = hsv[2]; rgb[1] = hsv[2]; rgb[2] = hsv[2]; continue; } h = hsv[0] * 6; j = (int)h; t1 = hsv[2]*(1 - hsv[1]); t2 = hsv[2]*(1 - hsv[1]*(h-(double)j)); t3 = hsv[2]*(1 - hsv[1]*(1-(h-(double)j))); switch(j) { case 0: rgb[0] = hsv[2]; rgb[1] = t3; rgb[2] = t1; break; case 1: rgb[0] = t2; rgb[1] = hsv[2]; rgb[2] = t1; break; case 2: rgb[0] = t1; rgb[1] = hsv[2]; rgb[2] = t3; break; case 3: rgb[0] = t1; rgb[1] = t2; rgb[2] = hsv[2]; break; case 4: rgb[0] = t3; rgb[1] = t1; rgb[2] = hsv[2]; break; default: rgb[0] = hsv[2]; rgb[1] = t1; rgb[2] = t2; break; } } } // ---------------------------------------------------------------------- void rgb2hsl(color_vector_t *pRGB, color_vector_t *pHSL, int len) { int i; double *rgb, *hsl, v_min, v_max, diff_max, diff_max_r, diff_r, diff_g, diff_b; for (i=0; i < len; i++) { rgb = (double*)&pRGB[i]; hsl = (double*)&pHSL[i]; v_min = smin(rgb[0], rgb[1]); v_min = smin(v_min, rgb[2]); v_max = smax(rgb[0], rgb[1]); v_max = smax(v_max, rgb[2]); diff_max = v_max - v_min; hsl[2] = (v_max + v_min)/2; if (diff_max == 0) { hsl[0] = diff_max; hsl[1] = diff_max; } else { diff_max_r = 1.0/diff_max; if(hsl[2] < 0.5) { hsl[1] = diff_max/(v_max + v_min); } else { hsl[1] = diff_max/(2 - v_max - v_min); } diff_r = (((v_max - rgb[0])*(1.0/6)) + (0.5*diff_max))*diff_max_r; diff_g = (((v_max - rgb[1])*(1.0/6)) + (0.5*diff_max))*diff_max_r; diff_b = (((v_max - rgb[2])*(1.0/6)) + (0.5*diff_max))*diff_max_r; if (rgb[0] == v_max) { hsl[0] = diff_b - diff_g; } else { if (rgb[1] == v_max) { hsl[0] = 1.0/3 + diff_r - diff_b; } else { if (rgb[2] == v_max) { hsl[0] = 2.0/3 + diff_g - diff_r; } } } if (hsl[0] < 0) hsl[0] += 1; if (hsl[0] > 1.0) hsl[0] -= 1; } } } // ---------------------------------------------------------------------- inline double Hue_2_RGB(double v1, double v2, double vH) //Function Hue_2_RGB { if (vH < 0) vH += 1; if (vH > 1) vH -= 1; if ((6*vH) < 1) return v1 + (v2 - v1)*6*vH; if ((2*vH) < 1) return v2; if ((3*vH) < 2) return v1 + (v2 - v1)*((2.0/3) - vH)*6; return v1; } // ---------------------------------------------------------------------- void hsl2rgb(color_vector_t *pHSL, color_vector_t *pRGB, int len) { int i, j; double h, t1, t2, t3, *rgb, *hsl; for (i=0; i < len; i++) { rgb = (double*)&pRGB[i]; hsl = (double*)&pHSL[i]; if (hsl[1] == 0) { rgb[0] = hsl[2]; rgb[1] = hsl[2]; rgb[2] = hsl[2]; continue; } if(hsl[2] < 0.5) { t2 = hsl[2]*(1 + hsl[1]); } else { t2 = (hsl[2] + hsl[1]) - hsl[2]*hsl[1]; } t1 = 2*hsl[2] - t2; rgb[0] = Hue_2_RGB(t1, t2, hsl[0] + 1.0/3); rgb[1] = Hue_2_RGB(t1, t2, hsl[0]); rgb[2] = Hue_2_RGB(t1, t2, hsl[0] - 1.0/3); } } // ---------------------------------------------------------------------- void rgb2xyz(double **ppRGB, double **ppXYZ, int len) { int i, j; double rgb[3]; double *pRGB, *pXYZ; for (i=0; i < len; i++) { pRGB = ((double*)ppRGB[i]); pXYZ = ((double*)ppXYZ[i]); for (j=0; j < 3; j++) { if (pRGB[j] > 0.04045) { rgb[j] = pow((pRGB[j]+0.055)/1.055,2.4); } else { rgb[j] = 1.0/12.92 * pRGB[j]; } rgb[j] *= K_XYZ; } // Observer = 2°, Illuminant = D65 pXYZ[0] = 0.412453*rgb[0] + 0.357580*rgb[1] + 0.180423*rgb[2]; pXYZ[1] = 0.212671*rgb[0] + 0.715160*rgb[1] + 0.072169*rgb[2]; pXYZ[2] = 0.019334*rgb[0] + 0.119193*rgb[1] + 0.950227*rgb[2]; } } // ---------------------------------------------------------------------- void xyz2rgb(double **ppXYZ, double **ppRGB, int len) { int i, j; double xyz[3]; double *pRGB, *pXYZ; for (i=0; i < len; i++) { pRGB = ((double*)ppRGB[i]); pXYZ = ((double*)ppXYZ[i]); for (j=0; j < 3; j++) { xyz[j] = 1.0/K_XYZ * pXYZ[j]; } // Observer = 2°, Illuminant = D65 pRGB[0] = 3.240479*xyz[0] - 1.537150*xyz[1] - 0.498535*xyz[2]; pRGB[1] = -0.969256*xyz[0] + 1.875992*xyz[1] + 0.041556*xyz[2]; pRGB[2] = 0.055648*xyz[0] - 0.204043*xyz[1] + 1.057311*xyz[2]; for (j=0; j < 3; j++) { if (pRGB[j] > 0.0031308) { pRGB[j] = 1.055 * pow(pRGB[j],1.0/2.4) - 0.055; } else { pRGB[j] = 12.92 * pRGB[j]; } } } } // ---------------------------------------------------------------------- void xyz2lab(double **ppXYZ, double **ppLAB, double *pRef, int len) { int i, j; double xyz[3] = {0}; double *pLAB, *pXYZ; for (i=0; i < len; i++) { pXYZ = ((double*)ppXYZ[i]); pLAB = ((double*)ppLAB[i]); for (j=0; j < 3; j++) { xyz[j] = pXYZ[j] / pRef[j]; } for (j=0; j < 3; j++) { if (xyz[j] > 0.008856) { xyz[j] = pow(xyz[j],1.0/3.0); } else { xyz[j] = 7.787*xyz[j] + 16.0/116.0; } } pLAB[0] = 116.0*xyz[1] - 16; pLAB[1] = 500.0*(xyz[0] - xyz[1]); pLAB[2] = 200.0*(xyz[1] - xyz[2]); } } // ---------------------------------------------------------------------- void lab2xyz(double **ppLAB, double **ppXYZ, double *pRef, int len) { int i, j; double xyz[3], xyz3; double *pLAB, *pXYZ; for (i=0; i < len; i++) { pXYZ = ((double*)ppXYZ[i]); pLAB = ((double*)ppLAB[i]); xyz[1] = 1.0/116.0*(pLAB[0] + 16); xyz[0] = 1.0/500.0*pLAB[1] + xyz[1]; xyz[2] = xyz[1] - 1.0/200.0*pLAB[2]; for (j=0; j < 3; j++) { xyz3 = pow(xyz[j],3.0); if (xyz3 > 0.008856) { xyz[j] = xyz3; } else { xyz[j] = 1.0/7.787*(xyz[j] - 16.0/116); } } for (j=0; j < 3; j++) { pXYZ[j] = xyz[j] *pRef[j]; } } } // ---------------------------------------------------------------------- void tristimulus(double *pRef, unsigned illuminant_type, unsigned observer_type) { double ref[3] = {K_XYZ*0.95047, K_XYZ*1.0, K_XYZ*1.08883}; if(observer_type == OBS_TYPE_2DEG) { switch (illuminant_type) { case ILLU_TYPE_A: case ILLU_TYPE_INCANDESCENT: pRef[0] = K_XYZ*1.09850; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.35585; break; case ILLU_TYPE_C: pRef[0] = K_XYZ*0.98074; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.18232; break; case ILLU_TYPE_D50: pRef[0] = K_XYZ*0.96422; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.82521; break; case ILLU_TYPE_D55: pRef[0] = K_XYZ*0.95682; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.92149; break; case ILLU_TYPE_D65: case ILLU_TYPE_DAYLIGHT: pRef[0] = K_XYZ*0.95047; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.08883; break; case ILLU_TYPE_D75: pRef[0] = K_XYZ*0.94972; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.22638; break; case ILLU_TYPE_F2: case ILLU_TYPE_FLUORESCENT: pRef[0] = K_XYZ*0.99187; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.67395; break; case ILLU_TYPE_F7: pRef[0] = K_XYZ*0.95044; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.08755; break; case ILLU_TYPE_F11: pRef[0] = K_XYZ*1.00966; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.64370; break; default: memcpy(pRef, ref, 3*sizeof(double)); break; } } if(observer_type == OBS_TYPE_10DEG) { switch (illuminant_type) { case ILLU_TYPE_A: case ILLU_TYPE_INCANDESCENT: pRef[0] = K_XYZ*1.11144; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.35200; break; case ILLU_TYPE_C: pRef[0] = K_XYZ*0.97285; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.16145; break; case ILLU_TYPE_D50: pRef[0] = K_XYZ*0.96720; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.81427; break; case ILLU_TYPE_D55: pRef[0] = K_XYZ*0.95799; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.90926; break; case ILLU_TYPE_D65: case ILLU_TYPE_DAYLIGHT: pRef[0] = K_XYZ*0.94811; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.07304; break; case ILLU_TYPE_D75: pRef[0] = K_XYZ*0.94416; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.20641; break; case ILLU_TYPE_F2: case ILLU_TYPE_FLUORESCENT: pRef[0] = K_XYZ*1.03280; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.69026; break; case ILLU_TYPE_F7: pRef[0] = K_XYZ*0.95792; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*1.07687; break; case ILLU_TYPE_F11: pRef[0] = K_XYZ*1.03866; pRef[1] = K_XYZ*1.0; pRef[2] = K_XYZ*0.65627; break; default: memcpy(pRef, ref, 3*sizeof(double)); break; } } } void rgb2rgb(double **ppSrc, double **ppDst, int len) { int i, j; double *pSrc, *pDst; for (i=0; i < len; i++) { pSrc = ((double*)ppSrc[i]); pDst = ((double*)ppDst[i]); for (j=0; j < 3; j++) { pDst[j] = pSrc[j]; } } }