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 .......: ltiMergeYPbPrToImage.h 00027 * authors ....: Pablo Alvarado 00028 * organization: Department of Electronics, ITCR 00029 * creation ...: 04.01.2007 00030 * revisions ..: $Id: ltiMergeYPbPrToImage.h,v 1.3 2007/01/10 02:25:58 alvarado Exp $ 00031 */ 00032 00033 #ifndef _LTI_MERGE_Y_Pb_Pr_TO_IMAGE_H_ 00034 #define _LTI_MERGE_Y_Pb_Pr_TO_IMAGE_H_ 00035 00036 #include "ltiMergeImage.h" 00037 00038 namespace lti { 00039 00040 /** 00041 * Creates RGB values from given YPbPr 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, YPbPr 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::splitImageToYPbPr is followed: 00059 * 00060 * \f[ 00061 * \begin{bmatrix} 00062 * R \\ 00063 * G \\ 00064 * B 00065 * \end{bmatrix} 00066 * = 00067 * M^{-1} 00068 * \begin{bmatrix} 00069 * Y \\ 00070 * Pb \\ 00071 * Pr 00072 * \end{bmatrix} 00073 * \f] 00074 * where M is the matrix given in lti::splitImageToYPbPr. 00075 * 00076 * If you know you have a YPbPr space but it was given to you as 00077 * YUV, then the equivalences are U=Pb and V=Pr. 00078 * 00079 * A way of noticing if you have a YPbPr color space is determining the range 00080 * of the values of each channel. Y should be in [0,1], while Pr and Pb 00081 * should be in [-0.5,0.5]. 00082 * 00083 * @ingroup gColor 00084 */ 00085 class mergeYPbPrToImage : public mergeImage { 00086 public: 00087 00088 /** 00089 * Constructor 00090 */ 00091 mergeYPbPrToImage(void); 00092 00093 00094 /** 00095 * Destructor 00096 */ 00097 ~mergeYPbPrToImage(); 00098 00099 /** 00100 * Return the name of this type 00101 */ 00102 virtual const char* getTypeName() const; 00103 00104 /** 00105 * Copy data of "other" functor. 00106 * 00107 * @param other the functor to be copied 00108 * @return a reference to this functor object 00109 */ 00110 mergeYPbPrToImage& copy(const mergeYPbPrToImage& other); 00111 00112 /** 00113 * Alias for copy method. 00114 * 00115 * @param other the functor to be copied 00116 * @return a reference to this functor object 00117 */ 00118 mergeYPbPrToImage& operator=(const mergeYPbPrToImage& other); 00119 00120 /** 00121 * Returns a pointer to a clone of the functor. 00122 */ 00123 virtual functor* clone() const; 00124 00125 /** 00126 * Merge channels Y, Pb, Pr to an image. 00127 * 00128 * @param Y the Y channel, i.e. black&white 00129 * @param Pb the Pb channel, chromatic 00130 * @param Pr the Pr channel, chromatic 00131 * @param img the image to be splitted 00132 */ 00133 virtual bool apply(const matrix<float>& Y, 00134 const matrix<float>& Pb, 00135 const matrix<float>& Pr, 00136 image& img) const; 00137 00138 /** 00139 * Merge 8-bit-channels Y, Pb, Pr to an image. 00140 * 00141 * @param Y the Y channel, i.e. black&white 00142 * @param Pb the Pb channel, chromatic 00143 * @param Pr the Pr channel, chromatic 00144 * @param img the image to be splitted 00145 */ 00146 virtual bool apply(const channel8& Y, 00147 const channel8& Pb, 00148 const channel8& Pr, 00149 image& img) const; 00150 00151 /** 00152 * Merge the values Y, Pb and Pr to a pixel. 00153 * @param Y the Y value, i.e. black&white 00154 * @param Pb the Pb value, chromatic 00155 * @param Pr the Pr value, chromatic 00156 * @param pixel the merged pixel 00157 */ 00158 inline virtual bool apply(const float& Y, 00159 const float& Pb, 00160 const float& Pr, 00161 rgbPixel& pixel) const; 00162 00163 /** 00164 * Merge the 8-bit-values Y, Pb and Pr to a pixel. 00165 * 00166 * @param Y the Y value, i.e. black&white 00167 * @param Pb the Pb value, chromatic 00168 * @param Pr the Pr value, chromatic 00169 * @param pixel the merged pixel 00170 */ 00171 inline virtual bool apply(const ubyte& Y, 00172 const ubyte& Pb, 00173 const ubyte& Pr, 00174 rgbPixel& pixel) const; 00175 00176 /* 00177 * Merge the 8-bit-values Y, Pb and Pr to a pixel. 00178 * 00179 * This is a static method to do the conversion. It is required by 00180 * other functors which need a fast access to the conversion without 00181 * requiring an instance. 00182 * 00183 * \waring Be careful while using this method, since its static nature 00184 * makes you responsible for the previous initialization of the LUTs. For 00185 * that matter, just make sure that any instance of mergeYPbPrToImage is 00186 * created before calling this method. 00187 * 00188 * @param Y the Y value, i.e. black&white 00189 * @param Pb the Pb value, chromatic 00190 * @param Pr the Pr value, chromatic 00191 * @param pixel the merged pixel 00192 */ 00193 static bool convert(const ubyte& Y, 00194 const ubyte& Pb, 00195 const ubyte& Pr, 00196 rgbPixel& pixel); 00197 00198 protected: 00199 00200 /** 00201 * Initialize the Look-Up-Tables 00202 */ 00203 virtual void initializeLUTs(); 00204 00205 /** 00206 * Look up tables to accelerate conversion YPbPr -> RGB 00207 */ 00208 //@{ 00209 /** 00210 * Partial Y results 00211 */ 00212 static const int* lutY; 00213 00214 /** 00215 * Partial results with Pr (equivalent to V) for the red channel 00216 * computation. 00217 */ 00218 static const int* lutVr; 00219 00220 /** 00221 * Partial results with Pb (equivalent to U) for the green channel 00222 * computation. 00223 */ 00224 static const int* lutUg; 00225 00226 /** 00227 * Partial results with Pr (equivalent to V) for the green channel 00228 * computation. 00229 */ 00230 static const int* lutVg; 00231 00232 /** 00233 * Partial results with Pb (equivalent to U) for the blue channel 00234 * computation. 00235 */ 00236 static const int* lutUb; 00237 //@} 00238 00239 /** 00240 * Clip function 00241 * 00242 * Equivalent to min(255,max(0,val)) but maybe faster 00243 */ 00244 inline static ubyte clip(const int val); 00245 00246 }; 00247 00248 // 00249 // ------------------------------------- 00250 // Implementation of inline methods 00251 // ------------------------------------- 00252 // 00253 00254 inline ubyte mergeYPbPrToImage::clip(const int val) { 00255 if (val>255) { 00256 return 255; 00257 } 00258 if (val<0) { 00259 return 0; 00260 } 00261 return static_cast<ubyte>(val); 00262 } 00263 00264 // create rgbPixel (ubyte) from YUV float values 00265 inline bool mergeYPbPrToImage::apply(const float& c1, 00266 const float& c2, 00267 const float& c3, 00268 rgbPixel& pixel) const { 00269 00270 // The following coefficients are tuned to produce 0% of error of 00271 // RGB -> YPbPr -> RGB convertions. Please DO NOT CHANGE! 00272 const float Y = c1*255.f + 0.5f; 00273 00274 pixel.set(clip(static_cast<int>(Y + c3*357.509895107622f)), 00275 clip(static_cast<int>(Y - c2* 87.7545979321608f 00276 - c3*182.104719673362f)), 00277 clip(static_cast<int>(Y + c2*451.860016848823f)), 00278 0); 00279 00280 return true; 00281 } 00282 00283 // merge 8-bit-values to create an rgbPixel 00284 inline bool mergeYPbPrToImage::convert(const ubyte& c1, 00285 const ubyte& c2, 00286 const ubyte& c3, 00287 rgbPixel& pixel) { 00288 00289 // The following coefficients are tuned to produce the smallest possible 00290 // error of RGB -> YPbPr -> RGB convertions. Please DO NOT CHANGE! 00291 00292 // The error cannot be further reduced as the ubyte precision looses many 00293 // information when converting RGB->YPbPr. With the given coefficients 00294 // 3999903 values of all 2^24 available were perfectly retrieved (31.3%), 00295 // an the mean deviation error is 0.761 (RGB color space L2 distance). 00296 00297 // The 32768 is half the 16 bit precision and is added to force a correct 00298 // rounding. 00299 00300 // The next lines are 100% equivalent to this, but using LUT, which 00301 // requires approximatelly 85% of the direct computation time. 00302 // 00303 // const int Y = static_cast<int>(c1)*65536 + 32768; 00304 // const int U = (static_cast<int>(c2)-128); 00305 // const int V = (static_cast<int>(c3)-128); 00306 00307 // pixel.set(clip((Y + 91881 * V)>>16), 00308 // clip((Y - 22553 * U - 46802 * V)>>16), 00309 // clip((Y + 116130 * U )>>16), 00310 // 0); 00311 00312 const int Y = lutY[c1]; 00313 pixel.set(clip( (Y + lutVr[c3])>>16), 00314 clip( (Y + lutUg[c2] + lutVg[c3])>>16), 00315 clip( (Y + lutUb[c2] )>>16), 00316 0); 00317 00318 return true; 00319 } 00320 00321 // merge 8-bit-values to create an rgbPixel 00322 inline bool mergeYPbPrToImage::apply(const ubyte& c1, 00323 const ubyte& c2, 00324 const ubyte& c3, 00325 rgbPixel& pixel) const { 00326 // alias for convert, so just call it 00327 return convert(c1,c2,c3,pixel); 00328 } 00329 } 00330 #endif