gml_HSVColor.h

00001 // gml_HSVColor.h --
00002 // 
00003 //  Defines the gml_TColor_HSV class template
00004 // 
00005 // Copyright (c) 2004 CLIPS-IMAG
00006 // 
00007 // See the file "gml_LicenseTerms.txt" for information on usage and redistribution
00008 // of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00009 // 
00010 //  Created on January 9, 2004 (JL).
00011 
00012 
00013 #ifndef __GML_HSVCOLOR__
00014 #define __GML_HSVCOLOR__
00015 
00016 #include <assert.h>
00017 #include "gml/base/gml_Types.h"
00018 #include "gml/base/gml_Attributes.h"
00019 #include "gml/math/gml_Math.h"
00020 
00021 ///
00022 /// gml_TColor_HSV_FFF --
00023 ///   A union type used to represent HSV-encoded color pixels.
00024 ///   HSV is Smith's Hue, Saturation, Value colorspace.
00025 ///   The type (and bitwidth) used for each channel is the template parameter.
00026 ///
00027 ///   Some of this code is adapted from section 15.3.4 of "Computer Graphics:
00028 ///   Principles and Practice", by J.D. Foley and A. van Dam.
00029 ///
00030 class gml_TColor_HSV_FFF
00031 {
00032 public:
00033 
00034   ///
00035   /// Constructor --
00036   ///   Convert a 24-bit RGB triplet into HSV and fill in the object.
00037   ///
00038   gml_TColor_HSV_FFF (UInt8 const r, UInt8 const g, UInt8 const b) {
00039   
00040     UInt32 min = Min (r, g, b);
00041     UInt32 max = Max (r, g, b);
00042     Float32 delta, h, s, v;
00043     
00044     v = Divide (max , 255.0F);
00045     s = (max == 0) ? 0.0F : (Divide ((max-min) , max));
00046     
00047     if (s == 0.0F) { // achromatic case
00048       h = 0.0F;
00049     } else {
00050       delta = max - min;
00051       if (r == max)   {
00052         h =        Divide (Float32(g) - Float32(b), delta);
00053         if (h < 0.0) h += 6.0;
00054       } else if (g == max) {
00055         h = 2.0F + Divide (Float32(b) - Float32(r), delta);
00056       } else /*if (b == max)*/ {
00057         h = 4.0F + Divide (Float32(r) - Float32(g), delta);
00058       }
00059     }
00060     H = (1.0F / 6.0F) * h;
00061     S = s;
00062     V = v;
00063     
00064     assert (H >= 0.0F && H <= 1.0F);
00065     assert (S >= 0.0F && S <= 1.0F);
00066     assert (V >= 0.0F && V <= 1.0F);
00067   }
00068   
00069   
00070   ///
00071   /// Constructor --
00072   ///   Fill the structure from data in memory
00073   ///
00074   gml_TColor_HSV_FFF (const void * const ptr) { 
00075     *this = *((gml_TColor_HSV_FFF*)ptr);
00076   }
00077   
00078   
00079   ///
00080   /// Constructor --
00081   ///   Leave the structure `as is'.
00082   ///   I.e. probably zero.
00083   ///
00084   gml_TColor_HSV_FFF () {}
00085   
00086     
00087   ///
00088   /// Print --
00089   ///   Dump a representation of the pixel to stdout: channels in hex and
00090   ///   in degrees, percent, percent format.
00091   ///   @warning no newline appended !
00092   ///
00093   void Print () {
00094     printf ("%f %f %f (%3d %3d%% %3d%%)", 
00095       H, S, V, 
00096       (int) LRound (fmod(360.0 * H + 360.0, 360.0)),
00097       (int) LRound (100 * S),
00098       (int) LRound (100 * V)
00099       );
00100   }
00101   
00102   
00103   ///
00104   /// Store --
00105   ///   Place the structure's data in memory
00106   ///
00107   void Store (void * const ptr) {
00108     *((gml_TColor_HSV_FFF*)ptr) = *this;
00109   }
00110   
00111   ///
00112   /// Convert --
00113   ///   Convert the HSV data in this object to a 24 bit RGB triplet.
00114   ///
00115   void Convert (UInt8 &r, UInt8 &g, UInt8 &b) {
00116     Float32 fr = 0.0f;
00117     Float32 fg = 0.0f;
00118     Float32 fb = 0.0f;
00119 
00120     if (S == 0.0F) {
00121       r = g = b = (UInt8) LRound (V * 255.0);
00122     } else {
00123       Float32 i = Floor (6.0F * H);
00124       Float32 f = 6.0F * H - i;
00125       Float32 p = V * (1.0F - S);
00126       Float32 q = V * (1.0F - S * f);
00127       Float32 t = V * (1.0F - S * (1.0F - f));
00128       assert (p >= 0.0F && p <= 1.0F);
00129       assert (q >= 0.0F && q <= 1.0F);
00130       assert (t >= 0.0F && t <= 1.0F);
00131       assert (V >= 0.0F && V <= 1.0F);
00132       switch ((int) i) {
00133         case 0:  fr = V;  fg = t;  fb = p;  break;
00134         case 1:  fr = q;  fg = V;  fb = p;  break;
00135         case 2:  fr = p;  fg = V;  fb = t;  break;
00136         case 3:  fr = p;  fg = q;  fb = V;  break;
00137         case 4:  fr = t;  fg = p;  fb = V;  break;
00138         case 5:  fr = V;  fg = p;  fb = q;  break;
00139       }
00140       assert (fr <= 255.0 && fr >= 0.0);
00141       assert (fg <= 255.0 && fg >= 0.0);
00142       assert (fb <= 255.0 && fb >= 0.0);
00143       r = (UInt8) LRound (fr * 255.0);
00144       g = (UInt8) LRound (fg * 255.0);
00145       b = (UInt8) LRound (fb * 255.0);
00146     }
00147   }
00148   
00149   
00150   ///
00151   /// Distance --
00152   ///   Compute the 16-bit distance to another HSV pixel.
00153   ///   The euclidian distance in the hue, saturation disc is used.
00154   ///
00155   UInt16 Distance (const gml_TColor_HSV_FFF other) { 
00156     const Float32 pi = 3.14159265358979323846F;
00157     Float32 x0, x1, y0, y1, res;
00158     x0 =       S * Cos (2.0F * pi *       H);
00159     y0 =       S * Sin (2.0F * pi *       H);
00160     x1 = other.S * Cos (2.0F * pi * other.H);
00161     y1 = other.S * Sin (2.0F * pi * other.H);
00162     res = Min (1.0F, Norm (x0, y0, x1, y1));
00163     assert (res >= 0.0F && res <= 1.0F);
00164     return (UInt16) LFloor (res * 65535.0F);
00165   }
00166 
00167 
00168   struct {                                ///< structure for transparent channel access
00169     #if BYTE_ORDER == BIG_ENDIAN
00170       Float32 H;                          ///< hue channel
00171       Float32 S;                          ///< saturation channel
00172       Float32 V;                          ///< value channel
00173     #else
00174       Float32 V;                          ///< value channel
00175       Float32 S;                          ///< saturation channel
00176       Float32 H;                          ///< hue channel
00177     #endif
00178   } GML_PACKED;
00179 
00180 };
00181 
00182 
00183 ///
00184 /// gml_TColor_HSV --
00185 ///   A union type used to represent HSV-encoded color pixels.
00186 ///   HSV is Smith's Hue, Saturation, Value colorspace.
00187 ///   The type (and bitwidth) used for each channel is the template parameter.
00188 ///
00189 template <typename Channel>
00190 class gml_TColor_HSV
00191 {
00192 public:
00193 
00194   ///
00195   /// Constructor --
00196   ///   Convert a 24-bit RGB triplet into HSV and fill in the object.
00197   ///
00198   gml_TColor_HSV (UInt8 const r, UInt8 const g, UInt8 const b) {
00199     gml_TColor_HSV_FFF const pix (r, g, b);
00200     H = LFloor (pix.H * sChannelMax);
00201     S = LFloor (pix.S * sChannelMax);
00202     V = LFloor (pix.V * sChannelMax);
00203   }
00204   
00205   
00206   ///
00207   /// Constructor --
00208   ///   Fill the structure from data in memory
00209   ///
00210   gml_TColor_HSV (const void * const ptr) { 
00211     *this = *((gml_TColor_HSV<Channel>*)ptr);
00212   }
00213   
00214   
00215   ///
00216   /// Constructor --
00217   ///   Leave the structure `as is'.
00218   ///   I.e. probably zero.
00219   ///
00220   gml_TColor_HSV () {}
00221   
00222     
00223   ///
00224   /// Print --
00225   ///   Dump a representation of the pixel to stdout: channels in hex and
00226   ///   in degrees, percent, percent format.
00227   ///   @warning no newline appended !
00228   ///
00229   void Print () {
00230     printf ("% 8X % 8X % 8X (%3d %3d%% %3d%%)", 
00231       H, S, V, 
00232       (UInt32) round (fmod(360.0 * H / sChannelMax + 360.0, 360.0)),
00233       100 * S / sChannelMax,
00234       100 * V / sChannelMax
00235       );
00236   }
00237   
00238   
00239   ///
00240   /// Store --
00241   ///   Place the structure's data in memory
00242   ///
00243   void Store (void * const ptr) {
00244     *((gml_TColor_HSV<Channel>*)ptr) = *this;
00245   }
00246   
00247   
00248   ///
00249   /// Convert --
00250   ///   Convert the HSV data in this object to a 24 bit RGB triplet.
00251   ///
00252   void Convert (UInt8 &r, UInt8 &g, UInt8 &b) {
00253     gml_TColor_HSV_FFF pix;
00254     pix.H = Divide (H, sChannelMax);
00255     pix.S = Divide (S, sChannelMax);
00256     pix.V = Divide (V, sChannelMax);
00257     pix.Convert (r, g, b);
00258   }
00259   
00260   
00261   ///
00262   /// Distance --
00263   ///   Compute the 16-bit distance to another HSV pixel.
00264   ///   The euclidian distance in the hue, saturation disc is used.
00265   ///
00266   UInt16 Distance (const gml_TColor_HSV<Channel> other) { 
00267     gml_TColor_HSV_FFF pix0, pix1;
00268     pix0.H = Divide (      H,       sChannelMax);
00269     pix0.S = Divide (      S,       sChannelMax);
00270     pix0.V = Divide (      V,       sChannelMax);
00271     pix1.H = Divide (other.H, other.sChannelMax);
00272     pix1.S = Divide (other.S, other.sChannelMax);
00273     pix1.V = Divide (other.V, other.sChannelMax);
00274     return pix0.Distance (pix1);
00275   }
00276   
00277   
00278   static UInt8  const sChannelBits  = 8 * sizeof (Channel);     ///< bits per channel
00279   static UInt64 const sChannelMax   = (1 << sChannelBits) - 1;  ///< max channel value
00280 
00281   struct {                                ///< structure for transparent channel access
00282     #if BYTE_ORDER == BIG_ENDIAN
00283       Channel H;                          ///< hue channel
00284       Channel S;                          ///< saturation channel
00285       Channel V;                          ///< value channel
00286     #else
00287       Channel V;                          ///< value channel
00288       Channel S;                          ///< saturation channel
00289       Channel H;                          ///< hue channel
00290     #endif
00291   } GML_PACKED;
00292 
00293 };
00294 
00295 //
00296 // gml_TColor_HSV_888, gml_TColor_HSV_SSS, gml_TColor_HSV_LLL --
00297 //
00298 typedef gml_TColor_HSV<UInt8>   gml_TColor_HSV_888;
00299 typedef gml_TColor_HSV<UInt16>  gml_TColor_HSV_SSS;
00300 typedef gml_TColor_HSV<UInt32>  gml_TColor_HSV_LLL;
00301 
00302 
00303 
00304 #endif /* __GML_HSVCOLOR__ */
00305 
Generated on Tue Jun 12 14:03:27 2007 for gml by Doxygen 1.5.2.