colorspaceConverter.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLRCOMPUTERVISION_COLORSPACECONVERTER_H_
00016 #define _DLRCOMPUTERVISION_COLORSPACECONVERTER_H_
00017 
00018 #include <functional>
00019 #include <dlrComputerVision/imageFormat.h>
00020 #include <dlrComputerVision/image.h>
00021 
00022 namespace dlr {
00023 
00024   namespace computerVision {
00025 
00026     template<ImageFormat FORMAT0, ImageFormat FORMAT1>
00027     class ColorspaceConverter
00028       : public std::unary_function<typename Image<FORMAT0>::PixelType,
00029                                    typename Image<FORMAT1>::PixelType>
00030     {
00031     public:
00032     
00037       ColorspaceConverter()
00038         : std::unary_function<typename Image<FORMAT0>::PixelType,
00039                               typename Image<FORMAT1>::PixelType>()
00040         {}
00041 
00042 
00049       virtual ~ColorspaceConverter()
00050         {}
00051 
00052 
00071       inline
00072       typename Image<FORMAT1>::PixelType
00073       operator()(const typename Image<FORMAT0>::PixelType& inputPixel) {
00074         typename Image<FORMAT1>::PixelType outputPixel;
00075         this->operator()(inputPixel, outputPixel);
00076         return outputPixel;
00077       }
00078     
00079 
00090       inline
00091       void
00092       operator()(const typename Image<FORMAT0>::PixelType& inputPixel,
00093                  typename Image<FORMAT1>::PixelType& outputPixel) {
00094         // Default rule should work for many format combinations.  We'll
00095         // specialize for the rest below.  If you try to convert between
00096         // formats where this static_cast isn't appropriate, and for
00097         // which we haven't written a specialization, then you'll either
00098         // get a compile error or an unexpected conversion result.
00099         outputPixel =
00100           static_cast<typename Image<FORMAT1>::PixelType>(inputPixel);
00101       }
00102     
00103     };
00104 
00105   } // namespace computerVision
00106   
00107 } // namespace dlr
00108 
00109 
00110 /* ============ Definitions of inline & template functions ============ */
00111 
00112 
00113 #include <cmath>
00114 
00115 namespace dlr {
00116 
00117   namespace computerVision {
00118 
00119     namespace privateCode {
00120 
00121       // Here we define file-scoped versions of common conversion
00122       // because dispatching between specializations of
00123       // ColorspaceConverter (to avoid code duplication) is too hard
00124       // for the compiler.  Instead, we dispatch to this function,
00125       // which is not templated.  Life gets much easiser.
00126 
00127         
00128       // This conversion follows the wikipedia article "HSL color space"
00129       // as of 2009-02-19, with the exception that all resulting
00130       // components are scaled [0.0, 1.0].  
00131       inline void
00132       doColorspaceConversion(const Image<RGB_FLOAT64>::PixelType& inputPixel,
00133                              Image<HSV_FLOAT64>::PixelType& outputPixel)
00134       {
00135         // "value" is the simplest to compute... it's just the max RGB value.
00136         Float64 maxVal = static_cast<Float64>(
00137           std::max(inputPixel.red,
00138                    std::max(inputPixel.green, inputPixel.blue)));
00139         outputPixel.value = maxVal;
00140     
00141         // Handle first special case up-front.
00142         if(maxVal == 0.0) {
00143           outputPixel.hue = Float64(0.0);
00144           outputPixel.saturation = Float64(0.0);
00145           return;
00146         }
00147 
00148         // Now we can compute "saturation".
00149         Float64 minVal = static_cast<Float64>(
00150           std::min(inputPixel.red,
00151                    std::min(inputPixel.green, inputPixel.blue)));
00152         Float64 delta = maxVal - minVal;
00153         outputPixel.saturation = delta / maxVal;
00154     
00155         // Handle second special case up-front.
00156         if(delta == 0.0) {
00157           outputPixel.hue = Float64(0.0);
00158           return;
00159         }
00160 
00161         // Warning(xxx): our definition of hue goes from 0.0 to 1.0, not
00162         // 0.0 to 360.0, as is traditional.
00163         if(inputPixel.red == maxVal) {
00164           outputPixel.hue =
00165             Float64(1.0 / 6.0)
00166             + (static_cast<Float64>(inputPixel.green)
00167                - static_cast<Float64>(inputPixel.blue)) / (6.0 * delta);
00168         } else if(inputPixel.green == maxVal) {
00169           outputPixel.hue =
00170             Float64(0.5)
00171             + (static_cast<Float64>(inputPixel.blue)
00172                - static_cast<Float64>(inputPixel.red)) / (6.0 * delta);
00173         } else {
00174           outputPixel.hue =
00175             Float64(5.0 / 6.0)
00176             + (static_cast<Float64>(inputPixel.red)
00177                - static_cast<Float64>(inputPixel.green)) / (6.0 * delta);
00178         }      
00179 
00180 #if 1
00181         // Previous code doesn't correspond to wikipedia anymore.
00182         // Possibly the 2009-02-19 page has been updated?  New
00183         // definition of hue is rotated 60 degrees from previous.
00184         outputPixel.hue -= 1.0 / 6.0;
00185         outputPixel.hue = ((outputPixel.hue < 0.0)
00186                            ? (outputPixel.hue + 1.0) : outputPixel.hue);
00187 #endif    
00188       }    
00189 
00190     } // namespace privateCode
00191 
00192     
00193     template<>
00194     inline
00195     void
00196     ColorspaceConverter<GRAY1, GRAY8>::
00197     operator()(const Image<GRAY1>::PixelType& inputPixel,
00198                Image<GRAY8>::PixelType& outputPixel)
00199     {
00200       if(inputPixel) {
00201         outputPixel = Image<GRAY8>::PixelType(255);
00202       } else {
00203         outputPixel = Image<GRAY8>::PixelType(0);
00204       }
00205     }
00206 
00207 
00208     template<>
00209     inline
00210     void
00211     ColorspaceConverter<GRAY1, RGB8>::
00212     operator()(const Image<GRAY1>::PixelType& inputPixel,
00213                Image<RGB8>::PixelType& outputPixel)
00214     {
00215       if(inputPixel) {
00216         outputPixel.red = ImageFormatTraits<RGB8>::ComponentType(255);
00217         outputPixel.green = ImageFormatTraits<RGB8>::ComponentType(255);
00218         outputPixel.blue = ImageFormatTraits<RGB8>::ComponentType(255);
00219       } else {
00220         outputPixel.red = ImageFormatTraits<RGB8>::ComponentType(0);
00221         outputPixel.green = ImageFormatTraits<RGB8>::ComponentType(0);
00222         outputPixel.blue = ImageFormatTraits<RGB8>::ComponentType(0);
00223       }
00224     }
00225 
00226 
00227     template<>
00228     inline
00229     void
00230     ColorspaceConverter<GRAY8, RGB8>::
00231     operator()(const Image<GRAY8>::PixelType& inputPixel,
00232                Image<RGB8>::PixelType& outputPixel)
00233     {
00234       outputPixel.red = inputPixel;
00235       outputPixel.green = inputPixel;
00236       outputPixel.blue = inputPixel;
00237     }
00238 
00239 
00240     template<>
00241     inline
00242     void
00243     ColorspaceConverter<RGB8, GRAY8>::
00244     operator()(const Image<RGB8>::PixelType& inputPixel,
00245                Image<GRAY8>::PixelType& outputPixel)
00246     {
00247       double accumulator = (0.3 * inputPixel.red
00248                             + 0.59 * inputPixel.green
00249                             + 0.11 * inputPixel.blue);
00250       outputPixel = static_cast<Image<GRAY8>::PixelType>(accumulator + 0.5);
00251     }
00252 
00253 
00254     template<>
00255     inline
00256     void
00257     ColorspaceConverter<RGB8, GRAY_FLOAT64>::
00258     operator()(const Image<RGB8>::PixelType& inputPixel,
00259                Image<GRAY_FLOAT64>::PixelType& outputPixel)
00260     {
00261       double accumulator = (0.3 * inputPixel.red
00262                             + 0.59 * inputPixel.green
00263                             + 0.11 * inputPixel.blue);
00264       outputPixel =
00265         static_cast<Image<GRAY_FLOAT64>::PixelType>(accumulator + 0.5);
00266     }
00267 
00268 
00269     template<>
00270     inline
00271     void
00272     ColorspaceConverter<RGB8, RGB16>::
00273     operator()(const Image<RGB8>::PixelType& inputPixel,
00274                Image<RGB16>::PixelType& outputPixel)
00275     {
00276       outputPixel.red = static_cast<UnsignedInt16>(inputPixel.red);
00277       outputPixel.green = static_cast<UnsignedInt16>(inputPixel.green);
00278       outputPixel.blue = static_cast<UnsignedInt16>(inputPixel.blue);
00279     }
00280 
00281 
00282     template<>
00283     inline
00284     void
00285     ColorspaceConverter<RGB8, RGB_FLOAT32>::
00286     operator()(const Image<RGB8>::PixelType& inputPixel,
00287                Image<RGB_FLOAT32>::PixelType& outputPixel)
00288     {
00289       outputPixel.red = static_cast<Float32>(inputPixel.red);
00290       outputPixel.green = static_cast<Float32>(inputPixel.green);
00291       outputPixel.blue = static_cast<Float32>(inputPixel.blue);
00292     }
00293 
00294 
00295     template<>
00296     inline
00297     void
00298     ColorspaceConverter<RGB8, RGB_FLOAT64>::
00299     operator()(const Image<RGB8>::PixelType& inputPixel,
00300                Image<RGB_FLOAT64>::PixelType& outputPixel)
00301     {
00302       outputPixel.red = static_cast<Float64>(inputPixel.red);
00303       outputPixel.green = static_cast<Float64>(inputPixel.green);
00304       outputPixel.blue = static_cast<Float64>(inputPixel.blue);
00305     }
00306 
00307 
00308     template<>
00309     inline
00310     void
00311     ColorspaceConverter<RGB_FLOAT32, RGB8>::
00312     operator()(const Image<RGB_FLOAT32>::PixelType& inputPixel,
00313                Image<RGB8>::PixelType& outputPixel)
00314     {
00315       outputPixel.red = static_cast<UnsignedInt8>(inputPixel.red + 0.5);
00316       outputPixel.green = static_cast<UnsignedInt8>(inputPixel.green + 0.5);
00317       outputPixel.blue = static_cast<UnsignedInt8>(inputPixel.blue + 0.5);
00318     }
00319 
00320 
00321     template<>
00322     inline
00323     void
00324     ColorspaceConverter<RGB8, HSV_FLOAT64>::
00325     operator()(const Image<RGB8>::PixelType& inputPixel,
00326                Image<HSV_FLOAT64>::PixelType& outputPixel)
00327     {
00328       // Dispatch to the static version of this converter.  Note
00329       // that we're not rescaling our RGB values [0.0, 1.0].  This
00330       // should have no effect on the S & V values, which are
00331       // essentually ratios of R, G, and B anyway.  We'll rescale
00332       // value later, thus saving two floating point operations.
00333       privateCode::doColorspaceConversion(
00334         Image<RGB_FLOAT64>::PixelType(inputPixel.red, inputPixel.green,
00335                                       inputPixel.blue),
00336         outputPixel);
00337 
00338       // Scale value 0.0 - 1.0, consistent with H and S.
00339       outputPixel.value /= 255.0;
00340     }
00341 
00342 
00343     template<>
00344     inline
00345     void
00346     ColorspaceConverter<RGB8, YIQ_FLOAT64>::
00347     operator()(const Image<RGB8>::PixelType& inputPixel,
00348                Image<YIQ_FLOAT64>::PixelType& outputPixel)
00349     {
00350       outputPixel.luma = ((0.299 / 255.0) * inputPixel.red
00351                           + (0.587 / 255.0) * inputPixel.green
00352                           + (0.114 / 255.0) * inputPixel.blue);
00353       outputPixel.inPhase = ((0.595716 / 255.0)* inputPixel.red
00354                              - (0.274453 / 255.0) * inputPixel.green
00355                              - (0.321263 / 255.0) * inputPixel.blue);
00356       outputPixel.quadrature = ((0.211456 / 255.0) * inputPixel.red
00357                                 - (0.522591 / 255.0) * inputPixel.green
00358                                 + (0.311135 / 255.0) * inputPixel.blue);
00359     }
00360 
00361 
00362     template<>
00363     inline
00364     void
00365     ColorspaceConverter<RGB8, BGRA8>::
00366     operator()(const Image<RGB8>::PixelType& inputPixel,
00367                Image<BGRA8>::PixelType& outputPixel)
00368     {
00369       outputPixel.red = inputPixel.red;
00370       outputPixel.green = inputPixel.green;
00371       outputPixel.blue = inputPixel.blue;
00372       outputPixel.alpha = UnsignedInt8(255);
00373     }
00374 
00375 
00376     template<>
00377     inline
00378     void
00379     ColorspaceConverter<RGB8, RGBA8>::
00380     operator()(const Image<RGB8>::PixelType& inputPixel,
00381                Image<RGBA8>::PixelType& outputPixel)
00382     {
00383       outputPixel.red = inputPixel.red;
00384       outputPixel.green = inputPixel.green;
00385       outputPixel.blue = inputPixel.blue;
00386       outputPixel.alpha = UnsignedInt8(255);
00387     }
00388 
00389 
00390     template<>
00391     inline
00392     void
00393     ColorspaceConverter<RGB16, RGB8>::
00394     operator()(const Image<RGB16>::PixelType& inputPixel,
00395                Image<RGB8>::PixelType& outputPixel)
00396     {
00397       outputPixel.red = static_cast<UnsignedInt8>(inputPixel.red);
00398       outputPixel.green = static_cast<UnsignedInt8>(inputPixel.green);
00399       outputPixel.blue = static_cast<UnsignedInt8>(inputPixel.blue);
00400     }
00401 
00402 
00403     template<>
00404     inline
00405     void
00406     ColorspaceConverter<RGB_FLOAT32, GRAY8>::
00407     operator()(const Image<RGB_FLOAT32>::PixelType& inputPixel,
00408                Image<GRAY8>::PixelType& outputPixel)
00409     {
00410       double accumulator = (inputPixel.red * inputPixel.red
00411                             + inputPixel.green * inputPixel.green
00412                             + inputPixel.blue * inputPixel.blue) / 3.0;
00413       outputPixel =
00414         static_cast<Image<GRAY8>::PixelType>(std::sqrt(accumulator) + 0.5);
00415     }
00416 
00417 
00418 
00419     template<>
00420     inline
00421     void
00422     ColorspaceConverter<RGB_FLOAT64, HSV_FLOAT64>::
00423     operator()(const Image<RGB_FLOAT64>::PixelType& inputPixel,
00424                Image<HSV_FLOAT64>::PixelType& outputPixel)
00425     {
00426       privateCode::doColorspaceConversion(inputPixel, outputPixel);
00427     }
00428 
00429 
00430     template<>
00431     inline
00432     void
00433     ColorspaceConverter<RGB_FLOAT64, YIQ_FLOAT64>::
00434     operator()(const Image<RGB_FLOAT64>::PixelType& inputPixel,
00435                Image<YIQ_FLOAT64>::PixelType& outputPixel)
00436     {
00437       outputPixel.luma = (0.299 * inputPixel.red
00438                           + 0.587 * inputPixel.green
00439                           + 0.114 * inputPixel.blue);
00440       outputPixel.inPhase = (0.595716 * inputPixel.red
00441                              - 0.274453 * inputPixel.green
00442                              - 0.321263 * inputPixel.blue);
00443       outputPixel.quadrature = (0.211456 * inputPixel.red
00444                                 - 0.522591 * inputPixel.green
00445                                 + 0.311135 * inputPixel.blue);
00446     }
00447 
00448     
00449     template<>
00450     inline
00451     void
00452     ColorspaceConverter<BGRA8, RGB8>::
00453     operator()(const Image<BGRA8>::PixelType& inputPixel,
00454                Image<RGB8>::PixelType& outputPixel)
00455     {
00456       outputPixel.red = inputPixel.red;
00457       outputPixel.green = inputPixel.green;
00458       outputPixel.blue = inputPixel.blue;
00459     }
00460   
00461 
00462     template<>
00463     inline
00464     void
00465     ColorspaceConverter<RGBA8, RGB8>::
00466     operator()(const Image<RGBA8>::PixelType& inputPixel,
00467                Image<RGB8>::PixelType& outputPixel)
00468     {
00469       outputPixel.red = inputPixel.red;
00470       outputPixel.green = inputPixel.green;
00471       outputPixel.blue = inputPixel.blue;
00472     }
00473 
00474   } // namespace computerVision
00475     
00476 } // namespace dlr
00477 
00478 #endif /* #ifndef _DLRCOMPUTERVISION_COLORSPACECONVERTER_H_ */

Generated on Wed Nov 25 12:15:04 2009 for dlrComputerVision Utility Library by  doxygen 1.5.8