core/vil/algo/vil_colour_space.cxx
Go to the documentation of this file.
00001 // This is core/vil/algo/vil_colour_space.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "vil_colour_space.h"
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_algorithm.h>
00012 #include <vcl_cmath.h>
00013 
00014 template <class T>
00015 void vil_colour_space_RGB_to_YIQ(T const in[3], T out[3])
00016 {
00017   out[0] = T(0.299) * in[0] + T(0.587) * in[1] + T(0.114) * in[2];
00018   out[1] = T(0.595716) * in[0] - T(0.274453) * in[1] - T(0.321263) * in[2];
00019   out[2] = T(0.211456) * in[0] - T(0.522591) * in[1] + T(0.311135) * in[2];
00020 }
00021 
00022 template <class T>
00023 void vil_colour_space_YIQ_to_RGB(T const in[3], T out[3])
00024 {
00025   out[0] = in[0] + T(0.956296) * in[1] + T(0.621024) * in[2];
00026   out[1] = in[0] - T(0.272122) * in[1] - T(0.647381) * in[2];
00027   out[2] = in[0] - T(1.106989) * in[1] + T(1.704615) * in[2];
00028 }
00029 
00030 //:
00031 // \verbatim
00032 //     green --- yellow     //
00033 //    /    \     /     \    //
00034 // cyan --- white ---- red  //
00035 //    \    /     \     /    //
00036 //     blue  --- magenta    //
00037 //                          //
00038 // \endverbatim
00039 
00040 template <class T>
00041 void vil_colour_space_RGB_to_HSV(T r, T g, T b, T *h, T *s, T *v)
00042 {
00043   T max = vcl_max(r, vcl_max(g, b));
00044   T min = vcl_min(r, vcl_min(g, b));
00045 
00046   // The value v is just the maximum.
00047   *v = max;
00048 
00049   // Next, saturation.
00050   if (max > 0)
00051     *s = (max - min)/max;
00052   else
00053     *s = 0;
00054 
00055   // Lastly, the hue:
00056   if (*s == 0)
00057     *h = T(); // The hue is undefined in the achromatic case.
00058   else {
00059     T delta = max - min;
00060     if      (r == max)
00061       *h = (g - b)/delta;
00062     else if (g == max)
00063       *h = 2 + (b - r)/delta;
00064     else if (b == max)
00065       *h = 4 + (r - g)/delta;
00066     else
00067       vcl_abort();
00068 
00069     *h *= 60;
00070     if (*h < 0)
00071       *h += 360;
00072   }
00073 }
00074 
00075 template <class T>
00076 void vil_colour_space_HSV_to_RGB(T h, T s, T v, T *r, T *g, T *b)
00077 {
00078   T p1, p2, p3, f, nr=0, ng=0, nb=0;
00079   T xh;
00080   int i;
00081 
00082   v = v/255;
00083 
00084 #if 0
00085   extern float hue,  s,  v;  // hue (0.0 to 360.0, is circular, 0=360)
00086                              // s and v are from 0.0 to 1.0
00087   extern long  r2,  g2,  b2; // values from 0 to 63
00088 #endif
00089 
00090   h -= int(h/360)*360;       // (THIS LOOKS BACKWARDS)
00091   if (h < 0) h += 360;
00092 
00093   xh = h / 60;                   // convert hue to be in [0,6)
00094   i = (int)vcl_floor((double)xh);// i = greatest integer <= xh
00095   f = xh - i;                    // f = fractional part of xh
00096   p1 = v * (1 - s);
00097   p2 = v * (1 - (s * f));
00098   p3 = v * (1 - (s * (1 - f)));
00099 
00100   switch (i)
00101   {
00102     case 0:
00103             nr = v;
00104             ng = p3;
00105             nb = p1;
00106             break;
00107     case 1:
00108             nr = p2;
00109             ng = v;
00110             nb = p1;
00111             break;
00112     case 2:
00113             nr = p1;
00114             ng = v;
00115             nb = p3;
00116             break;
00117     case 3:
00118             nr = p1;
00119             ng = p2;
00120             nb = v;
00121             break;
00122     case 4:
00123             nr = p3;
00124             ng = p1;
00125             nb = v;
00126             break;
00127     case 5:
00128             nr = v;
00129             ng = p1;
00130             nb = p2;
00131             break;
00132     default:
00133             break; // cannot be reached
00134   }
00135 
00136   *r = nr * 255; // Normalize the values to 63
00137   *g = ng * 255;
00138   *b = nb * 255;
00139   return;
00140 }
00141 
00142 
00143 template <class T>
00144 void vil_colour_space_RGB_to_YUV(T const in[3], T out[3])
00145 {
00146   out[0] = T(0.299) * in[0] + T(0.587) * in[1] + T(0.114) * in[2];
00147   out[1] = T(0.492) * (in[2] - out[0]);
00148   out[2] = T(0.877) * (in[0] - out[0]);
00149 }
00150 
00151 
00152 template <class T>
00153 void vil_colour_space_YUV_to_RGB(T const in[3], T out[3])
00154 {
00155   // the coefficient of the inverse are given here to higher precision
00156   // than typically used.  This allows for more accurate results when
00157   // working with floating point color representations
00158   out[0] = in[0] + T(1.1402508551881) * in[2];
00159   out[1] = in[0] - T(0.39473137491174) * in[1] - T(0.5808092090311) * in[2];
00160   out[2] = in[0] + T(2.0325203252033) * in[1];
00161 }
00162 
00163 // YPbPr (ITU-R BT.601)
00164 // ========================================================
00165 // Y' =     + 0.299    * R' + 0.587    * G' + 0.114    * B'
00166 // Pb =     - 0.168736 * R' - 0.331264 * G' + 0.5      * B'
00167 // Pr =     + 0.5      * R' - 0.418688 * G' - 0.081312 * B'
00168 // ........................................................
00169 // R', G', B' in [0; 1]
00170 // Y' in [0; 1]
00171 // Pb in [-0.5; 0.5]
00172 // Pr in [-0.5; 0.5]
00173 template <class T>
00174 void vil_colour_space_RGB_to_YPbPr_601(T const RGB[3], T YPbPr[3])
00175 {
00176   YPbPr[0] = T(0.299)    * RGB[0] + T(0.587)    * RGB[1] + T(0.114)    * RGB[2];
00177   YPbPr[1] = T(-0.168736)* RGB[0] - T(0.331264) * RGB[1] + T(0.5)      * RGB[2];
00178   YPbPr[2] = T(0.5)      * RGB[0] - T(0.418688) * RGB[1] - T(0.081312) * RGB[2];
00179 }
00180 
00181 // YPbPr (ITU-R BT.601)
00182 // ==========================================================
00183 // R' =     + 0.299    * Y' + 0.587    * Pb' + 0.114    * Pr'
00184 // G' =     - 0.168736 * Y' - 0.331264 * Pb' + 0.5      * Pr'
00185 // B' =     + 0.5      * Y' - 0.418688 * Pb' - 0.081312 * Pr'
00186 // ..........................................................
00187 // Y' in [0; 1]
00188 // Pb in [-0.5; 0.5]
00189 // Pr in [-0.5; 0.5]
00190 // R', G', B' in [0; 1]
00191 template <class T>
00192 void vil_colour_space_YPbPr_601_to_RGB(T const YPbPr[3], T RGB[3])
00193 {
00194   RGB[0] = vcl_max(T(0.0), vcl_min(T(1.0), (YPbPr[0]                          + T(1.402)    * YPbPr[2])));
00195   RGB[1] = vcl_max(T(0.0), vcl_min(T(1.0), (YPbPr[0] - T(0.344136) * YPbPr[1] - T(0.714136) * YPbPr[2])));
00196   RGB[2] = vcl_max(T(0.0), vcl_min(T(1.0), (YPbPr[0] + T(1.772)    * YPbPr[1]                         )));
00197 }
00198 
00199 // YCbCr (601) from "digital 8-bit R'G'B'  "
00200 // ========================================================================
00201 // Y' = 16  + 1/256 * (   65.738  * R'd +  129.057  * G'd +  25.064  * B'd)
00202 // Cb = 128 + 1/256 * ( - 37.945  * R'd -   74.494  * G'd + 112.439  * B'd)
00203 // Cr = 128 + 1/256 * (  112.439  * R'd -   94.154  * G'd -  18.285  * B'd)
00204 // ........................................................................
00205 // R'd, G'd, B'd in {0, 1, 2, ..., 255}
00206 // Y'               in {16, 17, ..., 235}
00207 //    with footroom in {1, 2, ..., 15}
00208 //         headroom in {236, 237, ..., 254}
00209 //         sync.    in {0, 255}
00210 // Cb, Cr           in {16, 17, ..., 240}
00211 void vil_colour_space_RGB_to_YCbCr_601(const unsigned char RGB[3], unsigned char YCbCr[3])
00212 {
00213   // Add an extra 0.5555555 to round instead of truncate
00214   YCbCr[0] = static_cast<unsigned char>(
00215     16.0  + (  65.738 * RGB[0] + 129.057 * RGB[1] +  25.064 * RGB[2])/256.0 + 0.55555555);
00216   YCbCr[1] = static_cast<unsigned char>(
00217     128.0 + ( -37.945 * RGB[0] -  74.494 * RGB[1] + 112.439 * RGB[2])/256.0 + 0.55555555);
00218   YCbCr[2] = static_cast<unsigned char>(
00219     128.0 + ( 112.439 * RGB[0] -  94.154 * RGB[1] -  18.285 * RGB[2])/256.0 + 0.55555555);
00220 }
00221 
00222 // 8-bit R'G'B' from YCbCr (601)
00223 // =====================================================================
00224 // R'd = ( 298.082 * Y'                + 408.583 * Cr ) / 256 - 222.921
00225 // G'd = ( 298.082 * Y' - 100.291 * Cb - 208.120 * Cr ) / 256 + 135.576
00226 // B'd = ( 298.082 * Y' + 516.412 * Cb                ) / 256 - 276.836
00227 void vil_colour_space_YCbCr_601_to_RGB(const unsigned char YCbCr[3], unsigned char RGB[3])
00228 {
00229   RGB[0] = static_cast<unsigned char>(
00230     (298.082 * YCbCr[0]                      + 408.583 * YCbCr[2]) / 256.0 - 222.921);
00231   RGB[1] = static_cast<unsigned char>(
00232     (298.082 * YCbCr[0] - 100.291 * YCbCr[1] - 208.120 * YCbCr[2]) / 256.0 + 135.576);
00233   RGB[2] = static_cast<unsigned char>(
00234     (298.082 * YCbCr[0] + 516.412 * YCbCr[1]                     ) / 256.0 - 276.836);
00235 }
00236 
00237 
00238 //----------------------------------------------------------------------
00239 
00240 #define inst(T) \
00241 template void vil_colour_space_RGB_to_YIQ(T const [3], T [3]); \
00242 template void vil_colour_space_YIQ_to_RGB(T const [3], T [3]); \
00243 template void vil_colour_space_RGB_to_HSV(T, T, T, T *, T *, T *); \
00244 template void vil_colour_space_HSV_to_RGB(T, T, T, T *, T *, T *); \
00245 template void vil_colour_space_RGB_to_YUV(T const [3], T [3]); \
00246 template void vil_colour_space_YUV_to_RGB(T const [3], T [3]); \
00247 template void vil_colour_space_RGB_to_YPbPr_601(T const RGB[3], T YPbPr[3]); \
00248 template void vil_colour_space_YPbPr_601_to_RGB(T const YPbPr[3], T RGB[3])
00249 
00250 inst(double);
00251 inst(float);