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