color_conversions.C

Go to the documentation of this file.
00001 /*!@file Image/color_conversions.C low-level routines for colorspace conversions */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/color_conversions.C $
00035 // $Id: color_conversions.C 8279 2007-04-20 21:44:59Z rjpeters $
00036 //
00037 
00038 #include "Image/color_conversions.H"
00039 
00040 #include "Image/Image.H"
00041 #include "Image/Pixels.H"
00042 #include "Image/colorDefs.H"  // for rgb<->yuv conversion factors
00043 #include "Util/Promotions.H" // for clamped_convert()
00044 #include "rutz/trace.h"
00045 
00046 #include <pthread.h>
00047 
00048 namespace
00049 {
00050   // Use this many extra bits in our fixed-point approximation to
00051   // floating-point arithmetic:
00052   const int BITS_OUT = 16;
00053 
00054   // rgb lookup tables
00055 
00056   int RGB_Y_tab[256];
00057   int B_U_tab[256];
00058   int G_U_tab[256];
00059   int G_V_tab[256];
00060   int R_V_tab[256];
00061 
00062   pthread_once_t colorspace_init_once = PTHREAD_ONCE_INIT;
00063 
00064   void colorspace_init()
00065   {
00066     // so that we get proper rounding in fixed-point integer arithmetic:
00067     const int half =
00068       BITS_OUT > 0
00069       ? 1<<(BITS_OUT-1)
00070       : 0;
00071 
00072     const int scale = 1<<BITS_OUT;
00073 
00074     for (int i = 0; i < 256; i++)
00075       {
00076         const int y  = i-VIDEOYUV_Y_OFFSET;
00077         const int uv = i-VIDEOYUV_UV_OFFSET;
00078 
00079         RGB_Y_tab[i] = half+int(0.5 + y  * VIDEOYUV_RGB_Y * scale);
00080         R_V_tab[i]   =      int(0.5 + uv * VIDEOYUV_R_V   * scale);
00081         // FIXME should probably have -0.5 instead of +0.5 here and
00082         // flip the sign of G_U_tab and G_V_tab:
00083         G_U_tab[i]   =      int(0.5 - uv * VIDEOYUV_G_U   * scale);
00084         G_V_tab[i]   =      int(0.5 - uv * VIDEOYUV_G_V   * scale);
00085         B_U_tab[i]   =      int(0.5 + uv * VIDEOYUV_B_U   * scale);
00086       }
00087   }
00088 }
00089 
00090 void yv12_to_rgb24_c(unsigned char* dst,
00091                      int dst_stride,
00092                      const unsigned char* y_src,
00093                      const unsigned char* u_src,
00094                      const unsigned char* v_src,
00095                      int y_stride,
00096                      int uv_stride,
00097                      int width,
00098                      int height)
00099 {
00100 GVX_TRACE(__PRETTY_FUNCTION__);
00101 
00102   if (width & 1)
00103     LFATAL("width must be even");
00104 
00105   if (height & 1)
00106     LFATAL("height must be even");
00107 
00108   pthread_once(&colorspace_init_once, &colorspace_init);
00109 
00110   const int dst_dif = 6 * dst_stride - 3 * width;
00111   int y_dif = 2 * y_stride - width;
00112 
00113   unsigned char* dst2 = dst + 3 * dst_stride;
00114   const unsigned char* y_src2 = y_src + y_stride;
00115 
00116   if (height < 0) {                     /* flip image? */
00117     height = -height;
00118     y_src += (height - 1) * y_stride;
00119     y_src2 = y_src - y_stride;
00120     u_src += (height / 2 - 1) * uv_stride;
00121     v_src += (height / 2 - 1) * uv_stride;
00122     y_dif = -width - 2 * y_stride;
00123     uv_stride = -uv_stride;
00124   }
00125 
00126   for (int y = height / 2; y; y--) {
00127     for (int x = 0; x < width / 2; x++) {
00128       const int u = u_src[x];
00129       const int v = v_src[x];
00130 
00131       const int r_v = R_V_tab[v];
00132       const int g_uv = - G_U_tab[u] - G_V_tab[v];
00133       const int b_u = B_U_tab[u];
00134 
00135       {
00136         const int rgb_y = RGB_Y_tab[*y_src];
00137         const int r = (rgb_y + r_v) >> BITS_OUT;
00138         const int g = (rgb_y + g_uv) >> BITS_OUT;
00139         const int b = (rgb_y + b_u) >> BITS_OUT;
00140         dst[0] = clamped_convert<unsigned char>(r);
00141         dst[1] = clamped_convert<unsigned char>(g);
00142         dst[2] = clamped_convert<unsigned char>(b);
00143         y_src++;
00144       }
00145       {
00146         const int rgb_y = RGB_Y_tab[*y_src];
00147         const int r = (rgb_y + r_v) >> BITS_OUT;
00148         const int g = (rgb_y + g_uv) >> BITS_OUT;
00149         const int b = (rgb_y + b_u) >> BITS_OUT;
00150         dst[3] = clamped_convert<unsigned char>(r);
00151         dst[4] = clamped_convert<unsigned char>(g);
00152         dst[5] = clamped_convert<unsigned char>(b);
00153         y_src++;
00154       }
00155       {
00156         const int rgb_y = RGB_Y_tab[*y_src2];
00157         const int r = (rgb_y + r_v) >> BITS_OUT;
00158         const int g = (rgb_y + g_uv) >> BITS_OUT;
00159         const int b = (rgb_y + b_u) >> BITS_OUT;
00160         dst2[0] = clamped_convert<unsigned char>(r);
00161         dst2[1] = clamped_convert<unsigned char>(g);
00162         dst2[2] = clamped_convert<unsigned char>(b);
00163         y_src2++;
00164       }
00165       {
00166         const int rgb_y = RGB_Y_tab[*y_src2];
00167         const int r = (rgb_y + r_v) >> BITS_OUT;
00168         const int g = (rgb_y + g_uv) >> BITS_OUT;
00169         const int b = (rgb_y + b_u) >> BITS_OUT;
00170         dst2[3] = clamped_convert<unsigned char>(r);
00171         dst2[4] = clamped_convert<unsigned char>(g);
00172         dst2[5] = clamped_convert<unsigned char>(b);
00173         y_src2++;
00174       }
00175 
00176       dst += 6;
00177       dst2 += 6;
00178     }
00179 
00180     dst += dst_dif;
00181     dst2 += dst_dif;
00182 
00183     y_src += y_dif;
00184     y_src2 += y_dif;
00185 
00186     u_src += uv_stride;
00187     v_src += uv_stride;
00188   }
00189 }
00190 
00191 // NOTE: we have more precise values for these YUV/RGB conversion
00192 // factors in Image/colorDefs.H, but for now we stick with the lower
00193 // precision values here to maintain backward compatibility for
00194 // callers of rgb24_to_yv12_c() (mainly FfmpegEncoder).
00195 
00196 #define Y_R_IN   0.257 // VIDEOYUV_Y_R from Image/colorDefs.H
00197 #define Y_G_IN   0.504 // VIDEOYUV_Y_G
00198 #define Y_B_IN   0.098 // VIDEOYUV_Y_B
00199 #define Y_ADD_IN 16
00200 
00201 #define U_R_IN   0.148 // -VIDEOYUV_U_R
00202 #define U_G_IN   0.291 // -VIDEOYUV_U_G
00203 #define U_B_IN   0.439 // VIDEOYUV_U_B
00204 #define U_ADD_IN 128
00205 
00206 #define V_R_IN   0.439 // VIDEOYUV_V_R
00207 #define V_G_IN   0.368 // -VIDEOYUV_V_G
00208 #define V_B_IN   0.071 // -VIDEOYUV_V_B
00209 #define V_ADD_IN 128
00210 
00211 #define SCALEBITS_IN 8
00212 
00213 #define FIX_IN(x) (int((x) * (1L<<SCALEBITS_IN) + 0.5))
00214 
00215 void rgb24_to_yv12_c(const Image<PixRGB<byte> >& img,
00216                      byte* const y_out,
00217                      byte* u_out,
00218                      byte* v_out)
00219 {
00220 GVX_TRACE(__PRETTY_FUNCTION__);
00221 
00222   const int width = img.getWidth();
00223   const int height = img.getHeight();
00224 
00225   const int width2 = width/2;
00226   const int height2 = height/2;
00227 
00228   typedef Image<PixRGB<byte> >::const_iterator src_iterator;
00229 
00230   const src_iterator in_begin = img.begin();
00231 
00232   for (int y = 0; y < height2; ++y)
00233     {
00234       // iterate in parallel over adjacent rows of both the input
00235       // image and the output Y image
00236 
00237       src_iterator src1 = in_begin + 2 * y * width;
00238       src_iterator src2 = src1 + width;
00239 
00240       byte* y_out1 = y_out + 2 * y * width;
00241       byte* y_out2 = y_out1 + width;
00242 
00243       for (int x = 0; x < width2; ++x)
00244         {
00245           uint r, g, b, r4, g4, b4;
00246 
00247           r4 = r = src1->red();
00248           g4 = g = src1->green();
00249           b4 = b = src1->blue();
00250           ++src1;
00251           *y_out1++ =
00252             (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00253                      FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00254 
00255           r4 += (r = src1->red());
00256           g4 += (g = src1->green());
00257           b4 += (b = src1->blue());
00258           ++src1;
00259           *y_out1++ =
00260             (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00261                      FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00262 
00263           r4 += (r = src2->red());
00264           g4 += (g = src2->green());
00265           b4 += (b = src2->blue());
00266           ++src2;
00267           *y_out2++ =
00268             (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00269                      FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00270 
00271           r4 += (r = src2->red());
00272           g4 += (g = src2->green());
00273           b4 += (b = src2->blue());
00274           ++src2;
00275           *y_out2++ =
00276             (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00277                      FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00278 
00279           *u_out++ =
00280             (byte) ((-FIX_IN(U_R_IN) * r4 - FIX_IN(U_G_IN) * g4 +
00281                      FIX_IN(U_B_IN) * b4) >> (SCALEBITS_IN + 2)) +
00282             U_ADD_IN;
00283 
00284 
00285           *v_out++ =
00286             (byte) ((FIX_IN(V_R_IN) * r4 - FIX_IN(V_G_IN) * g4 -
00287                      FIX_IN(V_B_IN) * b4) >> (SCALEBITS_IN + 2)) +
00288             V_ADD_IN;
00289 
00290 
00291           if (x==(width2-1) && (width&1))
00292             {
00293               r4 = r = src1->red();
00294               g4 = g = src1->green();
00295               b4 = b = src1->blue();
00296               ++src1;
00297               *y_out1++ =
00298                 (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00299                          FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00300 
00301               r4 += (r = src2->red());
00302               g4 += (g = src2->green());
00303               b4 += (b = src2->blue());
00304               ++src2;
00305               *y_out2++ =
00306                 (byte) ((FIX_IN(Y_R_IN) * r + FIX_IN(Y_G_IN) * g +
00307                          FIX_IN(Y_B_IN) * b) >> SCALEBITS_IN) + Y_ADD_IN;
00308 
00309               *u_out++ =
00310                 (byte) ((-FIX_IN(U_R_IN) * r4 - FIX_IN(U_G_IN) * g4 +
00311                          FIX_IN(U_B_IN) * b4) >> (SCALEBITS_IN + 1)) +
00312                 U_ADD_IN;
00313 
00314               *v_out++ =
00315                 (byte) ((FIX_IN(V_R_IN) * r4 - FIX_IN(V_G_IN) * g4 -
00316                          FIX_IN(V_B_IN) * b4) >> (SCALEBITS_IN + 1)) +
00317                 V_ADD_IN;
00318             }
00319         }
00320     }
00321 }
00322 
00323 void yuv422p_to_rgb24_c(byte* dst,
00324                         const int w, const int h,
00325                         const byte* yptr,
00326                         const byte* uptr,
00327                         const byte* vptr)
00328 {
00329   pthread_once(&colorspace_init_once, &colorspace_init);
00330 
00331   for (int j = 0; j < h; ++j)
00332     for (int i = 0; i < w; i += 2)
00333       {
00334         // we have 2 luminance pixels per chroma pair
00335 
00336         const int r_v = R_V_tab[*vptr];
00337         const int g_uv = - G_U_tab[*uptr] - G_V_tab[*vptr];
00338         const int b_u = B_U_tab[*uptr];
00339 
00340         ++uptr;
00341         ++vptr;
00342 
00343         // first luminance pixel:
00344 
00345         {
00346           const int rgb_y1 = RGB_Y_tab[*yptr++];
00347 
00348           const int r1 = (rgb_y1 + r_v) >> BITS_OUT;
00349           const int g1 = (rgb_y1 + g_uv) >> BITS_OUT;
00350           const int b1 = (rgb_y1 + b_u) >> BITS_OUT;
00351 
00352           *dst++ = clamped_convert<byte>(r1);
00353           *dst++ = clamped_convert<byte>(g1);
00354           *dst++ = clamped_convert<byte>(b1);
00355 
00356         }
00357 
00358         // second luminance pixel:
00359 
00360         {
00361           const int rgb_y2 = RGB_Y_tab[*yptr++];
00362 
00363           const int r2 = (rgb_y2 + r_v) >> BITS_OUT;
00364           const int g2 = (rgb_y2 + g_uv) >> BITS_OUT;
00365           const int b2 = (rgb_y2 + b_u) >> BITS_OUT;
00366 
00367           *dst++ = clamped_convert<byte>(r2);
00368           *dst++ = clamped_convert<byte>(g2);
00369           *dst++ = clamped_convert<byte>(b2);
00370         }
00371       }
00372 }
00373 
00374 void yuv422_to_rgb24_c(byte* dst,
00375                        const int w, const int h,
00376                        const byte* yuv422ptr,
00377                        const bool byteswap)
00378 {
00379   pthread_once(&colorspace_init_once, &colorspace_init);
00380 
00381   if (byteswap)
00382     for (int j = 0; j < h; ++j)
00383       for (int i = 0; i < w; i += 2)
00384         {
00385           // we have 2 luminance pixels per chroma pair
00386 
00387           const byte y1 = yuv422ptr[0];
00388           const byte u = yuv422ptr[1];
00389           const byte y2 = yuv422ptr[2];
00390           const byte v = yuv422ptr[3];
00391 
00392           yuv422ptr += 4;
00393 
00394           const int r_v = R_V_tab[v];
00395           const int g_uv = - G_U_tab[u] - G_V_tab[v];
00396           const int b_u = B_U_tab[u];
00397 
00398           // first luminance pixel:
00399           const int rgb_y1 = RGB_Y_tab[y1];
00400 
00401           *dst++ = clamped_convert<byte>((rgb_y1 + r_v) >> BITS_OUT);
00402           *dst++ = clamped_convert<byte>((rgb_y1 + g_uv) >> BITS_OUT);
00403           *dst++ = clamped_convert<byte>((rgb_y1 + b_u) >> BITS_OUT);
00404 
00405           // second luminance pixel:
00406           const int rgb_y2 = RGB_Y_tab[y2];
00407 
00408           *dst++ = clamped_convert<byte>((rgb_y2 + r_v) >> BITS_OUT);
00409           *dst++ = clamped_convert<byte>((rgb_y2 + g_uv) >> BITS_OUT);
00410           *dst++ = clamped_convert<byte>((rgb_y2 + b_u) >> BITS_OUT);
00411         }
00412 
00413   else // no byteswap
00414     for (int j = 0; j < h; ++j)
00415       for (int i = 0; i < w; i += 2)
00416         {
00417           // we have 2 luminance pixels per chroma pair
00418 
00419           const byte y1 = yuv422ptr[1];
00420           const byte u = yuv422ptr[0];
00421           const byte y2 = yuv422ptr[3];
00422           const byte v = yuv422ptr[2];
00423 
00424           yuv422ptr += 4;
00425 
00426           const int r_v = R_V_tab[v];
00427           const int g_uv = - G_U_tab[u] - G_V_tab[v];
00428           const int b_u = B_U_tab[u];
00429 
00430           // first luminance pixel:
00431           const int rgb_y1 = RGB_Y_tab[y1];
00432 
00433           *dst++ = clamped_convert<byte>((rgb_y1 + r_v) >> BITS_OUT);
00434           *dst++ = clamped_convert<byte>((rgb_y1 + g_uv) >> BITS_OUT);
00435           *dst++ = clamped_convert<byte>((rgb_y1 + b_u) >> BITS_OUT);
00436 
00437           // second luminance pixel:
00438           const int rgb_y2 = RGB_Y_tab[y2];
00439 
00440           *dst++ = clamped_convert<byte>((rgb_y2 + r_v) >> BITS_OUT);
00441           *dst++ = clamped_convert<byte>((rgb_y2 + g_uv) >> BITS_OUT);
00442           *dst++ = clamped_convert<byte>((rgb_y2 + b_u) >> BITS_OUT);
00443         }
00444 }
00445 
00446 // ######################################################################
00447 /* So things look consistent in everyone's emacs... */
00448 /* Local Variables: */
00449 /* indent-tabs-mode: nil */
00450 /* End: */
Generated on Sun May 8 08:05:05 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3