1 // This is mul/vil3d/vil3d_image_view.hxx
2 #ifndef vil3d_image_view_hxx_
3 #define vil3d_image_view_hxx_
4 //:
5 // \file
6 // \brief Represent images of one or more planes of Ts.
7 // \author Tim Cootes, Ian Scott
8 //
9 // Note: To keep down size of vil3d_image_view
10 // Please think carefully before adding any new methods.
11 // In particular any methods that provide new views (e.g. vil3d_slice)
12 // will be more usefully provided as external functions. - IMS.
13 // In that case, use the "relates" keyword of Doxygen to link the documentation
14 // of that function to the vil3d_image_view class.
15 
16 #include <cstring>
17 #include <string>
18 #include <ostream>
19 #include <iostream>
20 #include <algorithm>
21 #include "vil3d_image_view.h"
22 #include <cassert>
23 #ifdef _MSC_VER
24 #  include <vcl_msvc_warnings.h>
25 #endif
26 #include <vil/vil_pixel_format.h>
27 
28 //=======================================================================
29 
30 template <class T>
vil3d_image_view()31 vil3d_image_view<T>::vil3d_image_view() : top_left_(nullptr) {}
32 
33 template<class T>
vil3d_image_view(unsigned ni,unsigned nj,unsigned nk,unsigned n_planes)34 vil3d_image_view<T>::vil3d_image_view(unsigned ni, unsigned nj,
35                                       unsigned nk, unsigned n_planes)
36 : top_left_(nullptr),istep_(1),jstep_(0),kstep_(0)
37 {
38   set_size(ni,nj,nk,n_planes);
39 }
40 
41 //: Set this view to look at someone else's memory data.
42 template<class T>
vil3d_image_view(const T * top_left,unsigned n_i,unsigned n_j,unsigned n_k,unsigned n_planes,std::ptrdiff_t i_step,std::ptrdiff_t j_step,std::ptrdiff_t k_step,std::ptrdiff_t plane_step)43 vil3d_image_view<T>::vil3d_image_view(const T* top_left,
44                                       unsigned n_i, unsigned n_j, unsigned n_k, unsigned n_planes,
45                                       std::ptrdiff_t i_step, std::ptrdiff_t j_step,
46                                       std::ptrdiff_t k_step, std::ptrdiff_t plane_step)
47 {
48   set_to_memory(top_left,n_i,n_j,n_k,n_planes,i_step,j_step,k_step,plane_step);
49 }
50 
51 //: Set this view to look at another view's data
52 //  Need to pass the memory chunk to set up the internal smart ptr appropriately
53 template<class T>
vil3d_image_view(const vil_memory_chunk_sptr & mem_chunk,const T * top_left,unsigned n_i,unsigned n_j,unsigned n_k,unsigned n_planes,std::ptrdiff_t i_step,std::ptrdiff_t j_step,std::ptrdiff_t k_step,std::ptrdiff_t plane_step)54 vil3d_image_view<T>::vil3d_image_view(const vil_memory_chunk_sptr& mem_chunk,
55                                       const T* top_left, unsigned n_i, unsigned n_j,
56                                       unsigned n_k, unsigned n_planes,
57                                       std::ptrdiff_t i_step, std::ptrdiff_t j_step,
58                                       std::ptrdiff_t k_step, std::ptrdiff_t plane_step)
59  : vil3d_image_view_base(n_i, n_j, n_k, n_planes)
60  , top_left_(const_cast<T*>(top_left))
61  , istep_(i_step), jstep_(j_step), kstep_(k_step)
62  , planestep_(plane_step)
63  , ptr_(mem_chunk)
64 {
65   if (mem_chunk) // if we are doing a view transform on a non-owned image, then mem_chunk will be 0.
66   {
67     // check view and chunk are in rough agreement
68     assert(mem_chunk->size() >= n_planes*n_i*n_j*n_k*sizeof(T));
69     if (size() && (top_left  < reinterpret_cast<const T*>(mem_chunk->data()) ||
70         top_left >= reinterpret_cast<const T*>(reinterpret_cast<char*>(mem_chunk->data()) + mem_chunk->size()) ))
71       std::cerr << "top_left at " << static_cast<const void*>(top_left) << ", memory_chunk at "
72                << reinterpret_cast<const void*>(mem_chunk->data()) << ", size " << mem_chunk->size()
73                << ", size of data type " << sizeof(T) << '\n';
74     assert(!size() || (top_left >= reinterpret_cast<const T*>(mem_chunk->data()) &&
75            top_left  < reinterpret_cast<const T*>(reinterpret_cast<char*>(mem_chunk->data()) + mem_chunk->size()) ));
76   }
77 }
78 
79 //: Copy constructor
80 // If this view cannot set itself to view the other data (because the pixel
81 // formats are incompatible) it will set itself to empty.
82 template<class T>
vil3d_image_view(const vil3d_image_view<T> & im)83 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view<T>& im)
84   : vil3d_image_view_base(im.ni(), im.nj(), im.nk(), im.nplanes()),
85     top_left_(im.top_left_), istep_(im.istep()), jstep_(im.jstep()),
86     kstep_(im.kstep()), planestep_(im.planestep()), ptr_(im.memory_chunk())
87 {
88   if (static_cast<vil3d_image_view_base const&>(im).pixel_format() != pixel_format())
89     clear();
90 }
91 
92 //: Create shallow copy of image with given base reference
93 //  Sets to empty image if target is of different pixel type
94 template<class T>
vil3d_image_view(const vil3d_image_view_base & base_ref)95 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view_base& base_ref)
96   : top_left_(nullptr),istep_(0),jstep_(0),kstep_(0),planestep_(0)
97 {
98   operator=(base_ref);
99 }
100 
101 //: Create shallow copy of image with given base reference
102 //  Sets to empty image if target is of different pixel type
103 template<class T>
vil3d_image_view(const vil3d_image_view_base_sptr & base_sptr)104 vil3d_image_view<T>::vil3d_image_view(const vil3d_image_view_base_sptr& base_sptr)
105   : top_left_(nullptr),istep_(0),jstep_(0),kstep_(0),planestep_(0)
106 {
107   operator=(base_sptr);
108 }
109 
110 //: Create shallow copy of image with same type image
111 template<class T>
operator =(const vil3d_image_view<T> & rhs)112 const vil3d_image_view<T>& vil3d_image_view<T>::operator=(const vil3d_image_view<T>& rhs)
113 {
114   return operator=( static_cast<vil3d_image_view_base const&>(rhs) );
115 }
116 
117 //: Create shallow copy of image with given base reference
118 //  Sets to empty image if target is of different pixel type
119 template<class T>
operator =(const vil3d_image_view_base & base_ref)120 const vil3d_image_view<T>& vil3d_image_view<T>::operator=(const vil3d_image_view_base& base_ref)
121 {
122   if (static_cast<const vil3d_image_view_base*>(this) == &base_ref)
123     return *this;
124 
125   if (base_ref.pixel_format() == pixel_format())
126   {
127     const vil3d_image_view<T> &that = static_cast<const vil3d_image_view<T>&>(base_ref);
128     ni_=that.ni_;
129     nj_=that.nj_;
130     nk_=that.nk_;
131     nplanes_=that.nplanes_;
132     istep_=that.istep_;
133     jstep_=that.jstep_;
134     kstep_=that.kstep_;
135     planestep_=that.planestep_;
136     top_left_=that.top_left_;
137     ptr_=that.ptr_;
138     return *this;
139   }
140 
141   clear();
142   return *this;
143 }
144 
145 //: Perform deep copy of the src image, placing in this image
146 template<class T>
deep_copy(const vil3d_image_view<T> & src)147 void vil3d_image_view<T>::deep_copy(const vil3d_image_view<T>& src)
148 {
149   set_size(src.ni(),src.nj(),src.nk(),src.nplanes());
150 
151   std::ptrdiff_t s_planestep = src.planestep();
152   std::ptrdiff_t s_istep = src.istep();
153   std::ptrdiff_t s_jstep = src.jstep();
154   std::ptrdiff_t s_kstep = src.kstep();
155 
156   // Do a deep copy
157   // This is potentially inefficient
158   const T* src_data = src.origin_ptr();
159   T* data = top_left_;
160   for (unsigned int p=0;p<nplanes_;++p,src_data+=s_planestep,data+=planestep_)
161   {
162     T* slice = data;
163     const T* src_slice = src_data;
164     for (unsigned int k=0;k<nk_;++k,slice+=kstep_,src_slice+=s_kstep)
165     {
166       T* row = slice;
167       const T* src_row = src_slice;
168       for (unsigned int j=0;j<nj_;++j,row += jstep_,src_row += s_jstep)
169       {
170         T* p = row;
171         const T* sp = src_row;
172         for (unsigned int i=0;i<ni_;++i,p+=istep_,sp+=s_istep) *p = *sp;
173       }
174     }
175   }
176 }
177 
178 
~vil3d_image_view()179 template<class T> vil3d_image_view<T>::~vil3d_image_view()
180 {
181   // release_data();
182 }
183 
184 //=======================================================================
185 
186 template<class T>
set_size(unsigned n_i,unsigned n_j,unsigned n_k)187 void vil3d_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_k)
188 {
189   set_size(n_i,n_j,n_k, nplanes_);
190 }
191 
192 //: True if data all in one unbroken block and origin_ptr() is lowest data address
193 template<class T>
is_contiguous() const194 bool vil3d_image_view<T>::is_contiguous() const
195 {
196   // RRR GGG BBB
197   if (planestep_==int(ni_*nj_*nk_))
198   {
199     if (istep_==1 && jstep_==int(ni_) && kstep_==int(ni_*nj_) ) return true;
200     if (istep_==1 && kstep_==int(ni_) && jstep_==int(ni_*nk_) ) return true;
201     if (jstep_==1 && istep_==int(nj_) && kstep_==int(ni_*nj_) ) return true;
202     if (jstep_==1 && kstep_==int(nj_) && istep_==int(nj_*nk_) ) return true;
203     if (kstep_==1 && istep_==int(nk_) && jstep_==int(ni_*nk_) ) return true;
204     if (kstep_==1 && jstep_==int(nk_) && istep_==int(nj_*nk_) ) return true;
205   }
206 
207   int np = nplanes_;
208   // RGBRGBRGB
209   if (planestep_==1)
210   {
211     if (istep_==np && jstep_==int(ni_*np) && kstep_==int(ni_*nj_*np) ) return true;
212     if (istep_==np && kstep_==int(ni_*np) && jstep_==int(ni_*nk_*np) ) return true;
213     if (jstep_==np && istep_==int(nj_*np) && kstep_==int(ni_*nj_*np) ) return true;
214     if (jstep_==np && kstep_==int(nj_*np) && istep_==int(nj_*nk_*np) ) return true;
215     if (kstep_==np && istep_==int(nk_*np) && jstep_==int(ni_*nk_*np) ) return true;
216     if (kstep_==np && jstep_==int(nk_*np) && istep_==int(nj_*nk_*np) ) return true;
217   }
218 
219   // Note that there may be other weird combinations
220   return false;
221 }
222 
223 //=======================================================================
224 
225 template<class T>
set_size(unsigned n_i,unsigned n_j,unsigned n_k,unsigned n_planes)226 void vil3d_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_k, unsigned n_planes)
227 {
228   if (n_i==ni_ && n_j==nj_ && n_k==nk_ && n_planes==nplanes_) return;
229 
230   release_memory();
231 
232   vil_pixel_format fmt = vil_pixel_format_of(T());
233   ptr_ = new vil_memory_chunk(sizeof(T)*n_planes*n_k*n_j*n_i,
234     vil_pixel_format_component_format(fmt));
235 
236   ni_ = n_i;
237   nj_ = n_j;
238   nk_ = n_k;
239   nplanes_ = n_planes;
240   istep_ = 1;
241   jstep_ = n_i;
242   kstep_ = n_i*n_j;
243   planestep_ = n_i*n_j*n_k;
244 
245   top_left_ = reinterpret_cast<T*>(ptr_->data());
246 }
247 
248 
249 //: Set this view to look at someone else's memory.
250 template<class T>
set_to_memory(const T * top_left,unsigned n_i,unsigned n_j,unsigned n_k,unsigned n_planes,std::ptrdiff_t i_step,std::ptrdiff_t j_step,std::ptrdiff_t k_step,std::ptrdiff_t plane_step)251 void vil3d_image_view<T>::set_to_memory(const T* top_left,
252                                         unsigned n_i, unsigned n_j,
253                                         unsigned n_k, unsigned n_planes,
254                                         std::ptrdiff_t i_step, std::ptrdiff_t j_step,
255                                         std::ptrdiff_t k_step, std::ptrdiff_t plane_step)
256 {
257   release_memory();
258   top_left_ = const_cast<T*>(top_left);  // Remove const, as view may end up manipulating data
259 
260   ni_ = n_i;
261   nj_ = n_j;
262   nk_ = n_k;
263   nplanes_ = n_planes;
264   istep_ = i_step;
265   jstep_ = j_step;
266   kstep_ = k_step;
267   planestep_ = plane_step;
268 }
269 
270 //=======================================================================
271 //: Fill view with given value
272 template<class T>
fill(T value)273 void vil3d_image_view<T>::fill(T value)
274 {
275   if (is_contiguous())
276     if (value == 0)
277       std::memset(begin(), 0, this->size_bytes());
278     else
279       std::fill(begin(), end(), value);
280   else
281   {
282     T* plane = top_left_;
283     for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
284     {
285       T* slice = plane;
286       for (unsigned int k=0;k<nk_;++k,slice += kstep_)
287       {
288         T* row = slice;
289         for (unsigned int j=0;j<nj_;++j,row += jstep_)
290         {
291           T* p = row;
292           for (unsigned int i=0;i<ni_;++i,p+=istep_) *p = value;
293         }
294       }
295     }
296   }
297 }
298 
299 //=======================================================================
300 
301 template<class T>
is_class(std::string const & s) const302 bool vil3d_image_view<T>::is_class(std::string const& s) const
303 {
304   return s==vil3d_image_view<T>::is_a() || vil3d_image_view_base::is_class(s);
305 }
306 
307 //=======================================================================
308 
309 template<class T>
print(std::ostream & os) const310 void vil3d_image_view<T>::print(std::ostream& os) const
311 {
312   os<<nplanes_<<" planes, each "<<ni_<<" x "<<nj_<<" x "<<nk_;
313 }
314 
315 //=======================================================================
316 //: True if they share same view of same image data.
317 //  This does not do a deep equality on image data. If the images point
318 //  to different image data objects that contain identical images, then
319 //  the result will still be false.
320 template<class T>
operator ==(const vil3d_image_view<T> & other) const321 bool vil3d_image_view<T>::operator==(const vil3d_image_view<T> &other) const
322 {
323   if (!(bool) *this && !(bool)other) return true;
324   return ptr_  == other.ptr_ &&
325     top_left_  == other.top_left_ &&
326     nplanes_   == other.nplanes_ &&
327     ni_        == other.ni_ &&
328     nj_        == other.nj_ &&
329     nk_        == other.nk_ &&
330     planestep_ == other.planestep_ &&
331     istep_     == other.istep_ &&
332     jstep_     == other.jstep_ &&
333     kstep_     == other.kstep_;
334 }
335 
336 //=======================================================================
337 //: Provides an ordering.
338 //  Useful for ordered containers.
339 //  There is no guaranteed meaning to the less than operator, except that
340 //  (a<b && b<a)  is false and  !(a<b) && !(b<a)  is equivalent to  a==b
341 template<class T>
operator <(const vil3d_image_view<T> & other) const342 bool vil3d_image_view<T>::operator<(const vil3d_image_view<T>& other) const
343 {
344   if (ptr_ != other.ptr_) return ptr_<other.ptr_;
345   if ((bool) *this && (bool)other) return false;
346   if (nplanes_ != other.nplanes_) return nplanes_ < other.nplanes_;
347   if (ni_ != other.ni_) return ni_ < other.ni_;
348   if (nj_ != other.nj_) return nj_ < other.nj_;
349   if (nk_ != other.nk_) return nk_ < other.nk_;
350   if (planestep_ != other.planestep_) return planestep_ < other.planestep_;
351   if (istep_ != other.istep_) return istep_ < other.istep_;
352   if (jstep_ != other.jstep_) return jstep_ < other.jstep_;
353   return kstep_ < other.kstep_;
354 }
355 
356 
357 //=======================================================================
358 //: True if the actual images are identical.
359 // $\bigwedge_{i,j,k,p} {\textstyle src}(i,j,k,p) == {\textstyle dest}(i,j,k,p)$
360 // The data may be formatted differently in each memory chunk.
361 //  O(size).
362 // \relatesalso vil3d_image_view
363 template<class T>
vil3d_image_view_deep_equality(const vil3d_image_view<T> & lhs,const vil3d_image_view<T> & rhs)364 bool vil3d_image_view_deep_equality(const vil3d_image_view<T> &lhs,
365                                     const vil3d_image_view<T> &rhs)
366 {
367   if (lhs.nplanes() != rhs.nplanes() ||
368       lhs.nk() != rhs.nk() ||
369       lhs.nj() != rhs.nj() ||
370       lhs.ni() != rhs.ni())
371     return false;
372 
373   for (unsigned p = 0; p < rhs.nplanes(); ++p)
374    for (unsigned k = 0; k < rhs.nk(); ++k)
375     for (unsigned j = 0; j < rhs.nj(); ++j)
376       for (unsigned i = 0; i < rhs.ni(); ++i)
377         if (!(rhs(i,j,k,p) == lhs(i,j,k,p)))
378           return false;
379   return true;
380 }
381 
382 #define VIL3D_IMAGE_VIEW_INSTANTIATE(T) \
383 template <> std::string vil3d_image_view<T >::is_a() const \
384 { return std::string("vil3d_image_view<" #T ">"); } \
385 template class vil3d_image_view<T >; \
386 template bool vil3d_image_view_deep_equality(const vil3d_image_view<T >&, \
387                                              const vil3d_image_view<T >&)
388 
389 #endif // vil3d_image_view_hxx_
390