core/vidl/vidl_convert.cxx
Go to the documentation of this file.
00001 // This is core/vidl/vidl_convert.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Matt Leotta
00008 // \date   20 Jan 2006
00009 //
00010 // \verbatim
00011 //  Modifications
00012 //   10 Jul.2008 - Antonio Garrido - Added convertions for RGB_24(P),MONO8 and YUYV_422
00013 // \endvarbatim
00014 //
00015 //-----------------------------------------------------------------------------
00016 
00017 #include "vidl_convert.h"
00018 #include "vidl_frame.h"
00019 #include "vidl_pixel_format.h"
00020 #include "vidl_pixel_iterator.txx"
00021 #include "vidl_color.h"
00022 #include <vil/vil_convert.h>
00023 #include <vil/vil_new.h>
00024 #include <vil/vil_memory_chunk.h>
00025 #include <vcl_cstring.h>
00026 #include <vcl_cassert.h>
00027 #include <vcl_memory.h>
00028 
00029 //--------------------------------------------------------------------------------
00030 
00031 
00032 namespace {
00033 
00034 //: Define the function pointer for pixel format conversion functions
00035 typedef bool (*converter_func)(const vidl_frame& in_frame, vidl_frame& out_frame);
00036 
00037 
00038 //: Default pixel format conversion - it fails
00039 bool default_conversion(const vidl_frame& in_frame, vidl_frame& out_frame)
00040 {
00041   vcl_cerr << "No routine to convert " << in_frame.pixel_format()
00042            << " to " << out_frame.pixel_format() << vcl_endl;
00043   return false;
00044 }
00045 
00046 
00047 //: Use memcpy when the formats are the same
00048 bool copy_conversion(const vidl_frame& in_frame, vidl_frame& out_frame)
00049 {
00050   assert(in_frame.pixel_format() == out_frame.pixel_format());
00051   assert(in_frame.size() == out_frame.size());
00052   vcl_memcpy(out_frame.data(), in_frame.data(), in_frame.size());
00053   return true;
00054 }
00055 
00056 
00057 //: Convert to an intermediate RGB_24 frame
00058 // This is inefficient, but will provide the functionality until
00059 // an optimized version is written
00060 // defined later because it uses conversion_table
00061 bool intermediate_rgb24_conversion(const vidl_frame& in_frame, vidl_frame& out_frame);
00062 
00063 
00064 // Default pixel format conversion - it fails
00065 template <vidl_pixel_format in_Fmt, vidl_pixel_format out_Fmt>
00066 struct convert
00067 {
00068   enum { defined = false };
00069   static inline bool apply(const vidl_frame& /*in_frame*/,
00070                            vidl_frame& /*out_frame*/)
00071   {
00072     return false;
00073   }
00074 };
00075 
00076 //=============================================================================
00077 // Start of generic pixel conversions
00078 
00079 
00080 //: The generic pixel conversion function
00081 bool convert_generic(const vidl_frame& in_frame,
00082                      vidl_frame& out_frame)
00083 {
00084   // create pixel iterators for each frame
00085   vcl_auto_ptr<vidl_pixel_iterator> in_pitr(vidl_make_pixel_iterator(in_frame));
00086   if (!in_pitr.get())
00087     return false;
00088   vcl_auto_ptr<vidl_pixel_iterator> out_pitr(vidl_make_pixel_iterator(out_frame));
00089   if (!out_pitr.get())
00090     return false;
00091 
00092   vidl_pixel_iterator& in_itr = *in_pitr;
00093   vidl_pixel_iterator& out_itr = *out_pitr;
00094 
00095   vidl_pixel_traits in_t = vidl_pixel_format_traits(in_frame.pixel_format());
00096   vidl_pixel_traits out_t = vidl_pixel_format_traits(out_frame.pixel_format());
00097 
00098   // find the color conversion function
00099   vidl_color_conv_fptr color_conv =
00100       vidl_color_converter_func( in_t.color,  *in_t.type,
00101                                  out_t.color, *out_t.type);
00102   if (!color_conv)
00103     return false;
00104 
00105   const unsigned int num_pix = in_frame.ni() * in_frame.nj();
00106   // assume pixels are no more than 32 bytes (that's 4 doubles)
00107   vxl_byte in_pixel[32], out_pixel[32];
00108   for (unsigned int c=0; c<num_pix; ++c, ++in_itr, ++out_itr) {
00109     in_itr.get_data(in_pixel);
00110     color_conv(in_pixel, out_pixel);
00111     out_itr.set_data(out_pixel);
00112   }
00113   return true;
00114 }
00115 
00116 
00117 //=============================================================================
00118 // Start of pixel conversion specializations
00119 // Write optimized conversion specializations below
00120 
00121 // RGB_24 to UYVY_422
00122 VCL_DEFINE_SPECIALIZATION
00123 struct convert<VIDL_PIXEL_FORMAT_RGB_24, VIDL_PIXEL_FORMAT_UYVY_422>
00124 {
00125   enum { defined = true };
00126   static bool apply(const vidl_frame& in_frame,
00127                           vidl_frame& out_frame)
00128   {
00129     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24);
00130     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_UYVY_422);
00131     const vxl_byte* rgb = reinterpret_cast<const vxl_byte*>(in_frame.data());
00132     vxl_byte* uyvy = reinterpret_cast<vxl_byte*>(out_frame.data());
00133     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00134     for (unsigned int c=0; c<num_half_pix; ++c) {
00135       const vxl_byte& r1 = *(rgb++);
00136       const vxl_byte& g1 = *(rgb++);
00137       const vxl_byte& b1 = *(rgb++);
00138       const vxl_byte& r2 = *(rgb++);
00139       const vxl_byte& g2 = *(rgb++);
00140       const vxl_byte& b2 = *(rgb++);
00141       vxl_byte y1,u1,v1,y2,u2,v2;
00142       vidl_color_convert_rgb2yuv(r1,g1,b1,y1,u1,v1);
00143       vidl_color_convert_rgb2yuv(r2,g2,b2,y2,u2,v2);
00144       *(uyvy++) = (u1+u2)/2u;
00145       *(uyvy++) = y1;
00146       *(uyvy++) = (v1+v2)/2u;
00147       *(uyvy++) = y2;
00148     }
00149     return true;
00150   }
00151 };
00152 
00153 
00154 // UYVY_422 to RGB_24
00155 VCL_DEFINE_SPECIALIZATION
00156 struct convert<VIDL_PIXEL_FORMAT_UYVY_422, VIDL_PIXEL_FORMAT_RGB_24>
00157 {
00158   enum { defined = true };
00159   static bool apply(const vidl_frame& in_frame,
00160                           vidl_frame& out_frame)
00161   {
00162     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_UYVY_422);
00163     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24);
00164     const vxl_byte* uyvy = reinterpret_cast<const vxl_byte*>(in_frame.data());
00165     vxl_byte* rgb = reinterpret_cast<vxl_byte*>(out_frame.data());
00166     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00167     for (unsigned int c=0; c<num_half_pix; ++c) {
00168       const vxl_byte& u1 = *(uyvy++);
00169       const vxl_byte& y1 = *(uyvy++);
00170       const vxl_byte& v1 = *(uyvy++);
00171       const vxl_byte& y2 = *(uyvy++);
00172       vxl_byte r,g,b;
00173       vidl_color_convert_yuv2rgb(y1,u1,v1,r,g,b);
00174       *(rgb++) = r;
00175       *(rgb++) = g;
00176       *(rgb++) = b;
00177       vidl_color_convert_yuv2rgb(y2,u1,v1,r,g,b);
00178       *(rgb++) = r;
00179       *(rgb++) = g;
00180       *(rgb++) = b;
00181     }
00182     return true;
00183   }
00184 };
00185 
00186 
00187 // UYVY_422 to MONO_8
00188 VCL_DEFINE_SPECIALIZATION
00189 struct convert<VIDL_PIXEL_FORMAT_UYVY_422, VIDL_PIXEL_FORMAT_MONO_8>
00190 {
00191   enum { defined = true };
00192   static bool apply(const vidl_frame& in_frame,
00193                           vidl_frame& out_frame)
00194   {
00195     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_UYVY_422);
00196     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_MONO_8);
00197     const vxl_byte* uyvy = reinterpret_cast<const vxl_byte*>(in_frame.data());
00198     vxl_byte* mono = reinterpret_cast<vxl_byte*>(out_frame.data());
00199     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00200     for (unsigned int c=0; c<num_half_pix; ++c) {
00201       ++uyvy;
00202       const vxl_byte& y1 = *(uyvy++);
00203       ++uyvy;
00204       const vxl_byte& y2 = *(uyvy++);
00205       *(mono++) = y1;
00206       *(mono++) = y2;
00207     }
00208     return true;
00209   }
00210 };
00211 
00212 
00213 // RGB_24 to YUYV_422
00214 VCL_DEFINE_SPECIALIZATION
00215 struct convert<VIDL_PIXEL_FORMAT_RGB_24, VIDL_PIXEL_FORMAT_YUYV_422>
00216 {
00217   enum { defined = true };
00218   static bool apply(const vidl_frame& in_frame,
00219                           vidl_frame& out_frame)
00220   {
00221     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24);
00222     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_YUYV_422);
00223     const vxl_byte* rgb = reinterpret_cast<const vxl_byte*>(in_frame.data());
00224     vxl_byte* yuyv = reinterpret_cast<vxl_byte*>(out_frame.data());
00225     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00226     for (unsigned int c=0; c<num_half_pix; ++c) {
00227       const vxl_byte& r1 = *(rgb++);
00228       const vxl_byte& g1 = *(rgb++);
00229       const vxl_byte& b1 = *(rgb++);
00230       const vxl_byte& r2 = *(rgb++);
00231       const vxl_byte& g2 = *(rgb++);
00232       const vxl_byte& b2 = *(rgb++);
00233       vxl_byte y1,u1,v1,y2,u2,v2;
00234       vidl_color_convert_rgb2yuv(r1,g1,b1,y1,u1,v1);
00235       vidl_color_convert_rgb2yuv(r2,g2,b2,y2,u2,v2);
00236       *(yuyv++) = y1;
00237       *(yuyv++) = (u1+u2)/2u;
00238       *(yuyv++) = y2;
00239       *(yuyv++) = (v1+v2)/2u;
00240     }
00241     return true;
00242   }
00243 };
00244 
00245 
00246 // YUYV_422 to RGB_24
00247 VCL_DEFINE_SPECIALIZATION
00248 struct convert<VIDL_PIXEL_FORMAT_YUYV_422, VIDL_PIXEL_FORMAT_RGB_24>
00249 {
00250   enum { defined = true };
00251   static bool apply(const vidl_frame& in_frame,
00252                           vidl_frame& out_frame)
00253   {
00254     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_YUYV_422);
00255     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24);
00256     const vxl_byte* yuyv = reinterpret_cast<const vxl_byte*>(in_frame.data());
00257     vxl_byte* rgb = reinterpret_cast<vxl_byte*>(out_frame.data());
00258     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00259     for (unsigned int c=0; c<num_half_pix; ++c) {
00260       const vxl_byte& y1 = *(yuyv++);
00261       const vxl_byte& u1 = *(yuyv++);
00262       const vxl_byte& y2 = *(yuyv++);
00263       const vxl_byte& v1 = *(yuyv++);
00264       vxl_byte r,g,b;
00265       vidl_color_convert_yuv2rgb(y1,u1,v1,r,g,b);
00266       *(rgb++) = r;
00267       *(rgb++) = g;
00268       *(rgb++) = b;
00269       vidl_color_convert_yuv2rgb(y2,u1,v1,r,g,b);
00270       *(rgb++) = r;
00271       *(rgb++) = g;
00272       *(rgb++) = b;
00273     }
00274     return true;
00275   }
00276 };
00277 
00278 
00279 // RGB_24P to YUYV_422
00280 VCL_DEFINE_SPECIALIZATION
00281 struct convert<VIDL_PIXEL_FORMAT_RGB_24P, VIDL_PIXEL_FORMAT_YUYV_422>
00282 {
00283   enum { defined = true };
00284   static bool apply(const vidl_frame& in_frame,
00285                           vidl_frame& out_frame)
00286   {
00287     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24P);
00288     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_YUYV_422);
00289     const vxl_byte* red = reinterpret_cast<const vxl_byte*>(in_frame.data());
00290     const vxl_byte* green= red+in_frame.ni() * in_frame.nj();
00291     const vxl_byte* blue= green+in_frame.ni() * in_frame.nj();
00292     vxl_byte* yuyv = reinterpret_cast<vxl_byte*>(out_frame.data());
00293     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00294     for (unsigned int c=0; c<num_half_pix; ++c) {
00295       const vxl_byte& r1 = *(red++);
00296       const vxl_byte& g1 = *(green++);
00297       const vxl_byte& b1 = *(blue++);
00298       const vxl_byte& r2 = *(red++);
00299       const vxl_byte& g2 = *(green++);
00300       const vxl_byte& b2 = *(blue++);
00301       vxl_byte y1,u1,v1,y2,u2,v2;
00302       vidl_color_convert_rgb2yuv(r1,g1,b1,y1,u1,v1);
00303       vidl_color_convert_rgb2yuv(r2,g2,b2,y2,u2,v2);
00304       *(yuyv++) = y1;
00305       *(yuyv++) = (u1+u2)/2u;
00306       *(yuyv++) = y2;
00307       *(yuyv++) = (v1+v2)/2u;
00308     }
00309     return true;
00310   }
00311 };
00312 
00313 // YUYV_422 to RGB_24P
00314 VCL_DEFINE_SPECIALIZATION
00315 struct convert<VIDL_PIXEL_FORMAT_YUYV_422, VIDL_PIXEL_FORMAT_RGB_24P>
00316 {
00317   enum { defined = true };
00318   static bool apply(const vidl_frame& in_frame,
00319                           vidl_frame& out_frame)
00320   {
00321     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_YUYV_422);
00322     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_RGB_24P);
00323     const vxl_byte* yuyv = reinterpret_cast<const vxl_byte*>(in_frame.data());
00324     vxl_byte* red = reinterpret_cast<vxl_byte*>(out_frame.data());
00325     vxl_byte* green = red+out_frame.ni()*out_frame.nj();
00326     vxl_byte* blue = green+out_frame.ni()*out_frame.nj();
00327     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00328     for (unsigned int c=0; c<num_half_pix; ++c) {
00329       const vxl_byte& y1 = *(yuyv++);
00330       const vxl_byte& u1 = *(yuyv++);
00331       const vxl_byte& y2 = *(yuyv++);
00332       const vxl_byte& v1 = *(yuyv++);
00333       vxl_byte r,g,b;
00334       vidl_color_convert_yuv2rgb(y1,u1,v1,r,g,b);
00335       *(red++) = r;
00336       *(green++) = g;
00337       *(blue++) = b;
00338       vidl_color_convert_yuv2rgb(y2,u1,v1,r,g,b);
00339       *(red++) = r;
00340       *(green++) = g;
00341       *(blue++) = b;
00342     }
00343     return true;
00344   }
00345 };
00346 
00347 // YUYV_422 to MONO_8
00348 VCL_DEFINE_SPECIALIZATION
00349 struct convert<VIDL_PIXEL_FORMAT_YUYV_422, VIDL_PIXEL_FORMAT_MONO_8>
00350 {
00351   enum { defined = true };
00352   static bool apply(const vidl_frame& in_frame,
00353                           vidl_frame& out_frame)
00354   {
00355     assert(in_frame.pixel_format()==VIDL_PIXEL_FORMAT_YUYV_422);
00356     assert(out_frame.pixel_format()==VIDL_PIXEL_FORMAT_MONO_8);
00357     const vxl_byte* yuyv = reinterpret_cast<const vxl_byte*>(in_frame.data());
00358     vxl_byte* mono = reinterpret_cast<vxl_byte*>(out_frame.data());
00359     unsigned int num_half_pix = (in_frame.ni() * in_frame.nj() + 1)/2;
00360     for (unsigned int c=0; c<num_half_pix; ++c) {
00361       const vxl_byte& y1 = *(yuyv++);
00362       ++yuyv;
00363       const vxl_byte& y2 = *(yuyv++);
00364       ++yuyv;
00365       *(mono++) = y1;
00366       *(mono++) = y2;
00367     }
00368     return true;
00369   }
00370 };
00371 
00372 
00373 // End of pixel conversion specializations
00374 //=============================================================================
00375 
00376 
00377 //: Generates an entry into the table of pixel format conversions functions
00378 // This is called for every pair for pixel formats to build the table
00379 template <vidl_pixel_format in_Fmt, vidl_pixel_format out_Fmt>
00380 struct table_entry_init
00381 {
00382   static inline void set_entry(converter_func& table_entry)
00383   {
00384     // This should be done at compile time with partial specialization
00385     // This run time code generates many functions that are never actually used
00386     if (in_Fmt == out_Fmt)
00387       table_entry = &copy_conversion;
00388     else if (convert<in_Fmt,out_Fmt>::defined)
00389       table_entry = &convert<in_Fmt,out_Fmt>::apply;
00390     else if (vidl_pixel_iterator_valid<in_Fmt>::value &&
00391              vidl_pixel_iterator_valid<out_Fmt>::value)
00392       table_entry = &convert_generic;
00393     else
00394       table_entry = &default_conversion;
00395   }
00396 };
00397 
00398 //: Recursive template metaprogram to generate conditionals for converting each pair of pixel types
00399 template <int Fmt_Code>
00400 struct table_init
00401 {
00402   static inline void populate(converter_func table[VIDL_PIXEL_FORMAT_ENUM_END][VIDL_PIXEL_FORMAT_ENUM_END])
00403   {
00404     const vidl_pixel_format in_fmt = vidl_pixel_format(Fmt_Code/VIDL_PIXEL_FORMAT_ENUM_END);
00405     const vidl_pixel_format out_fmt = vidl_pixel_format(Fmt_Code%VIDL_PIXEL_FORMAT_ENUM_END);
00406     table_entry_init<in_fmt,out_fmt>::set_entry(table[in_fmt][out_fmt]);
00407     table_init<Fmt_Code-1>::populate(table);
00408   }
00409 };
00410 
00411 
00412 //: The base case
00413 VCL_DEFINE_SPECIALIZATION
00414 struct table_init<0>
00415 {
00416   static inline void populate(converter_func table[VIDL_PIXEL_FORMAT_ENUM_END][VIDL_PIXEL_FORMAT_ENUM_END])
00417   {
00418     const vidl_pixel_format in_fmt = vidl_pixel_format(0);
00419     const vidl_pixel_format out_fmt = vidl_pixel_format(0);
00420     table_entry_init<in_fmt,out_fmt>::set_entry(table[in_fmt][out_fmt]);
00421   }
00422 };
00423 
00424 
00425 //: A table of all conversion functions
00426 class converter
00427 {
00428  public:
00429   //: Constructor - generate the table
00430   converter()
00431   {
00432     // generate the table of function pointers
00433     table_init<VIDL_PIXEL_FORMAT_ENUM_END*VIDL_PIXEL_FORMAT_ENUM_END-1>::populate(table);
00434   }
00435 
00436   //: Apply the conversion
00437   bool operator()(const vidl_frame& in_frame, vidl_frame& out_frame) const
00438   {
00439     return (*table[in_frame.pixel_format()][out_frame.pixel_format()])(in_frame, out_frame);
00440   }
00441  private:
00442   //: Table of conversion functions
00443   converter_func table[VIDL_PIXEL_FORMAT_ENUM_END][VIDL_PIXEL_FORMAT_ENUM_END];
00444 };
00445 
00446 //: Instantiate a global conversion function table
00447 converter conversion_table;
00448 
00449 //: Convert to an intermediate RGB_24 frame
00450 // Defined here because it uses conversion_table
00451 bool intermediate_rgb24_conversion(const vidl_frame& in_frame, vidl_frame& out_frame)
00452 {
00453   unsigned int ni = in_frame.ni(), nj = in_frame.nj();
00454   vil_memory_chunk_sptr memory = new vil_memory_chunk(ni*nj*3, VIL_PIXEL_FORMAT_BYTE);
00455   vidl_memory_chunk_frame temp_frame(ni,nj,VIDL_PIXEL_FORMAT_RGB_24,memory);
00456   return conversion_table(in_frame, temp_frame) &&
00457       conversion_table(temp_frame, out_frame);
00458 }
00459 
00460 } // end anonymous namespace
00461 
00462 //--------------------------------------------------------------------------------
00463 
00464 //: Convert the pixel format of a frame
00465 //
00466 // The \p in_frame->data() is converted from \p in_frame->pixel_format()
00467 // to \p out_frame->pixel_format() and stored in \p out_frame->data()
00468 // \returns false if the output frame data is not the correct size.
00469 bool vidl_convert_frame(const vidl_frame& in_frame,
00470                               vidl_frame& out_frame)
00471 {
00472   vidl_pixel_format in_fmt = in_frame.pixel_format();
00473   vidl_pixel_format out_fmt = out_frame.pixel_format();
00474 
00475   if (in_fmt  == VIDL_PIXEL_FORMAT_UNKNOWN ||
00476       out_fmt == VIDL_PIXEL_FORMAT_UNKNOWN)
00477     return false;
00478 
00479   unsigned ni = in_frame.ni();
00480   unsigned nj = in_frame.nj();
00481   unsigned out_size = vidl_pixel_format_buffer_size(ni,nj,out_fmt);
00482 
00483   if (out_frame.size() != out_size ||
00484       out_frame.ni() != ni ||
00485       out_frame.nj() != nj ||
00486       !out_frame.data() )
00487     return false;
00488 
00489   // call the appropriate function in the conversion table
00490   return conversion_table(in_frame, out_frame);
00491 }
00492 
00493 
00494 //: Convert the pixel format of a frame
00495 //
00496 // The convert \p in_frame to a \p format by allocating
00497 // a new frame buffer
00498 vidl_frame_sptr vidl_convert_frame(const vidl_frame_sptr& in_frame,
00499                                    vidl_pixel_format format)
00500 {
00501   if (format == VIDL_PIXEL_FORMAT_UNKNOWN)
00502     return NULL;
00503 
00504   unsigned ni = in_frame->ni();
00505   unsigned nj = in_frame->nj();
00506   unsigned size = vidl_pixel_format_buffer_size(ni,nj,format);
00507   vil_memory_chunk_sptr memory = new vil_memory_chunk(size, VIL_PIXEL_FORMAT_BYTE);
00508   vidl_frame_sptr out_frame = new vidl_memory_chunk_frame(ni, nj, format, memory);
00509 
00510   if (vidl_convert_frame(*in_frame, *out_frame))
00511     return out_frame;
00512 
00513   return NULL;
00514 }
00515 
00516 
00517 //: Convert the image view to a frame
00518 // Will wrap the memory if possible, if not the image is converted to
00519 // the closest vidl_pixel_format
00520 vidl_frame_sptr vidl_convert_to_frame(const vil_image_view_base_sptr& image)
00521 {
00522   if (!image)
00523     return NULL;
00524   return vidl_convert_to_frame(*image);
00525 }
00526 
00527 
00528 //: Convert the image view to a frame
00529 // Will wrap the memory if possible, if not the image is converted to
00530 // the closest vidl_pixel_format
00531 vidl_frame_sptr vidl_convert_to_frame(const vil_image_view_base& image)
00532 {
00533   // try to wrap the image memory in a frame
00534   vidl_frame_sptr frame = new vidl_memory_chunk_frame(image);
00535   if (frame->pixel_format() != VIDL_PIXEL_FORMAT_UNKNOWN)
00536     return frame;
00537 
00538   // if the image could not be wrapped convert it
00539   unsigned ni = image.ni(), nj = image.nj(), np = image.nplanes();
00540 
00541   // use the pixel component format to account for
00542   // images of type vil_rgb<T>, vil_rgba<T>, etc.
00543   vil_pixel_format cmp_format =
00544       vil_pixel_format_component_format(image.pixel_format());
00545   unsigned int num_cmp = vil_pixel_format_num_components(image.pixel_format());
00546   unsigned int num_channels = np * num_cmp;
00547 
00548   // special case for 16 bit images
00549   if (cmp_format == VIL_PIXEL_FORMAT_UINT_16)
00550   {
00551     if (num_channels == 1)
00552     {
00553       vil_image_view<vxl_uint_16> img(ni,nj);
00554       img.deep_copy(vil_image_view<vxl_uint_16>(image));
00555       return new vidl_memory_chunk_frame(ni, nj, VIDL_PIXEL_FORMAT_MONO_16,
00556                                          img.memory_chunk());
00557     }
00558   }
00559   // special case for 32 bit float images
00560   else if (cmp_format == VIL_PIXEL_FORMAT_FLOAT)
00561   {
00562     if (num_channels == 1 || num_channels == 3)
00563     {
00564       vidl_pixel_format format = VIDL_PIXEL_FORMAT_UNKNOWN;
00565       if (num_channels == 1)
00566         format = VIDL_PIXEL_FORMAT_MONO_F32;
00567       else
00568         format = VIDL_PIXEL_FORMAT_RGB_F32P;
00569 
00570       vil_image_view<vxl_ieee_32> img(ni,nj,num_channels);
00571       img.deep_copy(vil_image_view<vxl_ieee_32>(image));
00572       return new vidl_memory_chunk_frame(ni, nj, format,
00573                                          img.memory_chunk());
00574     }
00575   }
00576 
00577   vidl_pixel_format format = VIDL_PIXEL_FORMAT_UNKNOWN;
00578   if (num_channels == 1)
00579     format = VIDL_PIXEL_FORMAT_MONO_8;
00580   else if (num_channels == 3)
00581     format = VIDL_PIXEL_FORMAT_RGB_24P;
00582   else if (num_channels == 4)
00583     format = VIDL_PIXEL_FORMAT_RGBA_32P;
00584   else
00585     return NULL;
00586 
00587   vil_image_view<vxl_byte> img;
00588   if (image.pixel_format() == VIL_PIXEL_FORMAT_BYTE)
00589     img.deep_copy(vil_image_view<vxl_byte>(image));
00590   else
00591   {
00592     vil_image_resource_sptr resrc = vil_new_image_resource_of_view(image);
00593     vil_image_view_base_sptr bimage = vil_convert_cast(vxl_byte(),resrc->get_view());
00594     if (!bimage)
00595       return NULL;
00596     img = *bimage;
00597   }
00598   return new vidl_memory_chunk_frame(ni, nj, format,
00599                                      img.memory_chunk());
00600 }
00601 
00602 
00603 //: convert the frame into an image view
00604 // possibly converts the pixel data type
00605 // always create a deep copy of the data
00606 bool vidl_convert_to_view(const vidl_frame& frame,
00607                           vil_image_view_base& image,
00608                           vidl_pixel_color require_color)
00609 {
00610   if (frame.pixel_format() == VIDL_PIXEL_FORMAT_UNKNOWN ||
00611       frame.data() == NULL)
00612     return false;
00613 
00614   vidl_pixel_color in_color = vidl_pixel_format_color(frame.pixel_format());
00615   if (require_color == VIDL_PIXEL_COLOR_UNKNOWN)
00616     require_color = in_color;
00617 
00618   unsigned ni = frame.ni(), nj = frame.nj();
00619   unsigned np = vidl_pixel_color_num_channels(require_color);
00620 
00621   // resize the image if necessary
00622   image.set_size(ni,nj,np);
00623 
00624   // special case for MONO_16
00625   if (frame.pixel_format() == VIDL_PIXEL_FORMAT_MONO_16) {
00626     vil_image_view<vxl_uint_16> wrapper(static_cast<const vxl_uint_16*>(frame.data()),
00627                                         ni,nj,1,1,ni,ni*nj);
00628     if (image.pixel_format() == VIL_PIXEL_FORMAT_UINT_16) {
00629       vil_image_view<vxl_uint_16>& img = static_cast<vil_image_view<vxl_uint_16>&>(image);
00630       img.deep_copy(vil_image_view<vxl_uint_16>(wrapper));
00631       return true;
00632     }
00633 
00634     switch ( vil_pixel_format_component_format(image.pixel_format()) ) {
00635 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00636 #define macro(F , T) \
00637     case F: {\
00638       vil_image_view<T> & dest_ref = static_cast<vil_image_view<T> &>(image); \
00639       vil_convert_cast( wrapper, dest_ref); break;}
00640 
00641 #if VXL_HAS_INT_64
00642     macro( VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64 );
00643     macro( VIL_PIXEL_FORMAT_INT_64, vxl_int_64 );
00644 #endif
00645     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 );
00646     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 );
00647     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 );
00648     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte );
00649     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte );
00650     macro( VIL_PIXEL_FORMAT_FLOAT, float );
00651     macro( VIL_PIXEL_FORMAT_DOUBLE, double );
00652     macro( VIL_PIXEL_FORMAT_BOOL, bool );
00653 #undef macro
00654 #endif // DOXYGEN_SHOULD_SKIP_THIS
00655       default:
00656         return false;
00657     }
00658     return true;
00659   }
00660 
00661   vidl_pixel_format default_format = VIDL_PIXEL_FORMAT_UNKNOWN;
00662   if (image.pixel_format() == VIL_PIXEL_FORMAT_BYTE)
00663   {
00664     vil_image_view<vxl_byte>& img = static_cast<vil_image_view<vxl_byte>&>(image);
00665     bool interleaved = (img.planestep() == 1);
00666 
00667     switch (require_color) {
00668       case VIDL_PIXEL_COLOR_MONO:
00669         default_format = VIDL_PIXEL_FORMAT_MONO_8; break;
00670       case VIDL_PIXEL_COLOR_RGB:
00671         default_format = interleaved?VIDL_PIXEL_FORMAT_RGB_24
00672                                     :VIDL_PIXEL_FORMAT_RGB_24P; break;
00673       case VIDL_PIXEL_COLOR_RGBA:
00674         default_format = interleaved?VIDL_PIXEL_FORMAT_RGBA_32
00675                                     :VIDL_PIXEL_FORMAT_RGBA_32P; break;
00676       case VIDL_PIXEL_COLOR_YUV:
00677         default_format = interleaved?VIDL_PIXEL_FORMAT_UYV_444
00678                                     :VIDL_PIXEL_FORMAT_YUV_444P; break;
00679       default:
00680         break;
00681     }
00682   }
00683 
00684   vidl_frame_sptr out_frame = new vidl_memory_chunk_frame(image,default_format);
00685   // if the image can be wrapped as a frame
00686   if (out_frame->pixel_format() != VIDL_PIXEL_FORMAT_UNKNOWN) {
00687     vidl_convert_frame(frame, *out_frame);
00688     return true;
00689   }
00690 
00691   // use an intermediate format
00692   vidl_pixel_format out_fmt;
00693   switch (in_color) {
00694     case VIDL_PIXEL_COLOR_MONO:
00695       out_fmt = VIDL_PIXEL_FORMAT_MONO_8; break;
00696     case VIDL_PIXEL_COLOR_RGB:
00697       out_fmt = VIDL_PIXEL_FORMAT_RGB_24P; break;
00698     case VIDL_PIXEL_COLOR_RGBA:
00699       out_fmt = VIDL_PIXEL_FORMAT_RGBA_32P; break;
00700     case VIDL_PIXEL_COLOR_YUV:
00701       out_fmt = VIDL_PIXEL_FORMAT_YUV_444P; break;
00702     default:
00703       return false;
00704   }
00705 
00706   vil_image_view<vxl_byte> temp(ni,nj,np);
00707   out_frame = new vidl_memory_chunk_frame(ni,nj,out_fmt,temp.memory_chunk());
00708   vidl_convert_frame(frame, *out_frame);
00709 
00710   switch ( vil_pixel_format_component_format(image.pixel_format()) ) {
00711 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00712 #define macro(F , T) \
00713     case F: {\
00714       vil_image_view<T> & dest_ref = static_cast<vil_image_view<T> &>(image); \
00715       vil_convert_cast( temp, dest_ref); break;}
00716 
00717 #if VXL_HAS_INT_64
00718     macro( VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64 );
00719     macro( VIL_PIXEL_FORMAT_INT_64, vxl_int_64 );
00720 #endif
00721     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 );
00722     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 );
00723     macro( VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16 );
00724     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 );
00725     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte );
00726     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte );
00727     macro( VIL_PIXEL_FORMAT_FLOAT, float );
00728     macro( VIL_PIXEL_FORMAT_DOUBLE, double );
00729     macro( VIL_PIXEL_FORMAT_BOOL, bool );
00730 #undef macro
00731 #endif // DOXYGEN_SHOULD_SKIP_THIS
00732     default:
00733       return false;
00734   }
00735   return true;
00736 }
00737 
00738 
00739 //: Wrap the frame buffer in an image view if supported
00740 // Returns a null pointer if not possible
00741 vil_image_view_base_sptr
00742 vidl_convert_wrap_in_view(const vidl_frame& frame)
00743 {
00744   vidl_pixel_format format = frame.pixel_format();
00745   vidl_pixel_traits pt =  vidl_pixel_format_traits(format);
00746   if ( pt.chroma_shift_x != 0 || pt.chroma_shift_y != 0 ||
00747        pt.bits_per_pixel % pt.num_channels != 0)
00748     return NULL;
00749 
00750   unsigned ni = frame.ni(), nj = frame.nj();
00751   unsigned np = pt.num_channels;
00752   vcl_ptrdiff_t i_step, j_step, p_step;
00753   switch (pt.arrangement) {
00754     case VIDL_PIXEL_ARRANGE_SINGLE:
00755       i_step = np;
00756       j_step = np*ni;
00757       p_step = 1;
00758       break;
00759     case VIDL_PIXEL_ARRANGE_PLANAR:
00760       i_step = 1;
00761       j_step = ni;
00762       p_step = ni*nj;
00763       break;
00764     default:
00765       // Cannot wrap other pixel arrangements
00766       return NULL;
00767   }
00768   vcl_ptrdiff_t top_left_offset = 0;
00769 
00770   if (format == VIDL_PIXEL_FORMAT_BGR_24) {
00771     top_left_offset = 3;
00772     p_step = -1;
00773   }
00774 
00775   // Create a view of a memory chunk frame
00776   if ( const vidl_memory_chunk_frame* cf =
00777        dynamic_cast<const vidl_memory_chunk_frame*>(&frame) )
00778   {
00779     vil_memory_chunk_sptr chunk = cf->memory_chunk();
00780     if (format == VIDL_PIXEL_FORMAT_MONO_16) {
00781       const vxl_uint_16* top_left = static_cast<const vxl_uint_16*>(cf->data()) + top_left_offset;
00782       return new vil_image_view<vxl_uint_16>(chunk,top_left, ni,nj,np, i_step,j_step,p_step);
00783     }
00784     else if (format == VIDL_PIXEL_FORMAT_MONO_1) {
00785       const bool* top_left = static_cast<const bool*>(cf->data()) + top_left_offset;
00786       return new vil_image_view<bool>(chunk,top_left, ni,nj,np, i_step,j_step,p_step);
00787     }else if (format == VIDL_PIXEL_FORMAT_MONO_F32 ||
00788               format == VIDL_PIXEL_FORMAT_RGB_F32 ||
00789               format == VIDL_PIXEL_FORMAT_RGB_F32P) {
00790       const vxl_ieee_32* top_left = static_cast<const vxl_ieee_32*>(cf->data()) + top_left_offset;
00791       return new vil_image_view<float>(chunk,top_left, ni,nj,np, i_step,j_step,p_step);
00792     } else {
00793       const vxl_byte* top_left = static_cast<const vxl_byte*>(cf->data()) + top_left_offset;
00794       return new vil_image_view<vxl_byte>(chunk,top_left, ni,nj,np, i_step,j_step,p_step);
00795     }
00796   }
00797 
00798   // Create a view of a frame (without ownership of the data)
00799   if (format == VIDL_PIXEL_FORMAT_MONO_16) {
00800     const vxl_uint_16* top_left = static_cast<const vxl_uint_16*>(frame.data()) + top_left_offset;
00801     return new vil_image_view<vxl_uint_16>(top_left, ni,nj,np, i_step,j_step,p_step);
00802   }
00803   else if (format == VIDL_PIXEL_FORMAT_MONO_1) {
00804     const bool* top_left = static_cast<const bool*>(frame.data()) + top_left_offset;
00805     return new vil_image_view<bool>(top_left, ni,nj,np, i_step,j_step,p_step);
00806   }
00807   const vxl_byte* top_left = static_cast<const vxl_byte*>(frame.data()) + top_left_offset;
00808   return new vil_image_view<vxl_byte>(top_left, ni,nj,np, i_step,j_step,p_step);
00809 }