core/vil/vil_image_view.txx
Go to the documentation of this file.
00001 // This is core/vil/vil_image_view.txx
00002 #ifndef vil_image_view_txx_
00003 #define vil_image_view_txx_
00004 //:
00005 // \file
00006 // \brief Represent images of one or more planes of Ts.
00007 // \author Ian Scott
00008 //
00009 // Note: To keep down size of vil_image_view
00010 // Please think carefully before adding any new methods.
00011 // In particular any methods that provide new views (e.g. vil_plane)
00012 // will be more usefully provided as external functions. - IMS.
00013 // In that case, use the "relates" keyword of Doxygen to link the documentation
00014 // of that function to the vil_image_view class.
00015 //
00016 // \verbatim
00017 //  Modifications
00018 //   23 Oct.2003 - Peter Vanroose - Added support for 64-bit int pixels
00019 // \endverbatim
00020 
00021 #include "vil_image_view.h"
00022 #include <vcl_string.h>
00023 #include <vcl_cassert.h>
00024 #include <vcl_cstdlib.h>
00025 #include <vcl_cmath.h>
00026 #include <vcl_ostream.h>
00027 #include <vil/vil_pixel_format.h>
00028 #include <vil/vil_exception.h>
00029 #include <vcl_cstring.h>
00030 #include <vcl_algorithm.h>
00031 
00032 //=======================================================================
00033 
00034 
00035 template<class T>
00036 vil_image_view<T>::vil_image_view(unsigned n_i, unsigned n_j, unsigned n_planes,
00037                                   unsigned n_interleaved_planes)
00038 : top_left_(0), istep_(n_interleaved_planes)
00039 {
00040   assert(n_planes==1 || n_interleaved_planes==1);
00041   assert(vil_pixel_format_of(T()) == VIL_PIXEL_FORMAT_UNKNOWN ||
00042          n_planes * n_interleaved_planes == 1 ||
00043          vil_pixel_format_num_components(vil_pixel_format_of(T())) == 1);
00044   set_size(n_i,n_j,n_planes*n_interleaved_planes);
00045 }
00046 
00047 //: Set this view to look at someone else's memory data.
00048 template<class T>
00049 vil_image_view<T>::vil_image_view(const T* top_left, unsigned n_i, unsigned n_j, unsigned n_planes,
00050                                   vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step, vcl_ptrdiff_t plane_step)
00051 {
00052   set_to_memory(top_left,n_i,n_j,n_planes,i_step,j_step,plane_step);
00053 }
00054 
00055 //: Set this view to look at another view's data
00056 //  Need to pass the memory chunk to set up the internal smart ptr appropriately
00057 template<class T>
00058 vil_image_view<T>::vil_image_view(vil_memory_chunk_sptr const& mem_chunk,
00059                                   const T* top_left, unsigned n_i, unsigned n_j, unsigned n_planes,
00060                                   vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step, vcl_ptrdiff_t plane_step)
00061  : vil_image_view_base(n_i, n_j, n_planes)
00062  , top_left_(const_cast<T*>(top_left))
00063  , istep_(i_step), jstep_(j_step)
00064  , planestep_(plane_step)
00065  , ptr_(mem_chunk)
00066 {
00067 #ifndef NDEBUG
00068   // check view and chunk are in rough agreement
00069   if (mem_chunk) // if we are doing a view transform on a non-owned image, then mem_chunk will be 0.
00070   {
00071     if ( mem_chunk->size() < n_planes*n_i*n_j*sizeof(T) )
00072       vcl_cerr << "mem_chunk->size()=" << mem_chunk->size() << '\n'
00073                << "nplanes=" << n_planes << '\n'
00074                << "n_i=" << n_i << '\n'
00075                << "n_j=" << n_j << '\n'
00076                << "sizeof(T)=" << sizeof(T) << '\n'
00077                << "n_planes*n_i*n_j*sizeof(T)=" << n_planes*n_i*n_j*sizeof(T) << '\n';
00078     assert(mem_chunk->size() >= n_planes*n_i*n_j*sizeof(T));
00079     if (top_left  < reinterpret_cast<const T*>(mem_chunk->data()) ||
00080         top_left >= reinterpret_cast<const T*>(reinterpret_cast<const char*>(mem_chunk->data()) + mem_chunk->size()))
00081       vcl_cerr << "top_left at " << static_cast<const void*>(top_left) << ", memory_chunk at "
00082                << reinterpret_cast<const void*>(mem_chunk->data()) << ", size " << mem_chunk->size()
00083                << ", size of data type " << sizeof(T) << '\n';
00084     assert(top_left >= reinterpret_cast<const T*>(mem_chunk->data()) &&
00085            (mem_chunk->size()==0 || top_left  < reinterpret_cast<const T*>(reinterpret_cast<const char*>(mem_chunk->data()) + mem_chunk->size())) );
00086   }
00087 #endif
00088 }
00089 
00090 //: Copy constructor
00091 // If this view cannot set itself to view the other data (e.g. because the
00092 // types are incompatible) it will set itself to empty.
00093 template<class T>
00094 vil_image_view<T>::vil_image_view(const vil_image_view<T>& that)
00095 : vil_image_view_base(that.ni(),that.nj(),that.nplanes()),
00096   top_left_(0), istep_(0), jstep_(0), planestep_(0), ptr_(0)
00097 {
00098   operator=( static_cast<vil_image_view_base const&>(that) );
00099 }
00100 
00101 //: Sort of copy constructor
00102 // If this view cannot set itself to view the other data (e.g. because the
00103 // types are incompatible) it will set itself to empty.
00104 template<class T>
00105 vil_image_view<T>::vil_image_view(const vil_image_view_base& that):
00106 top_left_(0), istep_(0), jstep_(0), planestep_(0), ptr_(0)
00107 {
00108   operator=(that);
00109 }
00110 
00111 //: Sort of copy constructor
00112 // If this view cannot set itself to view the other data (e.g. because the
00113 // types are incompatible) it will set itself to empty.
00114 template <class T>
00115 vil_image_view<T>::vil_image_view(const vil_image_view_base_sptr& that):
00116 top_left_(0), istep_(0), jstep_(0), planestep_(0), ptr_(0)
00117 {
00118   operator=(that);
00119 }
00120 
00121 //: Perform deep copy of the src image, placing in this image
00122 template<class T>
00123 void vil_image_view<T>::deep_copy(const vil_image_view<T>& src)
00124 {
00125   set_size(src.ni(),src.nj(),src.nplanes());
00126 
00127   if (src.is_contiguous() && this->is_contiguous())
00128   {
00129     istep_=src.istep_; jstep_= src.jstep_; planestep_ = src.planestep_;
00130     if (src.istep()>0 && src.jstep()>0 && src.planestep()>=0)
00131     {
00132       vcl_memcpy(top_left_,src.top_left_ptr(),src.size()*sizeof(T));
00133       return;
00134     }
00135     const_iterator s_it = src.begin();
00136     iterator d_it = begin();
00137     const_iterator end_it = src.end();
00138     while (s_it!=end_it) {*d_it = *s_it; ++s_it; ++d_it; }
00139     return;
00140   }
00141 
00142   const vcl_ptrdiff_t s_planestep = src.planestep();
00143   const vcl_ptrdiff_t s_istep = src.istep();
00144   const vcl_ptrdiff_t s_jstep = src.jstep();
00145 
00146   // Do a deep copy
00147   // This is potentially inefficient
00148   const T* src_data = src.top_left_ptr();
00149   T* data = top_left_;
00150   for (unsigned int p=0;p<nplanes_;++p,src_data += s_planestep,data += planestep_)
00151   {
00152     T* row = data;
00153     const T* src_row = src_data;
00154     for (unsigned int j=0;j<nj_;++j,row += jstep_,src_row += s_jstep)
00155     {
00156       T* p = row;
00157       const T* sp = src_row;
00158       for (unsigned int i=0;i<ni_;++i,p+=istep_,sp+=s_istep) *p = *sp;
00159     }
00160   }
00161 }
00162 
00163 // Notes on convert_components_from_planes() and convert_planes_from_components()
00164 // These are used by the operator= to provide the appropriate smart conversion
00165 // behaviour for the various types.
00166 // I don't think that C++ templates support full pattern matching,
00167 // so we have to provide one template instantiation to cover the general
00168 // compound pixel case (the range of which is possibly infinite)
00169 // We then specialise for all the scalar pixel cases (there are only so
00170 // many scalar types).
00171 // I guess someone could merge all the scalar specialisations using
00172 // macros and substantially reduce the length of this code.
00173 
00174 
00175 //: Convert planes to components from planes, or do nothing if types are wrong.
00176 template <class T>
00177 inline bool convert_components_from_planes(vil_image_view<T> &lhs,
00178                                            const vil_image_view_base &rhs_base)
00179 {
00180   typedef typename T::value_type comp_type;
00181 
00182   const int ncomp =
00183     vil_pixel_format_num_components(vil_pixel_format_of(T()));
00184 
00185   vil_pixel_format fmt = vil_pixel_format_of(T());
00186   if (// both sides have equal component types and rhs has scalar pixels and
00187       rhs_base.pixel_format() == vil_pixel_format_component_format(fmt) &&
00188       // lhs has number of components equal to rhs's number of planes.
00189       ncomp == (int)rhs_base.nplanes() )
00190   {
00191     const vil_image_view<comp_type> &rhs = static_cast<const vil_image_view<comp_type>&>(rhs_base);
00192     // Check that the steps are suitable for viewing as components
00193     if (rhs.planestep() != 1 || vcl_abs((int)rhs.istep())<ncomp || vcl_abs((int)rhs.jstep())<ncomp ) return false;
00194     lhs = vil_image_view<T >(rhs.memory_chunk(),
00195                              reinterpret_cast<T const*>(rhs.top_left_ptr()),
00196                              rhs.ni(),rhs.nj(),1,
00197                              rhs.istep()/ncomp,rhs.jstep()/ncomp,1);
00198     return true;
00199   }
00200   else
00201     return false;
00202 }
00203 
00204 
00205 VCL_DEFINE_SPECIALIZATION
00206 inline bool convert_components_from_planes(vil_image_view<float> & /*lhs*/,
00207                                            const vil_image_view_base & /*rhs_base*/)
00208 {return false;}  // when lhs has scalar pixels, don't attempt conversion
00209 
00210 VCL_DEFINE_SPECIALIZATION
00211 inline bool convert_components_from_planes(vil_image_view<double> & /*lhs*/,
00212                                            const vil_image_view_base & /*rhs_base*/)
00213 {return false;}
00214 
00215 VCL_DEFINE_SPECIALIZATION
00216 inline bool convert_components_from_planes(vil_image_view<bool> & /*lhs*/,
00217                                            const vil_image_view_base & /*rhs_base*/)
00218 {return false;}
00219 
00220 VCL_DEFINE_SPECIALIZATION
00221 inline bool convert_components_from_planes(vil_image_view<vxl_sbyte> & /*lhs*/,
00222                                            const vil_image_view_base & /*rhs_base*/)
00223 {return false;}
00224 
00225 VCL_DEFINE_SPECIALIZATION
00226 inline bool convert_components_from_planes(vil_image_view<vxl_byte> & /*lhs*/,
00227                                            const vil_image_view_base & /*rhs_base*/)
00228 {return false;}
00229 
00230 VCL_DEFINE_SPECIALIZATION
00231 inline bool convert_components_from_planes(vil_image_view<vxl_int_16> & /*lhs*/,
00232                                            const vil_image_view_base & /*rhs_base*/)
00233 {return false;}
00234 
00235 VCL_DEFINE_SPECIALIZATION
00236 inline bool convert_components_from_planes(vil_image_view<vxl_uint_16> & /*lhs*/,
00237                                            const vil_image_view_base & /*rhs_base*/)
00238 {return false;}
00239 
00240 VCL_DEFINE_SPECIALIZATION
00241 inline bool convert_components_from_planes(vil_image_view<vxl_int_32> & /*lhs*/,
00242                                            const vil_image_view_base & /*rhs_base*/)
00243 {return false;}
00244 
00245 VCL_DEFINE_SPECIALIZATION
00246 inline bool convert_components_from_planes(vil_image_view<vxl_uint_32> & /*lhs*/,
00247                                            const vil_image_view_base & /*rhs_base*/)
00248 {return false;}
00249 
00250 #if VXL_HAS_INT_64
00251 
00252 VCL_DEFINE_SPECIALIZATION
00253 inline bool convert_components_from_planes(vil_image_view<vxl_int_64> & /*lhs*/,
00254                                            const vil_image_view_base & /*rhs_base*/)
00255 {return false;}
00256 
00257 VCL_DEFINE_SPECIALIZATION
00258 inline bool convert_components_from_planes(vil_image_view<vxl_uint_64> & /*lhs*/,
00259                                            const vil_image_view_base & /*rhs_base*/)
00260 {return false;}
00261 
00262 #endif
00263 
00264 //: Convert components to planes from planes, or do nothing if types are wrong.
00265 template <class T>
00266 inline bool convert_planes_from_components(vil_image_view<T> & /*lhs*/,
00267                                            const vil_image_view_base & /*rhs*/)
00268 { return false;} // when lhs has non-scalar pixels, don't attempt conversion
00269 // except for the following typical cases
00270 VCL_DEFINE_SPECIALIZATION
00271 inline bool convert_planes_from_components(vil_image_view<vil_rgb<vxl_byte> > & lhs,
00272                                            const vil_image_view_base & rhs)
00273 {
00274   if (rhs.nplanes() != 3)
00275     return false;
00276   if (rhs.pixel_format()!=VIL_PIXEL_FORMAT_BYTE)
00277     return false;
00278   unsigned ni = rhs.ni(), nj = rhs.nj();
00279   const vil_image_view<vxl_byte> &rhsv = static_cast<const vil_image_view<vxl_byte>&>(rhs);
00280   lhs= *(new vil_image_view<vil_rgb<vxl_byte> >(ni, nj));
00281   for (unsigned j = 0; j<nj; ++j)
00282     for (unsigned i = 0; i<ni; ++i){
00283       lhs(i,j).r = rhsv(i,j,0); lhs(i, j).g = rhsv(i,j,1); lhs(i, j).b = rhsv(i,j,2);
00284     }
00285   return true;
00286 }
00287 
00288 VCL_DEFINE_SPECIALIZATION
00289 inline bool convert_planes_from_components(vil_image_view<vil_rgba<vxl_uint_16> > & lhs,
00290                                            const vil_image_view_base & rhs)
00291 {
00292   if (rhs.nplanes() != 4)
00293     return false;
00294   if (rhs.pixel_format()!=VIL_PIXEL_FORMAT_UINT_16)
00295     return false;
00296   unsigned ni = rhs.ni(), nj = rhs.nj();
00297   const vil_image_view<vxl_uint_16> &rhsv = static_cast<const vil_image_view<vxl_uint_16>&>(rhs);
00298   lhs = *(new vil_image_view<vil_rgba<vxl_uint_16> >(ni, nj));
00299   for (unsigned j = 0; j<nj; ++j)
00300     for (unsigned i = 0; i<ni; ++i){
00301       lhs(i, j).r = rhsv(i,j,0); lhs(i, j).g = rhsv(i,j,1); lhs(i, j).b = rhsv(i,j,2);
00302       lhs(i, j).a = rhsv(i,j,3);
00303     }
00304  return true;
00305 }
00306 
00307 VCL_DEFINE_SPECIALIZATION
00308 inline bool convert_planes_from_components(vil_image_view<vxl_byte> &lhs,
00309                                            const vil_image_view_base &rhs_base)
00310 {
00311   const unsigned ncomp =
00312     vil_pixel_format_num_components(rhs_base.pixel_format());
00313 
00314   if (// rhs has just 1 plane
00315       rhs_base.nplanes() == 1 &&
00316       // both sides have equal component types
00317       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_BYTE)
00318   {
00319     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00320     const vil_image_view<vxl_byte> &rhs = static_cast<const vil_image_view<vxl_byte>&>(rhs_base);
00321 
00322     lhs = vil_image_view<vxl_byte>(rhs.memory_chunk(), rhs.top_left_ptr(),
00323                                    rhs.ni(),rhs.nj(),ncomp,
00324                                    rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00325     return true;
00326   }
00327   else
00328     return false;
00329 }
00330 
00331 VCL_DEFINE_SPECIALIZATION
00332 inline bool convert_planes_from_components(vil_image_view<vxl_sbyte> &lhs,
00333                                            const vil_image_view_base &rhs_base)
00334 {
00335   const unsigned ncomp =
00336     vil_pixel_format_num_components(rhs_base.pixel_format());
00337 
00338   if (// rhs has just 1 plane
00339       rhs_base.nplanes() == 1 &&
00340       // both sides have equal component types
00341       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_SBYTE)
00342   {
00343     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00344     const vil_image_view<vxl_sbyte> &rhs = static_cast<const vil_image_view<vxl_sbyte>&>(rhs_base);
00345 
00346     lhs = vil_image_view<vxl_sbyte>(rhs.memory_chunk(), rhs.top_left_ptr(),
00347                                     rhs.ni(),rhs.nj(),ncomp,
00348                                     rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00349     return true;
00350   }
00351   else
00352     return false;
00353 }
00354 
00355 VCL_DEFINE_SPECIALIZATION
00356 inline bool convert_planes_from_components(vil_image_view<vxl_uint_16> &lhs,
00357                                            const vil_image_view_base &rhs_base)
00358 {
00359   const unsigned ncomp =
00360     vil_pixel_format_num_components(rhs_base.pixel_format());
00361 
00362   if (// rhs has just 1 plane
00363       rhs_base.nplanes() == 1 &&
00364       // both sides have equal component types
00365       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_UINT_16)
00366   {
00367     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00368     const vil_image_view<vxl_uint_16> &rhs = static_cast<const vil_image_view<vxl_uint_16>&>(rhs_base);
00369 
00370     lhs = vil_image_view<vxl_uint_16>(rhs.memory_chunk(), rhs.top_left_ptr(),
00371                                       rhs.ni(),rhs.nj(),ncomp,
00372                                       rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00373     return true;
00374   }
00375   else
00376     return false;
00377 }
00378 
00379 VCL_DEFINE_SPECIALIZATION
00380 inline bool convert_planes_from_components(vil_image_view<vxl_int_16> &lhs,
00381                                            const vil_image_view_base &rhs_base)
00382 {
00383   const unsigned ncomp =
00384     vil_pixel_format_num_components(rhs_base.pixel_format());
00385 
00386   if (// rhs has just 1 plane
00387       rhs_base.nplanes() == 1 &&
00388       // both sides have equal component types
00389       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_INT_16)
00390   {
00391     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00392     const vil_image_view<vxl_int_16> &rhs = static_cast<const vil_image_view<vxl_int_16>&>(rhs_base);
00393 
00394     lhs = vil_image_view<vxl_int_16>(rhs.memory_chunk(), rhs.top_left_ptr(),
00395                                      rhs.ni(),rhs.nj(),ncomp,
00396                                      rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00397     return true;
00398   }
00399   else
00400     return false;
00401 }
00402 
00403 VCL_DEFINE_SPECIALIZATION
00404 inline bool convert_planes_from_components(vil_image_view<vxl_uint_32> &lhs,
00405                                            const vil_image_view_base &rhs_base)
00406 {
00407   const unsigned ncomp =
00408     vil_pixel_format_num_components(rhs_base.pixel_format());
00409 
00410   if (// rhs has just 1 plane
00411       rhs_base.nplanes() == 1 &&
00412       // both sides have equal component types
00413        vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_UINT_32)
00414   {
00415     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00416     const vil_image_view<vxl_uint_32> &rhs = static_cast<const vil_image_view<vxl_uint_32>&>(rhs_base);
00417 
00418     lhs = vil_image_view<vxl_uint_32>(rhs.memory_chunk(), rhs.top_left_ptr(),
00419                                       rhs.ni(),rhs.nj(),ncomp,
00420                                       rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00421     return true;
00422   }
00423   else
00424     return false;
00425 }
00426 
00427 VCL_DEFINE_SPECIALIZATION
00428 inline bool convert_planes_from_components(vil_image_view<vxl_int_32> &lhs,
00429                                            const vil_image_view_base &rhs_base)
00430 {
00431   const unsigned ncomp =
00432     vil_pixel_format_num_components(rhs_base.pixel_format());
00433 
00434   if (// rhs has just 1 plane
00435       rhs_base.nplanes() == 1 &&
00436       // both sides have equal component types
00437       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_INT_32)
00438   {
00439     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00440     const vil_image_view<vxl_int_32> &rhs = static_cast<const vil_image_view<vxl_int_32>&>(rhs_base);
00441 
00442     lhs = vil_image_view<vxl_int_32>(rhs.memory_chunk(), rhs.top_left_ptr(),
00443                                      rhs.ni(),rhs.nj(),ncomp,
00444                                      rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00445     return true;
00446   }
00447   else
00448     return false;
00449 }
00450 
00451 #if VXL_HAS_INT_64
00452 
00453 VCL_DEFINE_SPECIALIZATION
00454 inline bool convert_planes_from_components(vil_image_view<vxl_uint_64> &lhs,
00455                                            const vil_image_view_base &rhs_base)
00456 {
00457   const unsigned ncomp =
00458     vil_pixel_format_num_components(rhs_base.pixel_format());
00459 
00460   if (// rhs has just 1 plane
00461       rhs_base.nplanes() == 1 &&
00462       // both sides have equal component types
00463        vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_UINT_64)
00464   {
00465     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00466     const vil_image_view<vxl_uint_64> &rhs = static_cast<const vil_image_view<vxl_uint_64>&>(rhs_base);
00467 
00468     lhs = vil_image_view<vxl_uint_64>(rhs.memory_chunk(), rhs.top_left_ptr(),
00469                                       rhs.ni(),rhs.nj(),ncomp,
00470                                       rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00471     return true;
00472   }
00473   else
00474     return false;
00475 }
00476 
00477 VCL_DEFINE_SPECIALIZATION
00478 inline bool convert_planes_from_components(vil_image_view<vxl_int_64> &lhs,
00479                                            const vil_image_view_base &rhs_base)
00480 {
00481   const unsigned ncomp =
00482     vil_pixel_format_num_components(rhs_base.pixel_format());
00483 
00484   if (// rhs has just 1 plane
00485       rhs_base.nplanes() == 1 &&
00486       // both sides have equal component types
00487       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_INT_64)
00488   {
00489     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00490     const vil_image_view<vxl_int_64> &rhs = static_cast<const vil_image_view<vxl_int_64>&>(rhs_base);
00491 
00492     lhs = vil_image_view<vxl_int_64>(rhs.memory_chunk(), rhs.top_left_ptr(),
00493                                      rhs.ni(),rhs.nj(),ncomp,
00494                                      rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00495     return true;
00496   }
00497   else
00498     return false;
00499 }
00500 
00501 #endif // VXL_HAS_INT_64
00502 
00503 VCL_DEFINE_SPECIALIZATION
00504 inline bool convert_planes_from_components(vil_image_view<float> &lhs,
00505                                            const vil_image_view_base &rhs_base)
00506 {
00507   const unsigned ncomp =
00508     vil_pixel_format_num_components(rhs_base.pixel_format());
00509 
00510   if (// rhs has just 1 plane
00511       rhs_base.nplanes() == 1 &&
00512       // both sides have equal component types
00513       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_FLOAT)
00514   {
00515     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00516     const vil_image_view<float> &rhs = static_cast<const vil_image_view<float>&>(rhs_base);
00517 
00518     lhs = vil_image_view<float>(rhs.memory_chunk(), rhs.top_left_ptr(),
00519                                 rhs.ni(),rhs.nj(),ncomp,
00520                                 rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00521     return true;
00522   }
00523   else
00524     return false;
00525 }
00526 
00527 VCL_DEFINE_SPECIALIZATION
00528 inline bool convert_planes_from_components(vil_image_view<double> &lhs,
00529                                            const vil_image_view_base &rhs_base)
00530 {
00531   const unsigned ncomp =
00532     vil_pixel_format_num_components(rhs_base.pixel_format());
00533 
00534   if (// rhs has just 1 plane
00535       rhs_base.nplanes() == 1 &&
00536       // both sides have equal component types
00537       vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_DOUBLE)
00538   {
00539     // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
00540     const vil_image_view<double> &rhs = static_cast<const vil_image_view<double>&>(rhs_base);
00541 
00542     lhs = vil_image_view<double>(rhs.memory_chunk(), rhs.top_left_ptr(),
00543                                  rhs.ni(),rhs.nj(),ncomp,
00544                                  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
00545     return true;
00546   }
00547   else
00548     return false;
00549 }
00550 
00551 
00552 template<class T>
00553 const vil_image_view<T> & vil_image_view<T>::operator= (const vil_image_view<T> & rhs)
00554 {
00555   return operator=( static_cast<vil_image_view_base const&>(rhs) );
00556 }
00557 
00558 
00559 template<class T>
00560 const vil_image_view<T> & vil_image_view<T>::operator= (const vil_image_view_base & rhs)
00561 {
00562   if (static_cast<const vil_image_view_base*>(this) == &rhs)
00563     return *this;
00564 
00565   if (rhs.pixel_format() == pixel_format())
00566   {
00567     const vil_image_view<T> &that = static_cast<const vil_image_view<T>&>(rhs);
00568     ni_=that.ni_;
00569     nj_=that.nj_;
00570     nplanes_=that.nplanes_;
00571     istep_=that.istep_;
00572     jstep_=that.jstep_;
00573     planestep_=that.planestep_;
00574     top_left_=that.top_left_;
00575     ptr_=that.ptr_;
00576     return *this;
00577   }
00578 
00579   if (convert_components_from_planes(*this, rhs))
00580     return *this;
00581 
00582   if (convert_planes_from_components(*this, rhs))
00583     return *this;
00584 
00585   vil_exception_warning(vil_exception_pixel_formats_incompatible(
00586     rhs.pixel_format(), this->pixel_format(), "vil_image_view::operator =") );
00587   set_to_memory(0, 0, 0, 0, 0, 0, 0);
00588   return *this;
00589 }
00590 
00591 
00592 //=======================================================================
00593 
00594 
00595 template<class T>
00596 void vil_image_view<T>::set_size(unsigned n_i, unsigned n_j)
00597 {
00598   if ( nplanes_ > 0 )
00599     set_size(n_i, n_j, nplanes_);
00600   else
00601     set_size(n_i, n_j, 1);
00602 }
00603 
00604 //: True if data all in one unbroken block and top_left_ptr() is lowest data address
00605 template<class T>
00606 bool vil_image_view<T>::is_contiguous() const
00607 {
00608   // For a contiguous image, the smallest step size should be 1, the
00609   // next step size should be the width of corresponding to the
00610   // smallest step size, and so on. So, sort the step sizes and check
00611   // if this is the case.
00612 
00613   // Sort the step sizes in ascending order, and keep the
00614   // corresponding widths.
00615 
00616   vcl_ptrdiff_t s1, s2, s3;
00617   unsigned n1, n2;
00618   if ( istep_ < jstep_ )
00619     if ( jstep_ < planestep_ )
00620     {
00621       s1 = istep_; s2 = jstep_; s3 = planestep_;
00622       n1 = ni_;    n2 = nj_;  //  n3 = nplanes_;
00623     }
00624     else // planestep_ < jstep_
00625       if ( istep_ < planestep_ )
00626       {
00627         s1 = istep_; s2 = planestep_; s3 = jstep_;
00628         n1 = ni_;    n2 = nplanes_; //  n3 = nj_;
00629       }
00630       else // planestep_ < istep_
00631       {
00632         s1 = planestep_; s2 = istep_; s3 = jstep_;
00633         n1 = nplanes_;   n2 = ni_;  //  n3 = nj_;
00634       }
00635   else // jstep < istep_
00636     if ( jstep_ < planestep_ )
00637       if ( istep_ < planestep_ )
00638       {
00639         s1 = jstep_; s2 = istep_; s3 = planestep_;
00640         n1 = nj_;    n2 = ni_;  //  n3 = nplanes_;
00641       }
00642       else // planestep_ < istep_
00643       {
00644         s1 = jstep_; s2 = planestep_; s3 = istep_;
00645         n1 = nj_;    n2 = nplanes_;  // n3 = ni_;
00646       }
00647     else // planestep_ < jstep_
00648     {
00649       s1 = planestep_; s2 = jstep_; s3 = istep_;
00650       n1 = nplanes_;   n2 = nj_;  //  n3 = ni_;
00651     }
00652 
00653   return s1 == 1 &&
00654          s2 > 0 && unsigned(s2) == n1 &&
00655          s3 > 0 && unsigned(s3) == n1*n2;
00656 }
00657 
00658 //=======================================================================
00659 
00660 template<class T>
00661 void vil_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_planes)
00662 {
00663   if (n_i==ni_ && n_j==nj_ && n_planes==nplanes_) return;
00664 
00665   release_memory();
00666 
00667   vil_pixel_format fmt = vil_pixel_format_of(T());
00668   ptr_ = new vil_memory_chunk(sizeof(T)*n_planes*n_j*n_i,
00669                               vil_pixel_format_component_format(fmt));
00670 
00671   ni_ = n_i;
00672   nj_ = n_j;
00673   nplanes_ = n_planes;
00674   // When the image view was in interleaved mode before entering this function,
00675   // check whether the new number of planes is the same as the istep_.
00676   // If the two agree, remain in the interleaved mode, which is desired by the constructor.
00677   // Otherwise, make istep_=1 and thus no longer interleaved.
00678   if (istep_==0 || int(istep_) != int(n_planes)) istep_ = 1;
00679   jstep_ = n_i*istep_;
00680   planestep_ = istep_==1 ? n_i*n_j : 1;
00681 
00682   top_left_ = reinterpret_cast<T*>(ptr_->data());
00683   assert( (istep_==1 && (int)planestep_==int(n_i*n_j)) || (planestep_==1 && (int)istep_==(int)n_planes) );
00684 }
00685 
00686 
00687 //: Set this view to look at someone else's memory.
00688 template<class T>
00689 void vil_image_view<T>::set_to_memory(const T* top_left,
00690                                       unsigned n_i, unsigned n_j, unsigned n_planes,
00691                                       vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step, vcl_ptrdiff_t plane_step)
00692 {
00693   release_memory();
00694   top_left_ = const_cast<T*>(top_left);  // Remove const, as view may end up manipulating data
00695 
00696   ni_ = n_i;
00697   nj_ = n_j;
00698   nplanes_ = n_planes;
00699   istep_ = i_step;
00700   jstep_ = j_step;
00701   planestep_ = plane_step;
00702 }
00703 
00704 
00705 //=======================================================================
00706 //: Fill view with given value
00707 template<class T>
00708 void vil_image_view<T>::fill(T value)
00709 {
00710   T* plane = top_left_;
00711 
00712   if (is_contiguous())
00713   {
00714     vcl_fill(begin(), end(), value);
00715     return;
00716   }
00717 
00718   if (istep_==1)
00719   {
00720     for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
00721     {
00722       T* row = plane;
00723       for (unsigned int j=0;j<nj_;++j,row += jstep_)
00724       {
00725         int i = ni_;
00726         while (i!=0) { row[--i]=value; }
00727       }
00728     }
00729     return;
00730   }
00731 
00732   if (jstep_==1)
00733   {
00734     for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
00735     {
00736       T* col = plane;
00737       for (unsigned int i=0;i<ni_;++i,col += istep_)
00738       {
00739         int j = nj_;
00740         while (j!=0) { col[--j]=value; }
00741       }
00742     }
00743     return;
00744   }
00745 
00746   for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
00747   {
00748     T* row = plane;
00749     for (unsigned int j=0;j<nj_;++j,row += jstep_)
00750     {
00751       T* p = row;
00752       for (unsigned int i=0;i<ni_;++i,p+=istep_) *p = value;
00753     }
00754   }
00755 }
00756 
00757 //=======================================================================
00758 
00759 template<class T>
00760 bool vil_image_view<T>::is_class(vcl_string const& s) const
00761 {
00762   return s==vil_image_view<T>::is_a() || vil_image_view_base::is_class(s);
00763 }
00764 
00765 //=======================================================================
00766 
00767 template<class T>
00768 void vil_image_view<T>::print(vcl_ostream& os) const
00769 {
00770   os<<nplanes_<<" planes, each "<<ni_<<" x "<<nj_;
00771 }
00772 
00773 //=======================================================================
00774 //: True if they share same view of same image data.
00775 //  This does not do a deep equality on image data. If the images point
00776 //  to different image data objects that contain identical images, then
00777 //  the result will still be false.
00778 template<class T>
00779 bool vil_image_view<T>::operator==(const vil_image_view_base &rhs) const
00780 {
00781   if (rhs.pixel_format() != pixel_format()) return false;
00782 
00783   const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
00784 
00785   if (this == &other) return true;
00786 
00787   if (!(bool) *this && !(bool)other) return true;
00788   return ptr_  == other.ptr_ &&
00789     top_left_  == other.top_left_ &&
00790     nplanes_   == other.nplanes_ &&
00791     ni_        == other.ni_ &&
00792     nj_        == other.nj_ &&
00793     (nplanes_ <= 1 || planestep_ == other.planestep_) &&
00794     istep_     == other.istep_ &&
00795     jstep_     == other.jstep_;
00796 }
00797 
00798 //=======================================================================
00799 //: Provides an ordering.
00800 //  Useful for ordered containers.
00801 //  There is no guaranteed meaning to the less than operator, except that
00802 //  (a<b && b<a)  is false and  !(a<b) && !(b<a)  is equivalent to  a==b
00803 template<class T>
00804 bool vil_image_view<T>::operator<(const vil_image_view_base& rhs) const
00805 {
00806   if (rhs.pixel_format() != pixel_format()) return pixel_format() < rhs.pixel_format();
00807 
00808   const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
00809   if (ptr_ != other.ptr_) return ptr_<other.ptr_;
00810   if (!(bool) *this && !(bool)other) return false;
00811   if (nplanes_ != other.nplanes_) return nplanes_ < other.nplanes_;
00812   if (ni_ != other.ni_) return ni_ < other.ni_;
00813   if (nj_ != other.nj_) return nj_ < other.nj_;
00814   if (planestep_ != other.planestep_) return planestep_ < other.planestep_;
00815   if (istep_ != other.istep_) return istep_ < other.istep_;
00816   return jstep_ < other.jstep_;
00817 }
00818 
00819 
00820 //=======================================================================
00821 //: Provides an ordering.
00822 //  Useful for ordered containers.
00823 //  There is no guaranteed meaning to the less than operator, except that
00824 //  (a>b) is equivalent to (b<a)
00825 template<class T>
00826 bool vil_image_view<T>::operator>(const vil_image_view_base& rhs) const
00827 {
00828   if (rhs.pixel_format() != pixel_format()) return pixel_format() > rhs.pixel_format();
00829 
00830   const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
00831 
00832   if (this == &other) return false;
00833 
00834   if (ptr_ != other.ptr_) return ptr_>other.ptr_;
00835   if (!(bool) *this && !(bool)other) return false;
00836   if (nplanes_ != other.nplanes_) return nplanes_ > other.nplanes_;
00837   if (ni_ != other.ni_) return ni_ > other.ni_;
00838   if (nj_ != other.nj_) return nj_ > other.nj_;
00839   if (planestep_ != other.planestep_) return planestep_ > other.planestep_;
00840   if (istep_ != other.istep_) return istep_ > other.istep_;
00841   return jstep_ > other.jstep_;
00842 }
00843 
00844 
00845 //=======================================================================
00846 //: True if the actual images are identical.
00847 // $\bigwedge_{i,j,p} {\textstyle src}(i,j,p) == {\textstyle dest}(i,j,p)$
00848 // The data may be formatted differently in each memory chunk.
00849 //  O(size).
00850 // \relatesalso vil_image_view
00851 template<class T>
00852 bool vil_image_view_deep_equality(const vil_image_view<T> &lhs,
00853                                   const vil_image_view<T> &rhs)
00854 {
00855   if (lhs.nplanes() != rhs.nplanes() ||
00856       lhs.nj() != rhs.nj() ||
00857       lhs.ni() != rhs.ni())
00858     return false;
00859 
00860   for (unsigned p = 0; p < rhs.nplanes(); ++p)
00861     for (unsigned j = 0; j < rhs.nj(); ++j)
00862       for (unsigned i = 0; i < rhs.ni(); ++i)
00863         if (!(rhs(i,j,p) == lhs(i,j,p)))
00864           return false;
00865   return true;
00866 }
00867 
00868 //=======================================================================
00869 
00870 // Specializations must be declared in all translation units where
00871 // they are used.  Since we do not know what instantiations will be
00872 // defined, and each requires a specialization, we define the primary
00873 // template of is_a to call a function that will be declared and
00874 // specialized only in the instantiation translation units.
00875 template <class T> vcl_string vil_image_view_type_name(T*);
00876 
00877 template <class T>
00878 vcl_string vil_image_view<T>::is_a() const
00879 {
00880   return vil_image_view_type_name(static_cast<T*>(0));
00881 }
00882 
00883 #define VIL_IMAGE_VIEW_INSTANTIATE(T) \
00884 VCL_DEFINE_SPECIALIZATION vcl_string vil_image_view_type_name(T*) \
00885 { return vcl_string("vil_image_view<" #T ">"); } \
00886 template class vil_image_view<T >; \
00887 template bool vil_image_view_deep_equality(const vil_image_view<T >&, \
00888                                            const vil_image_view<T >&)
00889 
00890 #endif // vil_image_view_txx_