contrib/mul/vil3d/vil3d_image_view.txx
Go to the documentation of this file.
00001 // This is mul/vil3d/vil3d_image_view.txx
00002 #ifndef vil3d_image_view_txx_
00003 #define vil3d_image_view_txx_
00004 //:
00005 // \file
00006 // \brief Represent images of one or more planes of Ts.
00007 // \author Tim Cootes, Ian Scott
00008 //
00009 // Note: To keep down size of vil3d_image_view
00010 // Please think carefully before adding any new methods.
00011 // In particular any methods that provide new views (e.g. vil3d_slice)
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 vil3d_image_view class.
00015 
00016 #include "vil3d_image_view.h"
00017 #include <vcl_cstring.h> // for std::memset
00018 #include <vcl_string.h>
00019 #include <vcl_cassert.h>
00020 #include <vcl_ostream.h>
00021 #include <vcl_algorithm.h>
00022 #include <vil/vil_pixel_format.h>
00023 
00024 //=======================================================================
00025 
00026 template<class T>
00027 vil3d_image_view<T>::vil3d_image_view()
00028 : top_left_(0),istep_(0),jstep_(0),kstep_(0),planestep_(0)
00029 {}
00030 
00031 template<class T>
00032 vil3d_image_view<T>::vil3d_image_view(unsigned ni, unsigned nj,
00033                                       unsigned nk, unsigned n_planes)
00034 : top_left_(0),istep_(1),jstep_(0),kstep_(0)
00035 {
00036   set_size(ni,nj,nk,n_planes);
00037 }
00038 
00039 //: Set this view to look at someone else's memory data.
00040 template<class T>
00041 vil3d_image_view<T>::vil3d_image_view(const T* top_left,
00042                                       unsigned n_i, unsigned n_j, unsigned n_k, unsigned n_planes,
00043                                       vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step,
00044                                       vcl_ptrdiff_t k_step, vcl_ptrdiff_t plane_step)
00045 {
00046   set_to_memory(top_left,n_i,n_j,n_k,n_planes,i_step,j_step,k_step,plane_step);
00047 }
00048 
00049 //: Set this view to look at another view's data
00050 //  Need to pass the memory chunk to set up the internal smart ptr appropriately
00051 template<class T>
00052 vil3d_image_view<T>::vil3d_image_view(const vil_memory_chunk_sptr& mem_chunk,
00053                                       const T* top_left, unsigned n_i, unsigned n_j,
00054                                       unsigned n_k, unsigned n_planes,
00055                                       vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step,
00056                                       vcl_ptrdiff_t k_step, vcl_ptrdiff_t plane_step)
00057  : vil3d_image_view_base(n_i, n_j, n_k, n_planes)
00058  , top_left_(const_cast<T*>(top_left))
00059  , istep_(i_step), jstep_(j_step), kstep_(k_step)
00060  , planestep_(plane_step)
00061  , ptr_(mem_chunk)
00062 {
00063   if (mem_chunk) // if we are doing a view transform on a non-owned image, then mem_chunk will be 0.
00064   {
00065     // check view and chunk are in rough agreement
00066     assert(mem_chunk->size() >= n_planes*n_i*n_j*n_k*sizeof(T));
00067     if (size() && (top_left  < reinterpret_cast<const T*>(mem_chunk->data()) ||
00068         top_left >= reinterpret_cast<const T*>(reinterpret_cast<char*>(mem_chunk->data()) + mem_chunk->size()) ))
00069       vcl_cerr << "top_left at " << static_cast<const void*>(top_left) << ", memory_chunk at "
00070                << reinterpret_cast<const void*>(mem_chunk->data()) << ", size " << mem_chunk->size()
00071                << ", size of data type " << sizeof(T) << '\n';
00072     assert(!size() || (top_left >= reinterpret_cast<const T*>(mem_chunk->data()) &&
00073            top_left  < reinterpret_cast<const T*>(reinterpret_cast<char*>(mem_chunk->data()) + mem_chunk->size()) ));
00074   }
00075 }
00076 
00077 //: Copy constructor
00078 // If this view cannot set itself to view the other data (because the pixel
00079 // formats are incompatible) it will set itself to empty.
00080 template<class T>
00081 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view<T>& im)
00082   : vil3d_image_view_base(im.ni(), im.nj(), im.nk(), im.nplanes()),
00083     top_left_(im.top_left_), istep_(im.istep()), jstep_(im.jstep()),
00084     kstep_(im.kstep()), planestep_(im.planestep()), ptr_(im.memory_chunk())
00085 {
00086   if (static_cast<vil3d_image_view_base const&>(im).pixel_format() != pixel_format())
00087     clear();
00088 }
00089 
00090 //: Create shallow copy of image with given base reference
00091 //  Sets to empty image if target is of different pixel type
00092 template<class T>
00093 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view_base& base_ref)
00094   : top_left_(0),istep_(0),jstep_(0),kstep_(0),planestep_(0)
00095 {
00096   operator=(base_ref);
00097 }
00098 
00099 //: Create shallow copy of image with given base reference
00100 //  Sets to empty image if target is of different pixel type
00101 template<class T>
00102 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view_base_sptr& base_sptr)
00103   : top_left_(0),istep_(0),jstep_(0),kstep_(0),planestep_(0)
00104 {
00105   operator=(base_sptr);
00106 }
00107 
00108 //: Create shallow copy of image with same type image
00109 template<class T>
00110 const vil3d_image_view<T>& vil3d_image_view<T>::operator=(const vil3d_image_view<T>& rhs)
00111 {
00112   return operator=( static_cast<vil3d_image_view_base const&>(rhs) );
00113 }
00114 
00115 //: Create shallow copy of image with given base reference
00116 //  Sets to empty image if target is of different pixel type
00117 template<class T>
00118 const vil3d_image_view<T>& vil3d_image_view<T>::operator=(const vil3d_image_view_base& base_ref)
00119 {
00120   if (static_cast<const vil3d_image_view_base*>(this) == &base_ref)
00121     return *this;
00122 
00123   if (base_ref.pixel_format() == pixel_format())
00124   {
00125     const vil3d_image_view<T> &that = static_cast<const vil3d_image_view<T>&>(base_ref);
00126     ni_=that.ni_;
00127     nj_=that.nj_;
00128     nk_=that.nk_;
00129     nplanes_=that.nplanes_;
00130     istep_=that.istep_;
00131     jstep_=that.jstep_;
00132     kstep_=that.kstep_;
00133     planestep_=that.planestep_;
00134     top_left_=that.top_left_;
00135     ptr_=that.ptr_;
00136     return *this;
00137   }
00138 
00139   clear();
00140   return *this;
00141 }
00142 
00143 //: Perform deep copy of the src image, placing in this image
00144 template<class T>
00145 void vil3d_image_view<T>::deep_copy(const vil3d_image_view<T>& src)
00146 {
00147   set_size(src.ni(),src.nj(),src.nk(),src.nplanes());
00148 
00149   vcl_ptrdiff_t s_planestep = src.planestep();
00150   vcl_ptrdiff_t s_istep = src.istep();
00151   vcl_ptrdiff_t s_jstep = src.jstep();
00152   vcl_ptrdiff_t s_kstep = src.kstep();
00153 
00154   // Do a deep copy
00155   // This is potentially inefficient
00156   const T* src_data = src.origin_ptr();
00157   T* data = top_left_;
00158   for (unsigned int p=0;p<nplanes_;++p,src_data+=s_planestep,data+=planestep_)
00159   {
00160     T* slice = data;
00161     const T* src_slice = src_data;
00162     for (unsigned int k=0;k<nk_;++k,slice+=kstep_,src_slice+=s_kstep)
00163     {
00164       T* row = slice;
00165       const T* src_row = src_slice;
00166       for (unsigned int j=0;j<nj_;++j,row += jstep_,src_row += s_jstep)
00167       {
00168         T* p = row;
00169         const T* sp = src_row;
00170         for (unsigned int i=0;i<ni_;++i,p+=istep_,sp+=s_istep) *p = *sp;
00171       }
00172     }
00173   }
00174 }
00175 
00176 
00177 template<class T> vil3d_image_view<T>::~vil3d_image_view()
00178 {
00179   // release_data();
00180 }
00181 
00182 //=======================================================================
00183 
00184 template<class T>
00185 void vil3d_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_k)
00186 {
00187   set_size(n_i,n_j,n_k, nplanes_);
00188 }
00189 
00190 //: True if data all in one unbroken block and origin_ptr() is lowest data address
00191 template<class T>
00192 bool vil3d_image_view<T>::is_contiguous() const
00193 {
00194   // RRR GGG BBB
00195   if (planestep_==int(ni_*nj_*nk_))
00196   {
00197     if (istep_==1 && jstep_==int(ni_) && kstep_==int(ni_*nj_) ) return true;
00198     if (istep_==1 && kstep_==int(ni_) && jstep_==int(ni_*nk_) ) return true;
00199     if (jstep_==1 && istep_==int(nj_) && kstep_==int(ni_*nj_) ) return true;
00200     if (jstep_==1 && kstep_==int(nj_) && istep_==int(nj_*nk_) ) return true;
00201     if (kstep_==1 && istep_==int(nk_) && jstep_==int(ni_*nk_) ) return true;
00202     if (kstep_==1 && jstep_==int(nk_) && istep_==int(nj_*nk_) ) return true;
00203   }
00204 
00205   int np = nplanes_;
00206   // RGBRGBRGB
00207   if (planestep_==1)
00208   {
00209     if (istep_==np && jstep_==int(ni_*np) && kstep_==int(ni_*nj_*np) ) return true;
00210     if (istep_==np && kstep_==int(ni_*np) && jstep_==int(ni_*nk_*np) ) return true;
00211     if (jstep_==np && istep_==int(nj_*np) && kstep_==int(ni_*nj_*np) ) return true;
00212     if (jstep_==np && kstep_==int(nj_*np) && istep_==int(nj_*nk_*np) ) return true;
00213     if (kstep_==np && istep_==int(nk_*np) && jstep_==int(ni_*nk_*np) ) return true;
00214     if (kstep_==np && jstep_==int(nk_*np) && istep_==int(nj_*nk_*np) ) return true;
00215   }
00216 
00217   // Note that there may be other weird combinations
00218   return false;
00219 }
00220 
00221 //=======================================================================
00222 
00223 template<class T>
00224 void vil3d_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_k, unsigned n_planes)
00225 {
00226   if (n_i==ni_ && n_j==nj_ && n_k==nk_ && n_planes==nplanes_) return;
00227 
00228   release_memory();
00229 
00230   vil_pixel_format fmt = vil_pixel_format_of(T());
00231   ptr_ = new vil_memory_chunk(sizeof(T)*n_planes*n_k*n_j*n_i,
00232     vil_pixel_format_component_format(fmt));
00233 
00234   ni_ = n_i;
00235   nj_ = n_j;
00236   nk_ = n_k;
00237   nplanes_ = n_planes;
00238   istep_ = 1;
00239   jstep_ = n_i;
00240   kstep_ = n_i*n_j;
00241   planestep_ = n_i*n_j*n_k;
00242 
00243   top_left_ = reinterpret_cast<T*>(ptr_->data());
00244 }
00245 
00246 
00247 //: Set this view to look at someone else's memory.
00248 template<class T>
00249 void vil3d_image_view<T>::set_to_memory(const T* top_left,
00250                                         unsigned n_i, unsigned n_j,
00251                                         unsigned n_k, unsigned n_planes,
00252                                         vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step,
00253                                         vcl_ptrdiff_t k_step, vcl_ptrdiff_t plane_step)
00254 {
00255   release_memory();
00256   top_left_ = const_cast<T*>(top_left);  // Remove const, as view may end up manipulating data
00257 
00258   ni_ = n_i;
00259   nj_ = n_j;
00260   nk_ = n_k;
00261   nplanes_ = n_planes;
00262   istep_ = i_step;
00263   jstep_ = j_step;
00264   kstep_ = k_step;
00265   planestep_ = plane_step;
00266 }
00267 
00268 //=======================================================================
00269 //: Fill view with given value
00270 template<class T>
00271 void vil3d_image_view<T>::fill(T value)
00272 {
00273   if (is_contiguous())
00274     if (value == 0)
00275       vcl_memset(begin(), 0, this->size_bytes());
00276     else
00277       vcl_fill(begin(), end(), value);
00278   else
00279   {
00280     T* plane = top_left_;
00281     for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
00282     {
00283       T* slice = plane;
00284       for (unsigned int k=0;k<nk_;++k,slice += kstep_)
00285       {
00286         T* row = slice;
00287         for (unsigned int j=0;j<nj_;++j,row += jstep_)
00288         {
00289           T* p = row;
00290           for (unsigned int i=0;i<ni_;++i,p+=istep_) *p = value;
00291         }
00292       }
00293     }
00294   }
00295 }
00296 
00297 //=======================================================================
00298 
00299 template<class T>
00300 bool vil3d_image_view<T>::is_class(vcl_string const& s) const
00301 {
00302   return s==vil3d_image_view<T>::is_a() || vil3d_image_view_base::is_class(s);
00303 }
00304 
00305 //=======================================================================
00306 
00307 template<class T>
00308 void vil3d_image_view<T>::print(vcl_ostream& os) const
00309 {
00310   os<<nplanes_<<" planes, each "<<ni_<<" x "<<nj_<<" x "<<nk_;
00311 }
00312 
00313 //=======================================================================
00314 //: True if they share same view of same image data.
00315 //  This does not do a deep equality on image data. If the images point
00316 //  to different image data objects that contain identical images, then
00317 //  the result will still be false.
00318 template<class T>
00319 bool vil3d_image_view<T>::operator==(const vil3d_image_view<T> &other) const
00320 {
00321   if (!(bool) *this && !(bool)other) return true;
00322   return ptr_  == other.ptr_ &&
00323     top_left_  == other.top_left_ &&
00324     nplanes_   == other.nplanes_ &&
00325     ni_        == other.ni_ &&
00326     nj_        == other.nj_ &&
00327     nk_        == other.nk_ &&
00328     planestep_ == other.planestep_ &&
00329     istep_     == other.istep_ &&
00330     jstep_     == other.jstep_ &&
00331     kstep_     == other.kstep_;
00332 }
00333 
00334 //=======================================================================
00335 //: Provides an ordering.
00336 //  Useful for ordered containers.
00337 //  There is no guaranteed meaning to the less than operator, except that
00338 //  (a<b && b<a)  is false and  !(a<b) && !(b<a)  is equivalent to  a==b
00339 template<class T>
00340 bool vil3d_image_view<T>::operator<(const vil3d_image_view<T>& other) const
00341 {
00342   if (ptr_ != other.ptr_) return ptr_<other.ptr_;
00343   if ((bool) *this && (bool)other) return false;
00344   if (nplanes_ != other.nplanes_) return nplanes_ < other.nplanes_;
00345   if (ni_ != other.ni_) return ni_ < other.ni_;
00346   if (nj_ != other.nj_) return nj_ < other.nj_;
00347   if (nk_ != other.nk_) return nk_ < other.nk_;
00348   if (planestep_ != other.planestep_) return planestep_ < other.planestep_;
00349   if (istep_ != other.istep_) return istep_ < other.istep_;
00350   if (jstep_ != other.jstep_) return jstep_ < other.jstep_;
00351   return kstep_ < other.kstep_;
00352 }
00353 
00354 
00355 //=======================================================================
00356 //: True if the actual images are identical.
00357 // $\bigwedge_{i,j,k,p} {\textstyle src}(i,j,k,p) == {\textstyle dest}(i,j,k,p)$
00358 // The data may be formatted differently in each memory chunk.
00359 //  O(size).
00360 // \relatesalso vil3d_image_view
00361 template<class T>
00362 bool vil3d_image_view_deep_equality(const vil3d_image_view<T> &lhs,
00363                                     const vil3d_image_view<T> &rhs)
00364 {
00365   if (lhs.nplanes() != rhs.nplanes() ||
00366       lhs.nk() != rhs.nk() ||
00367       lhs.nj() != rhs.nj() ||
00368       lhs.ni() != rhs.ni())
00369     return false;
00370 
00371   for (unsigned p = 0; p < rhs.nplanes(); ++p)
00372    for (unsigned k = 0; k < rhs.nk(); ++k)
00373     for (unsigned j = 0; j < rhs.nj(); ++j)
00374       for (unsigned i = 0; i < rhs.ni(); ++i)
00375         if (!(rhs(i,j,k,p) == lhs(i,j,k,p)))
00376           return false;
00377   return true;
00378 }
00379 
00380 #define VIL3D_IMAGE_VIEW_INSTANTIATE(T) \
00381 VCL_DEFINE_SPECIALIZATION vcl_string vil3d_image_view<T >::is_a() const \
00382 { return vcl_string("vil3d_image_view<" #T ">"); } \
00383 template class vil3d_image_view<T >; \
00384 template bool vil3d_image_view_deep_equality(const vil3d_image_view<T >&, \
00385                                              const vil3d_image_view<T >&)
00386 
00387 #endif // vil3d_image_view_txx_