Home Page Toolkit Overview Using GML User Input Services Finger Tracker Calibrator Frame Grabber Service protocol Obtaining GML Installing GML Licence Developer Documentation Tcl/Tk API The GML Canvas Image processing Tcl Scripts Library List of Classes List of Files C/C++ API List of Classes List of Files |
gml_HLSColor.h00001 // gml_HLSColor.h -- 00002 // 00003 // Defines the gml_TColor_HLS 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 #ifndef __GML_HLSCOLOR__ 00013 #define __GML_HLSCOLOR__ 00014 00015 #include <float.h> 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 #include "gml/math/gml_Tables.h" 00021 00022 /// 00023 /// gml_TColor_HLS_FFF -- 00024 /// A union type used to represent HLS-encoded color pixels. 00025 /// HLS is Metrick's Hue, Lightness, Saturation colorspace. 00026 /// 00027 /// Some of this code is adapted from section 15.3.5 of "Computer Graphics: 00028 /// Principles and Practice", by J.D. Foley and A. van Dam. 00029 /// 00030 class gml_TColor_HLS_FFF 00031 { 00032 public: 00033 /// 00034 /// Constructor -- 00035 /// Convert a 24-bit RGB triplet into HLS and fill in the object. 00036 /// 00037 gml_TColor_HLS_FFF (UInt8 const r, UInt8 const g, UInt8 const b) { 00038 Float32 fr = Float32 (r) * 0.00392156862745F; // that's 1/255 00039 Float32 fg = Float32 (g) * 0.00392156862745F; 00040 Float32 fb = Float32 (b) * 0.00392156862745F; 00041 Float32 min = Min (fr, fg, fb); 00042 Float32 max = Max (fr, fg, fb); 00043 Float32 delta = max - min; 00044 Float32 sum = max + min; 00045 Float32 h, l, s; 00046 00047 l = 0.5F * sum; 00048 00049 if(delta < FLT_EPSILON) { // achromatic case 00050 s = 0.0F; 00051 h = 0.0F; 00052 } else { 00053 s = (l <= 0.5F) ? Divide (delta, sum) : Divide (delta, 2.0F - sum); 00054 00055 if (fr == max) h = Divide (fg - fb, delta); 00056 else if (fg == max) h = 2.0F + Divide (fb - fr, delta); 00057 else /*fb == max*/ h = 4.0F + Divide (fr - fg, delta); 00058 } 00059 00060 H = fmodf (0.166666666667 * h + 1.0F, 1.0F); 00061 L = l; 00062 S = s; 00063 00064 assert (H >= 0.0F && H <= 1.0F); 00065 assert (L >= 0.0F && L <= 1.0F); 00066 assert (S >= 0.0F && S <= 1.0F); 00067 } 00068 00069 /// 00070 /// Constructor -- 00071 /// Fill the structure from data in memory 00072 /// 00073 gml_TColor_HLS_FFF (const void *const ptr) { 00074 *this = *((gml_TColor_HLS_FFF *) ptr); 00075 } 00076 00077 /// 00078 /// Constructor -- 00079 /// Leave the structure `as is'. 00080 /// I.e. probably zero. 00081 /// 00082 gml_TColor_HLS_FFF () {} 00083 00084 /// 00085 /// Print -- 00086 /// Dump a representation of the pixel to stdout: channels in hex and 00087 /// in degrees, percent, percent format. 00088 /// @warning no newline appended ! 00089 /// 00090 void Print () { 00091 printf ("%f %f %f (%3d %3d%% %3d%%)", H, L, S, 00092 (int) LRound (fmod (360.0 * H + 360.0, 360.0)), 00093 (int) LRound (100 * L), (int) LRound (100 * S) 00094 ); 00095 } 00096 00097 /// 00098 /// Store -- 00099 /// Place the structure's data in memory 00100 /// 00101 void Store (void *const ptr) { 00102 *((gml_TColor_HLS_FFF *) ptr) = *this; 00103 } 00104 00105 /// 00106 /// Convert -- 00107 /// Convert the HLS data in this object to a 24 bit RGB triplet. 00108 /// 00109 void Convert (UInt8 &r, UInt8 &g, UInt8 &b) { 00110 Float32 fr, fg, fb; 00111 00112 Float32 m2 = (L <= 0.5F) ? (L + L * S) : (L + S - L * S); 00113 Float32 m1 = 2.0F * L - m2; 00114 00115 if (S == 0.0F) { 00116 fr = fg = fb = L; 00117 } else { 00118 fr = Value (m1, m2, H + 0.333333333333F); 00119 fg = Value (m1, m2, H); 00120 fb = Value (m1, m2, H - 0.333333333333F); 00121 } 00122 00123 assert (fr <= 1.0F + FLT_EPSILON && fr >= 0.0F - FLT_EPSILON); 00124 assert (fg <= 1.0F + FLT_EPSILON && fg >= 0.0F - FLT_EPSILON); 00125 assert (fb <= 1.0F + FLT_EPSILON && fb >= 0.0F - FLT_EPSILON); 00126 r = (UInt8) LRound (fr * 255.0F); 00127 g = (UInt8) LRound (fg * 255.0F); 00128 b = (UInt8) LRound (fb * 255.0F); 00129 } 00130 00131 /// 00132 /// Distance -- 00133 /// Compute the 16-bit distance to another HLS pixel. 00134 /// The euclidian distance in the hue, saturation disc is used. 00135 /// 00136 UInt16 Distance (const gml_TColor_HLS_FFF other) 00137 { 00138 const Float32 pi = 3.14159265358979323846F; 00139 Float32 x0, x1, y0, y1, res; 00140 00141 x0 = S * Cos (2.0F * pi * H); 00142 y0 = S * Sin (2.0F * pi * H); 00143 x1 = other.S * Cos (2.0F * pi * other.H); 00144 y1 = other.S * Sin (2.0F * pi * other.H); 00145 res = Min (1.0F, Norm (x0, y0, x1, y1)); 00146 assert (res >= 0.0F && res <= 1.0F); 00147 return (UInt16) LFloor (res * 65535.0F); 00148 } 00149 00150 struct { ///< structure for transparent channel access 00151 #if BYTE_ORDER == BIG_ENDIAN 00152 Float32 H; ///< hue channel 00153 Float32 L; ///< saturation channel 00154 Float32 S; ///< value channel 00155 #else 00156 Float32 S; ///< value channel 00157 Float32 L; ///< saturation channel 00158 Float32 H; ///< hue channel 00159 #endif 00160 } GML_PACKED; 00161 00162 private: 00163 00164 /// Helper for Convert() 00165 inline static Float32 Value (Float32 n1, Float32 n2, Float32 hue) 00166 { 00167 hue = fmodf (hue + 1.0F, 1.0F); 00168 if (hue < 0.166666666667F) { 00169 return n1 + (n2 - n1) * hue * 6.0F; 00170 } else if (hue < 0.5F) { 00171 return n2; 00172 } else if (hue < 0.666666666667F) { 00173 return n1 + (n2 - n1) * (0.666666666667F - hue) * 6.0F; 00174 } else { 00175 return n1; 00176 } 00177 } 00178 00179 }; 00180 00181 /// 00182 /// gml_TColor_HLS -- 00183 /// A union type used to represent HLS-encoded color pixels. 00184 /// HLS is Metrick's Hue, Lightness, Saturation colorspace. 00185 /// The type (and bitwidth) used for each channel is the template parameter. 00186 /// 00187 template <typename Channel> class gml_TColor_HLS { 00188 public: 00189 /// 00190 /// Constructor -- 00191 /// Convert a 24-bit RGB triplet into HLS and fill in the object. 00192 /// 00193 gml_TColor_HLS (UInt8 const r, UInt8 const g, UInt8 const b) { 00194 UInt8 max, min; // max and min RGB values 00195 SInt32 h; 00196 00197 max = Max (r, g, b); 00198 min = Min (r, g, b); 00199 #ifndef __GML_AVOID_EUCLIDIAN_DIVISION 00200 L = ((max + min) * sChannelMax + 255) / (2 * 255); 00201 #else 00202 L = (((max + min) * sChannelMax) * 257ULL + (1<<16)) >> 17; 00203 #endif 00204 00205 // achromatic case 00206 if (max == min) { 00207 S = H = 0; 00208 return; 00209 } 00210 00211 // chromatic case 00212 SInt32 dr, dg, db; // intermediate values: % of spread from max 00213 UInt32 dif = max-min; 00214 UInt32 sum = Select (UInt32(L), UInt32(sChannelMax / 2), UInt32(max+min), UInt32(2*255 - (max+min))); 00215 #ifndef __GML_AVOID_EUCLIDIAN_DIVISION 00216 S = ((dif * sChannelMax) + (sum / 2)) / sum; 00217 00218 dr = (((max - r) * (sChannelMax / 6)) + (dif / 2)) / dif; 00219 dg = (((max - g) * (sChannelMax / 6)) + (dif / 2)) / dif; 00220 db = (((max - b) * (sChannelMax / 6)) + (dif / 2)) / dif; 00221 #else 00222 UInt64 rdif_mnt; // mantissa of dif's reciprocate 00223 UInt64 rsum_mnt; // mantissa of sum's reciprocate 00224 00225 rdif_mnt = ReciprocalMantissa_15_10bit (dif); 00226 rsum_mnt = ReciprocalMantissa_15_10bit (sum); 00227 00228 S = (((dif * sChannelMax) + (sum / 2)) * rsum_mnt + (1<<14)) >> 15; 00229 00230 dr = ((((max - r) * (sChannelMax / 6)) + (dif / 2)) * rdif_mnt + (1<<14)) >> 15; 00231 dg = ((((max - g) * (sChannelMax / 6)) + (dif / 2)) * rdif_mnt + (1<<14)) >> 15; 00232 db = ((((max - b) * (sChannelMax / 6)) + (dif / 2)) * rdif_mnt + (1<<14)) >> 15; 00233 #endif 00234 00235 if (r == max) 00236 h = db - dg; 00237 else if (g == max) 00238 h = (sChannelMax / 3) + dr - db; 00239 else /* b == max */ 00240 h = ((2 * sChannelMax) / 3) + dg - dr; 00241 00242 if (h < 0) H = h + sChannelMax; 00243 else if ((UInt32) h > sChannelMax) H = h - sChannelMax; 00244 else H = h; 00245 } 00246 00247 /// 00248 /// Constructor -- 00249 /// Fill the structure from data in memory 00250 /// 00251 gml_TColor_HLS (const void *const ptr) 00252 { 00253 *this = *((gml_TColor_HLS < Channel > *)ptr); 00254 } 00255 00256 /// 00257 /// Constructor -- 00258 /// Leave the structure `as is'. I.e. probably zero. 00259 /// 00260 gml_TColor_HLS () { } 00261 00262 /// 00263 /// Print -- 00264 /// Dump a representation of the pixel to stdout: channels in hex and 00265 /// in degrees, percent, percent format. 00266 /// @warning no newline appended ! 00267 /// 00268 void Print () 00269 { 00270 printf ("% 8X % 8X % 8X (%3d %3d%% %3d%%)", H, L, S, 00271 (UInt32) round (fmod (360.0 * H / sChannelMax + 360.0, 360.0)), 00272 100 * L / sChannelMax, 100 * S / sChannelMax); 00273 } 00274 00275 /// 00276 /// Store -- 00277 /// Place the structure's data in memory 00278 /// 00279 void Store (void *const ptr) 00280 { 00281 *((gml_TColor_HLS<Channel> *) ptr) = *this; 00282 } 00283 00284 /// 00285 /// Convert -- 00286 /// Convert the HLS data in this object to a 24 bit RGB triplet. 00287 /// 00288 void Convert (UInt8 &r, UInt8 &g, UInt8 &b) 00289 { 00290 SInt32 R, G, B; // RGB component values 00291 SInt32 m1, m2; // magic numbers (really!) 00292 00293 if (S == 0) { /* achromatic case */ 00294 R = G = B = (L * 255) >> (sChannelBits-1); 00295 } else { /* chromatic case */ 00296 // set up magic numbers 00297 if (L <= (sChannelMax / 2)) 00298 m2 = (L * (sChannelMax + S) + (sChannelMax / 2)) >> (sChannelBits-1); 00299 else 00300 m2 = L + S - (((L * S) + (sChannelMax / 2)) >> (sChannelBits-1)); 00301 m1 = 2 * L - m2; 00302 00303 // get RGB, change units from sChannelMax to 255 00304 R = (HueToRGB (m1, m2, H + (sChannelMax / 3)) * 255 + (sChannelMax / 2)) >> (sChannelBits-1); 00305 G = (HueToRGB (m1, m2, H ) * 255 + (sChannelMax / 2)) >> (sChannelBits-1); 00306 B = (HueToRGB (m1, m2, H - (sChannelMax / 3)) * 255 + (sChannelMax / 2)) >> (sChannelBits-1); 00307 } 00308 00309 assert (R >=0 && R <= 255); 00310 assert (G >=0 && G <= 255); 00311 assert (B >=0 && B <= 255); 00312 r = R; 00313 g = G; 00314 b = B; 00315 } 00316 00317 /// 00318 /// Distance -- 00319 /// Compute the 16-bit distance to another HLS pixel. 00320 /// The euclidian distance in the hue, saturation disc is used. 00321 /// 00322 UInt16 Distance (const gml_TColor_HLS<Channel> other) 00323 { 00324 gml_TColor_HLS_FFF pix0, pix1; 00325 pix0.H = Divide (H, sChannelMax); 00326 pix0.L = Divide (L, sChannelMax); 00327 pix0.S = Divide (S, sChannelMax); 00328 pix1.H = Divide (other.H, other.sChannelMax); 00329 pix1.L = Divide (other.L, other.sChannelMax); 00330 pix1.S = Divide (other.S, other.sChannelMax); 00331 return pix0.Distance (pix1); 00332 } 00333 00334 static UInt8 const sChannelBits = 8 * sizeof (Channel); ///< bits per channel 00335 static UInt64 const sChannelMax = (1 << (sChannelBits-1)); ///< max channel value 00336 // static UInt64 const sChannelMax = (1 << sChannelBits) - 1; ///< max channel value 00337 00338 struct { ///< structure for transparent channel access 00339 #if BYTE_ORDER == BIG_ENDIAN 00340 Channel H; ///< hue channel 00341 Channel L; ///< saturation channel 00342 Channel S; ///< value channel 00343 #else 00344 Channel S; ///< value channel 00345 Channel L; ///< saturation channel 00346 Channel H; ///< hue channel 00347 #endif 00348 } GML_PACKED; 00349 00350 private: 00351 inline static 00352 SInt32 HueToRGB (SInt32 n1, SInt32 n2, SInt32 hue) { 00353 // range check: note values passed add/subtract thirds of range 00354 if (hue < 0) hue += sChannelMax; 00355 if (hue > SInt32(sChannelMax)) 00356 hue -= sChannelMax; 00357 00358 // return r,g, or b value from this tridrant 00359 if (hue < SInt32(sChannelMax / 6)) 00360 return (n1 + (((n2 - n1) * hue + (sChannelMax / 12)) / (sChannelMax / 6))); 00361 if (hue < SInt32(sChannelMax / 2)) 00362 return (n2); 00363 if (hue < SInt32((sChannelMax * 2) / 3)) 00364 return (n1 + (((n2 - n1) * (((sChannelMax * 2) / 3) - hue) + (sChannelMax / 12)) / (sChannelMax / 6))); 00365 else 00366 return (n1); 00367 } 00368 00369 }; 00370 00371 // 00372 // gml_TColor_HLS_888, gml_TColor_HLS_SSS, gml_TColor_HLS_LLL -- 00373 // 00374 typedef gml_TColor_HLS <UInt8>gml_TColor_HLS_888; 00375 typedef gml_TColor_HLS <UInt16>gml_TColor_HLS_SSS; 00376 typedef gml_TColor_HLS <UInt32>gml_TColor_HLS_LLL; 00377 00378 #endif /* __GML_HLSCOLOR__ */ 00379
Generated on Tue Jun 12 14:03:27 2007 for gml by
Doxygen 1.5.2.
|
Contact: julien (dot) letessier (at) gmail (dot) com.
Copyright (c) 2000-2007 CLIPS-IMAG Laboratory, Grenoble, France. All rights reserved. W3CXHTML 1.0 W3CCSS 2.0 |