contrib/mul/vil3d/vil3d_convert.h
Go to the documentation of this file.
00001 // This is mul/vil3d/vil3d_convert.h
00002 #ifndef vil3d_convert_h_
00003 #define vil3d_convert_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Some standard conversion functions.
00010 // \author Ian Scott.
00011 //
00012 // This file contains a large number of image to image conversion
00013 // functions.
00014 // They are in two basic function types (plus a few helper functions.)
00015 // Some involve only explicit types and convert
00016 // a vil3d_image_view<T> to a vil3d_image_view<T>,
00017 // the others take an unknown pixel type, using a
00018 // vil3d_image_view_base_sptr. The basic conversion
00019 // operations (e.g. casting, rounding) are available in both types.
00020 // All of the conversions attempt to find shortcuts, so the output
00021 // may be a reconfigured, or shallow copy of the input.
00022 //
00023 // \par vil3d_convert with explicit pixel types
00024 // These are useful when you have two vil3d_image_view objects you want
00025 // to convert between. You can use them in templates where the pixel
00026 // type is one of the template parameters. These functions
00027 // may create a shallow copy of the input if the types match too save
00028 // unnecessary work.
00029 // - vil3d_convert_cast
00030 // - vil3d_convert_round
00031 // - vil3d_convert_stretch_range
00032 //
00033 // \par vil3d_convert with unknown pixel types
00034 // These functions are useful when taking an image from vil3d_load
00035 // of vil3d_image_resource::get_view(), where you may not know the
00036 // pixel type in advance, but want to force the image into a
00037 // particular pixel type.
00038 // - vil3d_convert_cast
00039 // - vil3d_convert_round
00040 // - vil3d_convert_stretch_range
00041 // - vil3d_convert_to_n_planes
00042 // In general these functions expect to take scalar pixel images as
00043 // inputs. Even though many of these functions could return a known
00044 // pixel-typed image, they all return a vil3d_image_view_base_sptr,
00045 // so that the functions can be strung along
00046 //
00047 // Note that these vil3d_convert_..( vil3d_image_view_base_sptr ) functions
00048 // are provided as a convenience for users of vil3d_load and
00049 // vil3d_image_resource::get_view(). Their existence should not suggest
00050 // that it is sensible to use a vil3d_image_view_base_sptr as storage,
00051 // nor that it is a good idea to write a functions that
00052 // take or return a vil3d_image_view_base_sptr. If you need a
00053 // pixel-type-agnostic image container then use a vil3d_image_resource_sptr
00054 //
00055 // It may be a good idea to provide vil3d_image_resource_sptr based
00056 // vil3d_converts as well.
00057 
00058 #include <vcl_cassert.h>
00059 #include <vcl_limits.h>
00060 #include <vil/vil_convert.h>
00061 #include <vil3d/vil3d_transform.h>
00062 #include <vil3d/vil3d_math.h>
00063 #include <vil3d/vil3d_plane.h>
00064 #include <vil3d/vil3d_copy.h>
00065 
00066 
00067 //: Cast one pixel type to another.
00068 // There must be a cast operator from inP to outP
00069 //
00070 // If the two pixel types are the same, the destination may only be a shallow
00071 // copy of the source.
00072 // \relatesalso vil3d_image_view
00073 template <class inP, class outP>
00074 inline void vil3d_convert_cast(const vil3d_image_view<inP >&src,
00075                                vil3d_image_view<outP >&dest)
00076 {
00077   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
00078     dest = src;
00079   else
00080     vil3d_transform2(src, dest, vil_convert_cast_pixel<inP, outP>());
00081 }
00082 
00083 
00084 //: Convert one pixel type to another with rounding.
00085 // This should only be used to convert scalar pixel types to other scalar
00086 // pixel types, or RGBs to RGBs. This function only rounds in terms of the
00087 // destination type.
00088 //
00089 // If the two pixel types are the same, the destination may only be a
00090 // shallow copy of the source.
00091 // \relatesalso vil3d_image_view
00092 template <class inP, class outP>
00093 inline void vil3d_convert_round(const vil3d_image_view<inP >&src,
00094                                 vil3d_image_view<outP >&dest)
00095 {
00096   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
00097     dest = src;
00098   else
00099     vil3d_transform2(src, dest, vil_convert_round_pixel<inP, outP>());
00100 }
00101 
00102 
00103 //: Convert src to byte image dest by stretching to range [0,255]
00104 // \relatesalso vil3d_image_view
00105 template <class T>
00106 inline void vil3d_convert_stretch_range(const vil3d_image_view<T>& src,
00107                                         vil3d_image_view<vxl_byte>& dest)
00108 {
00109   T min_b,max_b;
00110   vil3d_math_value_range(src,min_b,max_b);
00111   double a = -1.0*double(min_b);
00112   double b = 0.0;
00113   if (max_b-min_b >0) b = 255.0/(max_b-min_b);
00114   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
00115   for (unsigned p = 0; p < src.nplanes(); ++p)
00116     for (unsigned k = 0; k < src.nk(); ++k)
00117       for (unsigned j = 0; j < src.nj(); ++j)
00118         for (unsigned i = 0; i < src.ni(); ++i)
00119            dest(i,j,k,p) = static_cast<vxl_byte>( b*( src(i,j,k,p)+ a ) );
00120 }
00121 
00122 
00123 // It doesn't seem sensible to write a general stretch
00124 // conversion function from any type to any type.
00125 // The individual pixel transfer function has to perform
00126 // multiplications which have to be done in double
00127 // to provide both the range and precision. You may as well
00128 // leave the image in double, and convert it again later.
00129 
00130 //: Convert src to double image dest by stretching to range [lo,hi]
00131 template <class inP>
00132 inline void vil3d_convert_stretch_range(const vil3d_image_view<inP>& src,
00133                                         vil3d_image_view<double>& dest,
00134                                         double lo, double hi)
00135 {
00136   inP min_b=0, max_b=0;
00137   vil3d_math_value_range(src,min_b,max_b);
00138   double b = 0.0;
00139   if (max_b-min_b >0)
00140     b = (hi-lo)/static_cast<double>(max_b-min_b);
00141   double a = -1.0*min_b*b + lo;
00142   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
00143   for (unsigned p = 0; p < src.nplanes(); ++p)
00144     for (unsigned k = 0; k < src.nk(); ++k)
00145       for (unsigned j = 0; j < src.nj(); ++j)
00146         for (unsigned i = 0; i < src.ni(); ++i)
00147           dest(i,j,k,p) =  b*src(i,j,k,p) + a;
00148 }
00149 
00150 
00151 //: Convert src image<inP> to dest image<double> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
00152 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
00153 template <class inP>
00154 inline void vil3d_convert_stretch_range_limited(const vil3d_image_view<inP>& src,
00155                                                 vil3d_image_view<double>& dest,
00156                                                 const inP src_lo,
00157                                                 const inP src_hi,
00158                                                 const double dest_lo,
00159                                                 const double dest_hi)
00160 {
00161   double ddest = dest_hi - dest_lo;
00162   double dsrc = static_cast<double>(src_hi - src_lo);
00163   double dds = ddest / dsrc;
00164 
00165   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
00166   for (unsigned p = 0; p < src.nplanes(); ++p)
00167     for (unsigned k = 0; k < src.nk(); ++k)
00168       for (unsigned j = 0; j < src.nj(); ++j)
00169         for (unsigned i = 0; i < src.ni(); ++i)
00170         {
00171           inP s = src(i,j,k,p);
00172           dest(i,j,k,p) = s<=src_lo ? dest_lo :
00173                           s>=src_hi ? dest_hi :
00174                                       dest_lo + dds*static_cast<double>(s-src_lo);
00175         }
00176 }
00177 
00178 
00179 //: Cast the unknown pixel type to the known one.
00180 //
00181 // This function is designed to be used with vil3d_load or
00182 // vil3d_image_resource::get_view()
00183 // where you do not know the pixel type in advance.
00184 // If you need a multi-component view, then call this to get the corresponding
00185 // multi-planar view, and do a second (cheap) conversion.
00186 // The input image's storage arrangement may not be preserved.
00187 template <class outP>
00188 inline vil3d_image_view_base_sptr vil3d_convert_cast(outP /*dummy*/,
00189                                                      const vil3d_image_view_base_sptr& src)
00190 {
00191   if (!src) return vil3d_image_view_base_sptr();
00192 
00193   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP>;
00194   vil3d_image_view<outP> & dest_ref = static_cast<vil3d_image_view<outP> &>(*dest);
00195 
00196   switch ( vil_pixel_format_component_format(src->pixel_format()) )
00197   {
00198 #define macro(F , T) \
00199    case F: \
00200     vil3d_convert_cast( vil3d_image_view<T >( src ), dest_ref );\
00201     break;
00202 
00203     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 )
00204     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 )
00205     macro( VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16 )
00206     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 )
00207     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte )
00208     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte )
00209     macro( VIL_PIXEL_FORMAT_FLOAT, float )
00210     macro( VIL_PIXEL_FORMAT_DOUBLE, double )
00211     macro( VIL_PIXEL_FORMAT_BOOL, bool )
00212 #undef macro
00213     default: dest=0;
00214   }
00215   return dest;
00216 }
00217 
00218 
00219 //: Convert an image of any pixel type to another with rounding.
00220 // This should only be used to convert to scalar
00221 // pixel types. This function only rounds in terms of the
00222 // destination type.
00223 // This function is designed to be used with vil3d_load or
00224 // vil3d_image_resource::get_view()
00225 // where you do not know the pixel type in advance.
00226 //
00227 // If the input image already has outP as its pixel type, the destination
00228 // may only be a shallow copy of the source.
00229 // outP should be a scalar pixel type.
00230 // The input image's storage arrangement may not be preserved.
00231 template <class outP>
00232 inline vil3d_image_view_base_sptr vil3d_convert_round(
00233   outP /*dummy*/, const vil3d_image_view_base_sptr &src)
00234 {
00235   assert(vil_pixel_format_num_components(vil_pixel_format_of(outP()))==1);
00236 
00237   if (!src) return vil3d_image_view_base_sptr();
00238 
00239   if (vil_pixel_format_component_format(src->pixel_format()) ==
00240       vil_pixel_format_of(outP()))
00241     return src;
00242 
00243   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP >;
00244   vil3d_image_view<outP > &dest_ref = static_cast<vil3d_image_view<outP >&>(*dest);
00245 
00246   switch (vil_pixel_format_component_format(src->pixel_format()))
00247   {
00248 #define macro( F , T ) \
00249    case F: { \
00250     vil3d_image_view<T > src1 = src; \
00251     vil3d_transform2(src1, dest_ref, vil_convert_round_pixel<T , outP>()); \
00252     break; }
00253 
00254     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
00255     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
00256     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
00257     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
00258     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
00259     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
00260     macro(VIL_PIXEL_FORMAT_FLOAT , float )
00261     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
00262 #undef macro
00263    default: dest=0;
00264   }
00265   return dest;
00266 }
00267 
00268 
00269 //: Create a greyscale image of specified pixel type from any image src.
00270 // This function is designed to be used with vil3d_load or
00271 // vil3d_image_resource::get_view()
00272 // where you do not know the pixel type in advance. e.g.
00273 // \verbatim
00274 // vil3d_image_view<float> input = vil3d_convert_cast(
00275 //   convert_to_grey_using_average(vil3d_load(filename)), float());
00276 // \endverbatim
00277 // The output may be a reconfigured view of the input.
00278 // The input image's pixel type and storage arrangement may not be preserved.
00279 inline vil3d_image_view_base_sptr vil3d_convert_to_grey_using_average(
00280   const vil3d_image_view_base_sptr &src)
00281 {
00282   if (!src) return vil3d_image_view_base_sptr();
00283 
00284   // convert via vil3d_image_view<double>
00285   switch (vil_pixel_format_component_format(src->pixel_format()))
00286   {
00287 #define macro( F , T ) \
00288    case F: { \
00289     /* try to do it quickly */ \
00290     if (src->nplanes() == 1 && \
00291         vil_pixel_format_component_format(src->pixel_format())==1) \
00292       return src; \
00293     /* create output view */ \
00294     vil3d_image_view<T > dest; \
00295     vil3d_image_view<T > src1 = *src; \
00296     vil3d_math_mean_over_planes(src1, dest, double()); \
00297     return vil3d_image_view_base_sptr(new vil3d_image_view<T >(dest)); }
00298 
00299     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
00300     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
00301     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
00302     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
00303     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
00304     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
00305     macro(VIL_PIXEL_FORMAT_FLOAT , float )
00306     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
00307 #undef macro
00308    default:
00309     return vil3d_image_view_base_sptr();
00310   }
00311 }
00312 
00313 
00314 //: Create an n plane image from any image src.
00315 // This function is designed to be used with vil3d_load or
00316 // vil3d_image_resource::get_view()
00317 // where you do not know the pixel type or number of planes in advance.
00318 // If the input images have too many planes, the higher planes will be
00319 // truncated. If the input image has too few planes, the new planes will be
00320 // copies of the first plane.
00321 //
00322 // The output may be a shallow copy of the input.
00323 // The input image's storage arrangement may not be preserved.
00324 // \endverbatim
00325 inline vil3d_image_view_base_sptr vil3d_convert_to_n_planes(
00326   unsigned n_planes, const vil3d_image_view_base_sptr &src)
00327 {
00328   if (!src || n_planes == 0)
00329     return vil3d_image_view_base_sptr();
00330 
00331 
00332   switch (vil_pixel_format_component_format(src->pixel_format()))
00333   {
00334  #define macro( F, T ) \
00335    case F: { \
00336     vil3d_image_view<T > src_ref = src; \
00337     if (!src_ref) return vil3d_image_view_base_sptr(); \
00338     /* try to do it quickly 1 */ \
00339     if (src_ref.nplanes() >= n_planes)  /* reduce number of planes */ \
00340       return vil3d_image_view_base_sptr( new vil3d_image_view<T >( \
00341         vil3d_planes(vil3d_image_view<T > (src),0,1,n_planes) )); \
00342     else { /* expand number of planes with copying */ \
00343       vil3d_image_view_base_sptr dest = new vil3d_image_view<T >( \
00344         src_ref.ni(), src_ref.nj(), src_ref.nk(), n_planes); \
00345       vil3d_image_view<T > & dest_ref = \
00346         static_cast<vil3d_image_view<T > &>(*dest); \
00347       vil3d_image_view<T > dest_slices = \
00348         vil3d_planes(dest_ref, 0, 1, src_ref.nplanes()); \
00349       vil3d_copy_reformat(src_ref, dest_slices); \
00350       vil3d_image_view<T > src_slice(vil3d_plane(src_ref, 0)); \
00351       for (unsigned i=src_ref.nplanes(); i<n_planes; ++i) { \
00352         dest_slices = vil3d_plane(dest_ref, i); \
00353         vil3d_copy_reformat(src_slice,  dest_slices); } \
00354       return dest;  } } \
00355 
00356     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
00357     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
00358     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
00359     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
00360     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
00361     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
00362     macro(VIL_PIXEL_FORMAT_FLOAT , float )
00363     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
00364 #undef macro
00365 
00366    default:
00367     return vil3d_image_view_base_sptr();
00368   }
00369 }
00370 
00371 
00372 //: Create an image of the desired type by stretching the range to fit.
00373 // This function is designed to be used with vil3d_load or
00374 // vil3d_image_resource::get_view()
00375 // where you do not know the pixel type in advance.
00376 // In the case of floating point output pixels the range is set to [0,1]
00377 // The input image's storage arrangement may not be preserved.
00378 //
00379 // This function works on scalar pixel types only. You can convert the image
00380 // to rgb using a cheap assignment afterwards.
00381 template <class outP>
00382 inline vil3d_image_view_base_sptr vil3d_convert_stretch_range(
00383   outP /*dummy*/, const vil3d_image_view_base_sptr &src)
00384 {
00385   // Check that input isn't trying to produce multi-component pixels
00386   assert (vil_pixel_format_num_components(vil_pixel_format_of(outP())) == 1);
00387 
00388   if (!src)
00389     return vil3d_image_view_base_sptr();
00390 
00391   double hi,lo;
00392 
00393   if (vcl_numeric_limits<outP>::is_integer)
00394   {
00395     hi = vcl_numeric_limits<outP>::max()+0.999;
00396     lo = vcl_numeric_limits<outP>::min();
00397   }
00398   else
00399   {
00400     hi=1.0;
00401     lo=0.0;
00402   }
00403 
00404   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP>;
00405   vil3d_image_view<outP> & dest_ref = static_cast<vil3d_image_view<outP> &>(*dest);
00406   vil3d_image_view<double> inter;
00407   switch (vil_pixel_format_component_format(src->pixel_format()))
00408   {
00409 #define macro( F , T ) \
00410    case F: { \
00411     vil3d_image_view<T> src_ref = src; \
00412     if (!src_ref) return vil3d_image_view_base_sptr(); \
00413     vil3d_convert_stretch_range(src_ref, inter, lo, hi); \
00414     vil3d_convert_cast(inter, dest_ref); \
00415     break; }
00416 
00417     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
00418     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
00419     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
00420     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
00421     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
00422     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
00423     macro(VIL_PIXEL_FORMAT_FLOAT , float )
00424     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
00425 #undef macro
00426    default:
00427     dest_ref.clear();
00428   }
00429   return dest;
00430 }
00431 
00432 
00433 #endif // vil3d_convert_h_