latest version v1.9 - last update 10 Apr 2010 |
00001 /* 00002 * Copyright (C) 2003, 2004, 2005, 2006, 2007 00003 * Department of Electronics, ITCR, Costa Rica 00004 * 00005 * This file is part of the LTI-Computer Vision Library (LTI-Lib) 00006 * 00007 * The LTI-Lib is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License (LGPL) 00009 * as published by the Free Software Foundation; either version 2.1 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * The LTI-Lib is distributed in the hope that it will be 00013 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00014 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with the LTI-Lib; see the file LICENSE. If 00019 * not, write to the Free Software Foundation, Inc., 59 Temple Place - 00020 * Suite 330, Boston, MA 02111-1307, USA. 00021 */ 00022 00023 00024 /*-------------------------------------------------------------------- 00025 * project ....: LTI-Lib: Image Processing and Computer Vision Library 00026 * file .......: ltiMergeYCbCrToImage.h 00027 * authors ....: Pablo Alvarado 00028 * organization: Department of Electronics, ITCR 00029 * creation ...: 04.01.2007 00030 * revisions ..: $Id: ltiMergeYCbCrToImage.h,v 1.3 2007/01/05 19:19:56 alvarado Exp $ 00031 */ 00032 00033 #ifndef _LTI_MERGE_Y_Cb_Cr_TO_IMAGE_H_ 00034 #define _LTI_MERGE_Y_Cb_Cr_TO_IMAGE_H_ 00035 00036 #include "ltiMergeImage.h" 00037 00038 namespace lti { 00039 00040 /** 00041 * Creates RGB values from given YCbCr values by merging float or ubyte 00042 * values to an rgbPixel, merging channels(floats) or channel8s(ubytes) to an 00043 * Image 00044 * 00045 * In the literature, technical and scientific, there is often confusion 00046 * among the color spaces YUV, YCbCr and YPbPr. Poynton in 00047 * http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html explains that 00048 * YUV is usually never correctly meant, because the color space normally 00049 * used for component digital video is the YCbCr (ITU-RS601 or CCIR-601). 00050 * Other devices use the YPbPr, but the "real" YUV is rarely employed. 00051 * 00052 * The LTI-Lib provides all three spaces: 00053 * 00054 * - YCbCr: lti::mergeYCbCrToImage used by IEEE 1394 FireWire cameras 00055 * - YPbPr: lti::mergeYPbPrToImage used by some WebCams 00056 * - YUV: lti::mergeYUVToImage did they really meant to use this? 00057 * 00058 * Here, the inverse transformation of lti::splitImageToYCbCr is followed: 00059 * 00060 * \f[ 00061 * \begin{bmatrix} 00062 * R \\ 00063 * G \\ 00064 * B 00065 * \end{bmatrix} 00066 * = 00067 * M^{-1} 00068 * \left( 00069 * \begin{bmatrix} 00070 * Y \\ 00071 * Cb \\ 00072 * Cr 00073 * \end{bmatrix} 00074 * - 00075 * \begin{bmatrix} 00076 * 16 \\ 00077 * 128 \\ 00078 * 128 00079 * \end{bmatrix} 00080 * \right) 00081 * \f] 00082 * where M is the matrix given in lti::splitImageToYCbCr. 00083 * 00084 * If you know you have a YCbCr space but it was given to you as 00085 * YUV, then the equivalences are U=Cb and V=Cr. 00086 * 00087 * A way of noticing if you have a YCbCr color space is determining the range 00088 * of the values of each channel. Y should be in [16,235], while Cr and Cb 00089 * should be in [16,240]. If you channel Y has values in [0,255] then you 00090 * should use mergeYPbPrToImage instead. 00091 * 00092 * @ingroup gColor 00093 */ 00094 class mergeYCbCrToImage : public mergeImage { 00095 public: 00096 00097 /** 00098 * Constructor 00099 */ 00100 mergeYCbCrToImage(void); 00101 00102 00103 /** 00104 * Destructor 00105 */ 00106 ~mergeYCbCrToImage(); 00107 00108 /** 00109 * Return the name of this type 00110 */ 00111 virtual const char* getTypeName() const; 00112 00113 /** 00114 * Copy data of "other" functor. 00115 * 00116 * @param other the functor to be copied 00117 * @return a reference to this functor object 00118 */ 00119 mergeYCbCrToImage& copy(const mergeYCbCrToImage& other); 00120 00121 /** 00122 * Alias for copy method. 00123 * 00124 * @param other the functor to be copied 00125 * @return a reference to this functor object 00126 */ 00127 mergeYCbCrToImage& operator=(const mergeYCbCrToImage& other); 00128 00129 /** 00130 * Returns a pointer to a clone of the functor. 00131 */ 00132 virtual functor* clone() const; 00133 00134 /** 00135 * Merge channels Y, Cr, Cb to an image. 00136 * 00137 * @param Y the Y channel, i.e. black&white 00138 * @param Cb the Cb channel, chromatic 00139 * @param Cr the Cr channel, chromatic 00140 * @param img the image to be splitted 00141 */ 00142 virtual bool apply(const matrix<float>& Y, 00143 const matrix<float>& Cb, 00144 const matrix<float>& Cr, 00145 image& img) const; 00146 00147 /** 00148 * Merge 8-bit-channels Y, U, V to an image. 00149 * 00150 * @param Y the Y channel, i.e. black&white 00151 * @param Cb the Cb channel, chromatic 00152 * @param Cr the Cr channel, chromatic 00153 * @param img the image to be splitted 00154 */ 00155 virtual bool apply(const channel8& Y, 00156 const channel8& Cb, 00157 const channel8& Cr, 00158 image& img) const; 00159 00160 /** 00161 * Merge the values Y, Cr and Cb to a pixel. 00162 * @param Y the Y value, i.e. black&white 00163 * @param Cb the Cb value, chromatic 00164 * @param Cr the Cr value, chromatic 00165 * @param pixel the merged pixel 00166 */ 00167 inline virtual bool apply(const float& Y, 00168 const float& Cb, 00169 const float& Cr, 00170 rgbPixel& pixel) const; 00171 00172 /** 00173 * Merge the 8-bit-values Y, U and V to a pixel. 00174 * 00175 * @param Y the Y value, i.e. black&white 00176 * @param Cb the Cb value, chromatic 00177 * @param Cr the Cr value, chromatic 00178 * @param pixel the merged pixel 00179 */ 00180 inline virtual bool apply(const ubyte& Y, 00181 const ubyte& Cb, 00182 const ubyte& Cr, 00183 rgbPixel& pixel) const; 00184 protected: 00185 00186 /** 00187 * Initialize the Look-Up-Tables 00188 */ 00189 virtual void initializeLUTs(); 00190 00191 /** 00192 * Look up tables to accelerate conversion YUV -> RGB 00193 */ 00194 //@{ 00195 /** 00196 * Partial Y results 00197 */ 00198 static const int* lutY; 00199 00200 /** 00201 * Partial results with Cr (equivalent to V) for the red channel 00202 * computation. 00203 */ 00204 static const int* lutVr; 00205 00206 /** 00207 * Partial results with Cb (equivalent to U) for the green channel 00208 * computation. 00209 */ 00210 static const int* lutUg; 00211 00212 /** 00213 * Partial results with Cr (equivalent to V) for the green channel 00214 * computation. 00215 */ 00216 static const int* lutVg; 00217 00218 /** 00219 * Partial results with Cb (equivalent to U) for the blue channel 00220 * computation. 00221 */ 00222 static const int* lutUb; 00223 //@} 00224 00225 /** 00226 * Clip function 00227 * 00228 * Equivalent to min(255,max(0,val)) but maybe faster 00229 */ 00230 inline ubyte clip(const int val) const; 00231 00232 }; 00233 00234 // 00235 // ------------------------------------- 00236 // Implementation of inline methods 00237 // ------------------------------------- 00238 // 00239 00240 inline ubyte mergeYCbCrToImage::clip(const int val) const { 00241 if (val>255) { 00242 return 255; 00243 } 00244 if (val<0) { 00245 return 0; 00246 } 00247 return static_cast<ubyte>(val); 00248 } 00249 00250 // create rgbPixel (ubyte) from YUV float values 00251 inline bool mergeYCbCrToImage::apply(const float& c1, 00252 const float& c2, 00253 const float& c3, 00254 rgbPixel& pixel) const { 00255 00256 // The values here are chosen to exactly invert the method followed in 00257 // splitImageToYCrBr 00258 static const float offuv = 128.f/255.f; 00259 static const float offY = 16.f/255.f; 00260 00261 // The following coefficients are tuned to produce 0% of error of 00262 // RGB -> YCbCr -> RGB convertions. Please DO NOT CHANGE! 00263 00264 const float Y = (c1-offY)*296.917808219178f + 0.5f; 00265 const float U = c2-offuv; 00266 const float V = c3-offuv; 00267 00268 pixel.set(clip(static_cast<int>(Y + V*406.986856270605f)), 00269 clip(static_cast<int>(Y - U*99.8994476850698f 00270 - V*207.306914501362f)), 00271 clip(static_cast<int>(Y + U*514.394323086897f)), 00272 0); 00273 00274 return true; 00275 } 00276 00277 // merge 8-bit-values to create an rgbPixel 00278 inline bool mergeYCbCrToImage::apply(const ubyte& c1, 00279 const ubyte& c2, 00280 const ubyte& c3, 00281 rgbPixel& pixel) const { 00282 00283 // The following coefficients are tuned to produce the smallest possible 00284 // error of RGB -> YCbCr -> RGB convertions. Please DO NOT CHANGE! 00285 00286 // The error cannot be further reduced as the ubyte precision looses many 00287 // information when converting RGB->YCbCr. With the given coefficients 00288 // 2660449 values of all 2^24 available were perfectly retrieved (18.8%), 00289 // an the mean deviation error is 0.845 (RGB color space L2 distance). 00290 00291 // the 32768 is half the 16 bit precision and is added to force a correct 00292 // rounding 00293 00294 // The next lines are 100% equivalent to this, but using LUT, which 00295 // requires approximatelly 85% of the direct computation time. 00296 // 00297 // const int Y = (static_cast<int>(c1)- 16)*76309 + 32768; 00298 // const int U = (static_cast<int>(c2)-128); 00299 // const int V = (static_cast<int>(c3)-128); 00300 00301 // pixel.set(clip((Y + 104597 * V)>>16), 00302 // clip((Y - 25675 * U - 53279 * V)>>16), 00303 // clip((Y + 132201 * U )>>16), 00304 // 0); 00305 00306 const int Y = lutY[c1]; 00307 pixel.set(clip( (Y + lutVr[c3])>>16), 00308 clip( (Y + lutUg[c2] + lutVg[c3])>>16), 00309 clip( (Y + lutUb[c2] )>>16), 00310 0); 00311 00312 return true; 00313 } 00314 } 00315 #endif