vil_image_view.hxx
Go to the documentation of this file.
1 // This is core/vil/vil_image_view.hxx
2 #ifndef vil_image_view_hxx_
3 #define vil_image_view_hxx_
4 //:
5 // \file
6 // \brief Represent images of one or more planes of Ts.
7 // \author Ian Scott
8 //
9 // Note: To keep down size of vil_image_view
10 // Please think carefully before adding any new methods.
11 // In particular any methods that provide new views (e.g. vil_plane)
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 vil_image_view class.
15 //
16 // \verbatim
17 // Modifications
18 // 23 Oct.2003 - Peter Vanroose - Added support for 64-bit int pixels
19 // \endverbatim
20 
21 #include <string>
22 #include <cstdlib>
23 #include <cmath>
24 #include <ostream>
25 #include <cstring>
26 #include <algorithm>
27 #include "vil_image_view.h"
28 #include <cassert>
29 #ifdef _MSC_VER
30 # include <vcl_msvc_warnings.h>
31 #endif
32 #include <vil/vil_pixel_format.h>
33 #include <vil/vil_exception.h>
34 
35 //=======================================================================
36 
37 
38 template<class T>
39 vil_image_view<T>::vil_image_view(unsigned n_i, unsigned n_j, unsigned n_planes,
40  unsigned n_interleaved_planes)
41 : top_left_(nullptr), istep_(n_interleaved_planes)
42 {
43  assert(n_planes==1 || n_interleaved_planes==1);
45  n_planes * n_interleaved_planes == 1 ||
47  set_size(n_i,n_j,n_planes*n_interleaved_planes);
48 }
49 
50 //: Set this view to look at someone else's memory data.
51 template<class T>
52 vil_image_view<T>::vil_image_view(const T* top_left, unsigned n_i, unsigned n_j, unsigned n_planes,
53  std::ptrdiff_t i_step, std::ptrdiff_t j_step, std::ptrdiff_t plane_step)
54 {
55  set_to_memory(top_left,n_i,n_j,n_planes,i_step,j_step,plane_step);
56 }
57 
58 //: Set this view to look at another view's data
59 // Need to pass the memory chunk to set up the internal smart ptr appropriately
60 template<class T>
62  const T* top_left, unsigned n_i, unsigned n_j, unsigned n_planes,
63  std::ptrdiff_t i_step, std::ptrdiff_t j_step, std::ptrdiff_t plane_step)
64  : vil_image_view_base(n_i, n_j, n_planes)
65  , top_left_(const_cast<T*>(top_left))
66  , istep_(i_step), jstep_(j_step)
67  , planestep_(plane_step)
68  , ptr_(mem_chunk)
69 {
70 #ifndef NDEBUG
71  // check view and chunk are in rough agreement
72  if (mem_chunk) // if we are doing a view transform on a non-owned image, then mem_chunk will be 0.
73  {
74  if ( mem_chunk->size() < n_planes*n_i*n_j*sizeof(T) )
75  std::cerr << "mem_chunk->size()=" << mem_chunk->size() << '\n'
76  << "nplanes=" << n_planes << '\n'
77  << "n_i=" << n_i << '\n'
78  << "n_j=" << n_j << '\n'
79  << "sizeof(T)=" << sizeof(T) << '\n'
80  << "n_planes*n_i*n_j*sizeof(T)=" << n_planes*n_i*n_j*sizeof(T) << '\n';
81  assert(mem_chunk->size() >= n_planes*n_i*n_j*sizeof(T));
82  if (top_left < reinterpret_cast<const T*>(mem_chunk->data()) ||
83  top_left >= reinterpret_cast<const T*>(reinterpret_cast<const char*>(mem_chunk->data()) + mem_chunk->size()))
84  std::cerr << "top_left at " << static_cast<const void*>(top_left) << ", memory_chunk at "
85  << reinterpret_cast<const void*>(mem_chunk->data()) << ", size " << mem_chunk->size()
86  << ", size of data type " << sizeof(T) << '\n';
87  assert(top_left >= reinterpret_cast<const T*>(mem_chunk->data()) &&
88  (mem_chunk->size()==0 || top_left < reinterpret_cast<const T*>(reinterpret_cast<const char*>(mem_chunk->data()) + mem_chunk->size())) );
89  }
90 #endif
91 }
92 
93 //: Copy constructor
94 // If this view cannot set itself to view the other data (e.g. because the
95 // types are incompatible) it will set itself to empty.
96 template<class T>
98 : vil_image_view_base(that.ni(),that.nj(),that.nplanes()),
99  top_left_(nullptr), istep_(0), jstep_(0), planestep_(0), ptr_(nullptr)
100 {
101  operator=( static_cast<vil_image_view_base const&>(that) );
102 }
103 
104 //: Sort of copy constructor
105 // If this view cannot set itself to view the other data (e.g. because the
106 // types are incompatible) it will set itself to empty.
107 template<class T>
109 top_left_(nullptr), istep_(0), jstep_(0), planestep_(0), ptr_(nullptr)
110 {
111  operator=(that);
112 }
113 
114 //: Sort of copy constructor
115 // If this view cannot set itself to view the other data (e.g. because the
116 // types are incompatible) it will set itself to empty.
117 template <class T>
119 top_left_(nullptr), istep_(0), jstep_(0), planestep_(0), ptr_(nullptr)
120 {
121  operator=(that);
122 }
123 
124 //: Perform deep copy of the src image, placing in this image
125 template<class T>
127 {
128  set_size(src.ni(),src.nj(),src.nplanes());
129 
130  if (src.is_contiguous() && this->is_contiguous())
131  {
132  istep_=src.istep_; jstep_= src.jstep_; planestep_ = src.planestep_;
133  if (src.istep()>0 && src.jstep()>0 && src.planestep()>=0)
134  {
135  std::memcpy(top_left_,src.top_left_ptr(),src.size()*sizeof(T));
136  return;
137  }
138  const_iterator s_it = src.begin();
139  iterator d_it = begin();
140  const_iterator end_it = src.end();
141  while (s_it!=end_it) {*d_it = *s_it; ++s_it; ++d_it; }
142  return;
143  }
144 
145  const std::ptrdiff_t s_planestep = src.planestep();
146  const std::ptrdiff_t s_istep = src.istep();
147  const std::ptrdiff_t s_jstep = src.jstep();
148 
149  // Do a deep copy
150  // This is potentially inefficient
151  const T* src_data = src.top_left_ptr();
152  T* data = top_left_;
153  for (unsigned int p=0;p<nplanes_;++p,src_data += s_planestep,data += planestep_)
154  {
155  T* row = data;
156  const T* src_row = src_data;
157  for (unsigned int j=0;j<nj_;++j,row += jstep_,src_row += s_jstep)
158  {
159  T* p = row;
160  const T* sp = src_row;
161  for (unsigned int i=0;i<ni_;++i,p+=istep_,sp+=s_istep) *p = *sp;
162  }
163  }
164 }
165 
166 // Notes on convert_components_from_planes() and convert_planes_from_components()
167 // These are used by the operator= to provide the appropriate smart conversion
168 // behaviour for the various types.
169 // I don't think that C++ templates support full pattern matching,
170 // so we have to provide one template instantiation to cover the general
171 // compound pixel case (the range of which is possibly infinite)
172 // We then specialise for all the scalar pixel cases (there are only so
173 // many scalar types).
174 // I guess someone could merge all the scalar specialisations using
175 // macros and substantially reduce the length of this code.
176 
177 
178 //: Convert planes to components from planes, or do nothing if types are wrong.
179 template <class T>
181  const vil_image_view_base &rhs_base)
182 {
183  typedef typename T::value_type comp_type;
184 
185  const int ncomp =
187 
189  if (// both sides have equal component types and rhs has scalar pixels and
190  rhs_base.pixel_format() == vil_pixel_format_component_format(fmt) &&
191  // lhs has number of components equal to rhs's number of planes.
192  ncomp == (int)rhs_base.nplanes() )
193  {
194  const vil_image_view<comp_type> &rhs = static_cast<const vil_image_view<comp_type>&>(rhs_base);
195  // Check that the steps are suitable for viewing as components
196  if (rhs.planestep() != 1 || std::abs((int)rhs.istep())<ncomp || std::abs((int)rhs.jstep())<ncomp ) return false;
197  lhs = vil_image_view<T >(rhs.memory_chunk(),
198  reinterpret_cast<T const*>(rhs.top_left_ptr()),
199  rhs.ni(),rhs.nj(),1,
200  rhs.istep()/ncomp,rhs.jstep()/ncomp,1);
201  return true;
202  }
203  else
204  return false;
205 }
206 
207 
208 template <>
210  const vil_image_view_base & /*rhs_base*/)
211 {return false;} // when lhs has scalar pixels, don't attempt conversion
212 
213 template <>
215  const vil_image_view_base & /*rhs_base*/)
216 {return false;}
217 
218 template <>
220  const vil_image_view_base & /*rhs_base*/)
221 {return false;}
222 
223 template <>
225  const vil_image_view_base & /*rhs_base*/)
226 {return false;}
227 
228 template <>
230  const vil_image_view_base & /*rhs_base*/)
231 {return false;}
232 
233 template <>
235  const vil_image_view_base & /*rhs_base*/)
236 {return false;}
237 
238 template <>
240  const vil_image_view_base & /*rhs_base*/)
241 {return false;}
242 
243 template <>
245  const vil_image_view_base & /*rhs_base*/)
246 {return false;}
247 
248 template <>
250  const vil_image_view_base & /*rhs_base*/)
251 {return false;}
252 
253 #if VXL_HAS_INT_64
254 
255 template <>
257  const vil_image_view_base & /*rhs_base*/)
258 {return false;}
259 
260 template <>
262  const vil_image_view_base & /*rhs_base*/)
263 {return false;}
264 
265 #endif
266 
267 //: Convert components to planes from planes, or do nothing if types are wrong.
268 template <class T>
270  const vil_image_view_base & /*rhs*/)
271 { return false;} // when lhs has non-scalar pixels, don't attempt conversion
272 // except for the following typical cases
273 template <>
275  const vil_image_view_base & rhs)
276 {
277  if (rhs.nplanes() != 3)
278  return false;
280  return false;
281  unsigned ni = rhs.ni(), nj = rhs.nj();
282  const vil_image_view<vxl_byte> &rhsv = static_cast<const vil_image_view<vxl_byte>&>(rhs);
283  lhs= *(new vil_image_view<vil_rgb<vxl_byte> >(ni, nj));
284  for (unsigned j = 0; j<nj; ++j)
285  for (unsigned i = 0; i<ni; ++i){
286  lhs(i,j).r = rhsv(i,j,0); lhs(i, j).g = rhsv(i,j,1); lhs(i, j).b = rhsv(i,j,2);
287  }
288  return true;
289 }
290 
291 template <>
293  const vil_image_view_base & rhs)
294 {
295  if (rhs.nplanes() != 4)
296  return false;
298  return false;
299  unsigned ni = rhs.ni(), nj = rhs.nj();
300  const vil_image_view<vxl_uint_16> &rhsv = static_cast<const vil_image_view<vxl_uint_16>&>(rhs);
301  lhs = *(new vil_image_view<vil_rgba<vxl_uint_16> >(ni, nj));
302  for (unsigned j = 0; j<nj; ++j)
303  for (unsigned i = 0; i<ni; ++i){
304  lhs(i, j).r = rhsv(i,j,0); lhs(i, j).g = rhsv(i,j,1); lhs(i, j).b = rhsv(i,j,2);
305  lhs(i, j).a = rhsv(i,j,3);
306  }
307  return true;
308 }
309 
310 template <>
312  const vil_image_view_base &rhs_base)
313 {
314  const unsigned ncomp =
316 
317  if (// rhs has just 1 plane
318  rhs_base.nplanes() == 1 &&
319  // both sides have equal component types
321  {
322  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
323  const vil_image_view<vxl_byte> &rhs = static_cast<const vil_image_view<vxl_byte>&>(rhs_base);
324 
326  rhs.ni(),rhs.nj(),ncomp,
327  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
328  return true;
329  }
330  else
331  return false;
332 }
333 
334 template <>
336  const vil_image_view_base &rhs_base)
337 {
338  const unsigned ncomp =
340 
341  if (// rhs has just 1 plane
342  rhs_base.nplanes() == 1 &&
343  // both sides have equal component types
345  {
346  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
347  const vil_image_view<vxl_sbyte> &rhs = static_cast<const vil_image_view<vxl_sbyte>&>(rhs_base);
348 
350  rhs.ni(),rhs.nj(),ncomp,
351  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
352  return true;
353  }
354  else
355  return false;
356 }
357 
358 template <>
360  const vil_image_view_base &rhs_base)
361 {
362  const unsigned ncomp =
364 
365  if (// rhs has just 1 plane
366  rhs_base.nplanes() == 1 &&
367  // both sides have equal component types
369  {
370  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
371  const vil_image_view<vxl_uint_16> &rhs = static_cast<const vil_image_view<vxl_uint_16>&>(rhs_base);
372 
374  rhs.ni(),rhs.nj(),ncomp,
375  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
376  return true;
377  }
378  else
379  return false;
380 }
381 
382 template <>
384  const vil_image_view_base &rhs_base)
385 {
386  const unsigned ncomp =
388 
389  if (// rhs has just 1 plane
390  rhs_base.nplanes() == 1 &&
391  // both sides have equal component types
393  {
394  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
395  const vil_image_view<vxl_int_16> &rhs = static_cast<const vil_image_view<vxl_int_16>&>(rhs_base);
396 
398  rhs.ni(),rhs.nj(),ncomp,
399  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
400  return true;
401  }
402  else
403  return false;
404 }
405 
406 template <>
408  const vil_image_view_base &rhs_base)
409 {
410  const unsigned ncomp =
412 
413  if (// rhs has just 1 plane
414  rhs_base.nplanes() == 1 &&
415  // both sides have equal component types
417  {
418  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
419  const vil_image_view<vxl_uint_32> &rhs = static_cast<const vil_image_view<vxl_uint_32>&>(rhs_base);
420 
422  rhs.ni(),rhs.nj(),ncomp,
423  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
424  return true;
425  }
426  else
427  return false;
428 }
429 
430 template <>
432  const vil_image_view_base &rhs_base)
433 {
434  const unsigned ncomp =
436 
437  if (// rhs has just 1 plane
438  rhs_base.nplanes() == 1 &&
439  // both sides have equal component types
441  {
442  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
443  const vil_image_view<vxl_int_32> &rhs = static_cast<const vil_image_view<vxl_int_32>&>(rhs_base);
444 
446  rhs.ni(),rhs.nj(),ncomp,
447  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
448  return true;
449  }
450  else
451  return false;
452 }
453 
454 #if VXL_HAS_INT_64
455 
456 template <>
458  const vil_image_view_base &rhs_base)
459 {
460  const unsigned ncomp =
462 
463  if (// rhs has just 1 plane
464  rhs_base.nplanes() == 1 &&
465  // both sides have equal component types
466  vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_UINT_64)
467  {
468  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
469  const vil_image_view<vxl_uint_64> &rhs = static_cast<const vil_image_view<vxl_uint_64>&>(rhs_base);
470 
472  rhs.ni(),rhs.nj(),ncomp,
473  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
474  return true;
475  }
476  else
477  return false;
478 }
479 
480 template <>
482  const vil_image_view_base &rhs_base)
483 {
484  const unsigned ncomp =
486 
487  if (// rhs has just 1 plane
488  rhs_base.nplanes() == 1 &&
489  // both sides have equal component types
490  vil_pixel_format_component_format(rhs_base.pixel_format()) == VIL_PIXEL_FORMAT_INT_64)
491  {
492  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
493  const vil_image_view<vxl_int_64> &rhs = static_cast<const vil_image_view<vxl_int_64>&>(rhs_base);
494 
496  rhs.ni(),rhs.nj(),ncomp,
497  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
498  return true;
499  }
500  else
501  return false;
502 }
503 
504 #endif // VXL_HAS_INT_64
505 
506 template <>
508  const vil_image_view_base &rhs_base)
509 {
510  const unsigned ncomp =
512 
513  if (// rhs has just 1 plane
514  rhs_base.nplanes() == 1 &&
515  // both sides have equal component types
517  {
518  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
519  const vil_image_view<float> &rhs = static_cast<const vil_image_view<float>&>(rhs_base);
520 
522  rhs.ni(),rhs.nj(),ncomp,
523  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
524  return true;
525  }
526  else
527  return false;
528 }
529 
530 template <>
532  const vil_image_view_base &rhs_base)
533 {
534  const unsigned ncomp =
536 
537  if (// rhs has just 1 plane
538  rhs_base.nplanes() == 1 &&
539  // both sides have equal component types
541  {
542  // cheat by casting to component type, not pixel type (because we don't know full pixel type at compile time.)
543  const vil_image_view<double> &rhs = static_cast<const vil_image_view<double>&>(rhs_base);
544 
546  rhs.ni(),rhs.nj(),ncomp,
547  rhs.istep()*ncomp,rhs.jstep()*ncomp,1);
548  return true;
549  }
550  else
551  return false;
552 }
553 
554 
555 template<class T>
557 {
558  return operator=( static_cast<vil_image_view_base const&>(rhs) );
559 }
560 
561 
562 template<class T>
564 {
565  if (static_cast<const vil_image_view_base*>(this) == &rhs)
566  return *this;
567 
568  if (rhs.pixel_format() == pixel_format())
569  {
570  const vil_image_view<T> &that = static_cast<const vil_image_view<T>&>(rhs);
571  ni_=that.ni_;
572  nj_=that.nj_;
573  nplanes_=that.nplanes_;
574  istep_=that.istep_;
575  jstep_=that.jstep_;
576  planestep_=that.planestep_;
577  top_left_=that.top_left_;
578  ptr_=that.ptr_;
579  return *this;
580  }
581 
582  if (convert_components_from_planes(*this, rhs))
583  return *this;
584 
585  if (convert_planes_from_components(*this, rhs))
586  return *this;
587 
589  rhs.pixel_format(), this->pixel_format(), "vil_image_view::operator =") );
590  set_to_memory(nullptr, 0, 0, 0, 0, 0, 0);
591  return *this;
592 }
593 
594 
595 //=======================================================================
596 
597 
598 template<class T>
599 void vil_image_view<T>::set_size(unsigned n_i, unsigned n_j)
600 {
601  if ( nplanes_ > 0 )
602  set_size(n_i, n_j, nplanes_);
603  else
604  set_size(n_i, n_j, 1);
605 }
606 
607 //: True if data all in one unbroken block and top_left_ptr() is lowest data address
608 template<class T>
610 {
611  // For a contiguous image, the smallest step size should be 1, the
612  // next step size should be the width of corresponding to the
613  // smallest step size, and so on. So, sort the step sizes and check
614  // if this is the case.
615 
616  // Sort the step sizes in ascending order, and keep the
617  // corresponding widths.
618 
619  std::ptrdiff_t s1, s2, s3;
620  unsigned n1, n2;
621  if ( istep_ < jstep_ )
622  if ( jstep_ < planestep_ )
623  {
624  s1 = istep_; s2 = jstep_; s3 = planestep_;
625  n1 = ni_; n2 = nj_; // n3 = nplanes_;
626  }
627  else // planestep_ < jstep_
628  if ( istep_ < planestep_ )
629  {
630  s1 = istep_; s2 = planestep_; s3 = jstep_;
631  n1 = ni_; n2 = nplanes_; // n3 = nj_;
632  }
633  else // planestep_ < istep_
634  {
635  s1 = planestep_; s2 = istep_; s3 = jstep_;
636  n1 = nplanes_; n2 = ni_; // n3 = nj_;
637  }
638  else // jstep < istep_
639  if ( jstep_ < planestep_ )
640  if ( istep_ < planestep_ )
641  {
642  s1 = jstep_; s2 = istep_; s3 = planestep_;
643  n1 = nj_; n2 = ni_; // n3 = nplanes_;
644  }
645  else // planestep_ < istep_
646  {
647  s1 = jstep_; s2 = planestep_; s3 = istep_;
648  n1 = nj_; n2 = nplanes_; // n3 = ni_;
649  }
650  else // planestep_ < jstep_
651  {
652  s1 = planestep_; s2 = jstep_; s3 = istep_;
653  n1 = nplanes_; n2 = nj_; // n3 = ni_;
654  }
655 
656  return s1 == 1 &&
657  s2 > 0 && unsigned(s2) == n1 &&
658  s3 > 0 && unsigned(s3) == n1*n2;
659 }
660 
661 //=======================================================================
662 
663 template<class T>
664 void vil_image_view<T>::set_size(unsigned n_i, unsigned n_j, unsigned n_planes)
665 {
666  if (n_i==ni_ && n_j==nj_ && n_planes==nplanes_) return;
667 
668  release_memory();
669 
671  ptr_ = new vil_memory_chunk(sizeof(T)*n_planes*n_j*n_i,
673 
674  ni_ = n_i;
675  nj_ = n_j;
676  nplanes_ = n_planes;
677  // When the image view was in interleaved mode before entering this function,
678  // check whether the new number of planes is the same as the istep_.
679  // If the two agree, remain in the interleaved mode, which is desired by the constructor.
680  // Otherwise, make istep_=1 and thus no longer interleaved.
681  if (istep_==0 || int(istep_) != int(n_planes)) istep_ = 1;
682  jstep_ = n_i*istep_;
683  planestep_ = istep_==1 ? n_i*n_j : 1;
684 
685  top_left_ = reinterpret_cast<T*>(ptr_->data());
686  assert( (istep_==1 && (int)planestep_==int(n_i*n_j)) || (planestep_==1 && (int)istep_==(int)n_planes) );
687 }
688 
689 
690 //: Set this view to look at someone else's memory.
691 template<class T>
692 void vil_image_view<T>::set_to_memory(const T* top_left,
693  unsigned n_i, unsigned n_j, unsigned n_planes,
694  std::ptrdiff_t i_step, std::ptrdiff_t j_step, std::ptrdiff_t plane_step)
695 {
696  release_memory();
697  top_left_ = const_cast<T*>(top_left); // Remove const, as view may end up manipulating data
698 
699  ni_ = n_i;
700  nj_ = n_j;
701  nplanes_ = n_planes;
702  istep_ = i_step;
703  jstep_ = j_step;
704  planestep_ = plane_step;
705 }
706 
707 
708 //=======================================================================
709 //: Fill view with given value
710 template<class T>
712 {
713  T* plane = top_left_;
714 
715  if (is_contiguous())
716  {
717  std::fill(begin(), end(), value);
718  return;
719  }
720 
721  if (istep_==1)
722  {
723  for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
724  {
725  T* row = plane;
726  for (unsigned int j=0;j<nj_;++j,row += jstep_)
727  {
728  int i = ni_;
729  while (i!=0) { row[--i]=value; }
730  }
731  }
732  return;
733  }
734 
735  if (jstep_==1)
736  {
737  for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
738  {
739  T* col = plane;
740  for (unsigned int i=0;i<ni_;++i,col += istep_)
741  {
742  int j = nj_;
743  while (j!=0) { col[--j]=value; }
744  }
745  }
746  return;
747  }
748 
749  for (unsigned int p=0;p<nplanes_;++p,plane += planestep_)
750  {
751  T* row = plane;
752  for (unsigned int j=0;j<nj_;++j,row += jstep_)
753  {
754  T* p = row;
755  for (unsigned int i=0;i<ni_;++i,p+=istep_) *p = value;
756  }
757  }
758 }
759 
760 //=======================================================================
761 
762 template<class T>
763 bool vil_image_view<T>::is_class(std::string const& s) const
764 {
766 }
767 
768 //=======================================================================
769 
770 template<class T>
771 void vil_image_view<T>::print(std::ostream& os) const
772 {
773  os<<nplanes_<<" planes, each "<<ni_<<" x "<<nj_;
774 }
775 
776 //=======================================================================
777 //: True if they share same view of same image data.
778 // This does not do a deep equality on image data. If the images point
779 // to different image data objects that contain identical images, then
780 // the result will still be false.
781 template<class T>
783 {
784  if (rhs.pixel_format() != pixel_format()) return false;
785 
786  const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
787 
788  if (this == &other) return true;
789 
790  if (!(bool) *this && !(bool)other) return true;
791  return ptr_ == other.ptr_ &&
792  top_left_ == other.top_left_ &&
793  nplanes_ == other.nplanes_ &&
794  ni_ == other.ni_ &&
795  nj_ == other.nj_ &&
796  (nplanes_ <= 1 || planestep_ == other.planestep_) &&
797  istep_ == other.istep_ &&
798  jstep_ == other.jstep_;
799 }
800 
801 //=======================================================================
802 //: Provides an ordering.
803 // Useful for ordered containers.
804 // There is no guaranteed meaning to the less than operator, except that
805 // (a<b && b<a) is false and !(a<b) && !(b<a) is equivalent to a==b
806 template<class T>
808 {
809  if (rhs.pixel_format() != pixel_format()) return pixel_format() < rhs.pixel_format();
810 
811  const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
812  if (ptr_ != other.ptr_) return ptr_<other.ptr_;
813  if (!(bool) *this && !(bool)other) return false;
814  if (nplanes_ != other.nplanes_) return nplanes_ < other.nplanes_;
815  if (ni_ != other.ni_) return ni_ < other.ni_;
816  if (nj_ != other.nj_) return nj_ < other.nj_;
817  if (planestep_ != other.planestep_) return planestep_ < other.planestep_;
818  if (istep_ != other.istep_) return istep_ < other.istep_;
819  return jstep_ < other.jstep_;
820 }
821 
822 
823 //=======================================================================
824 //: Provides an ordering.
825 // Useful for ordered containers.
826 // There is no guaranteed meaning to the less than operator, except that
827 // (a>b) is equivalent to (b<a)
828 template<class T>
830 {
831  if (rhs.pixel_format() != pixel_format()) return pixel_format() > rhs.pixel_format();
832 
833  const vil_image_view<T> & other = static_cast<const vil_image_view<T> &>(rhs);
834 
835  if (this == &other) return false;
836 
837  if (ptr_ != other.ptr_) return ptr_>other.ptr_;
838  if (!(bool) *this && !(bool)other) return false;
839  if (nplanes_ != other.nplanes_) return nplanes_ > other.nplanes_;
840  if (ni_ != other.ni_) return ni_ > other.ni_;
841  if (nj_ != other.nj_) return nj_ > other.nj_;
842  if (planestep_ != other.planestep_) return planestep_ > other.planestep_;
843  if (istep_ != other.istep_) return istep_ > other.istep_;
844  return jstep_ > other.jstep_;
845 }
846 
847 
848 //=======================================================================
849 //: True if the actual images are identical.
850 // $\bigwedge_{i,j,p} {\textstyle src}(i,j,p) == {\textstyle dest}(i,j,p)$
851 // The data may be formatted differently in each memory chunk.
852 // O(size).
853 // \relatesalso vil_image_view
854 template<class T>
856  const vil_image_view<T> &rhs)
857 {
858  if (lhs.nplanes() != rhs.nplanes() ||
859  lhs.nj() != rhs.nj() ||
860  lhs.ni() != rhs.ni())
861  return false;
862 
863  for (unsigned p = 0; p < rhs.nplanes(); ++p)
864  for (unsigned j = 0; j < rhs.nj(); ++j)
865  for (unsigned i = 0; i < rhs.ni(); ++i)
866  if (!(rhs(i,j,p) == lhs(i,j,p)))
867  return false;
868  return true;
869 }
870 
871 //=======================================================================
872 
873 // Specializations must be declared in all translation units where
874 // they are used. Since we do not know what instantiations will be
875 // defined, and each requires a specialization, we define the primary
876 // template of is_a to call a function that will be declared and
877 // specialized only in the instantiation translation units.
878 template <class T> std::string vil_image_view_type_name(T*);
879 
880 template <class T>
881 std::string vil_image_view<T>::is_a() const
882 {
883  return vil_image_view_type_name(static_cast<T*>(nullptr));
884 }
885 
886 #define VIL_IMAGE_VIEW_INSTANTIATE(T) \
887 template <> std::string vil_image_view_type_name(T*) \
888 { return std::string("vil_image_view<" #T ">"); } \
889 template class vil_image_view<T >; \
890 template bool vil_image_view_deep_equality(const vil_image_view<T >&, \
891  const vil_image_view<T >&)
892 
893 #endif // vil_image_view_hxx_
unsigned ni_
Number of columns.
An abstract base class of smart pointers to actual image data in memory.
virtual bool is_class(std::string const &s) const
True if this is (or is derived from) class s.
vil_pixel_format
Describes the type of the concrete data.
vil_pixel_format vil_pixel_format_component_format(enum vil_pixel_format f)
Return the number of components in pixel format f.
std::ptrdiff_t istep_
Add this to a pixel pointer to move one column left.
bool convert_planes_from_components(vil_image_view< T > &, const vil_image_view_base &)
Convert components to planes from planes, or do nothing if types are wrong.
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
void fill(T value)
Fill view with given value.
bool is_contiguous() const
True if data all in one unbroken block and top_left_ptr() is lowest data address.
bool convert_components_from_planes(vil_image_view< T > &lhs, const vil_image_view_base &rhs_base)
Convert planes to components from planes, or do nothing if types are wrong.
void set_size(unsigned ni, unsigned nj) override
resize current planes to ni x nj.
Exceptions thrown by vil, and a mechanism for turning them off.
std::ptrdiff_t planestep_
Add this to a pixel pointer to move one plane back.
std::ptrdiff_t jstep() const
Add this to your pixel pointer to get next j pixel.
bool vil_image_view_deep_equality(const vil_image_view< T > &lhs, const vil_image_view< T > &rhs)
True if the actual images are identical.
bool operator<(const vil_image_view_base &rhs) const
Provides an ordering.
vil_memory_chunk_sptr ptr_
Reference to actual image data.
unsigned ni() const
Width.
iterator end()
unsigned nj() const
Height.
virtual enum vil_pixel_format pixel_format() const =0
Return a description of the concrete data pixel type.
std::ptrdiff_t planestep() const
Add this to your pixel pointer to get pixel on next plane.
iterator begin()
bool operator>(const vil_image_view_base &rhs) const
Provides an ordering.
unsigned vil_pixel_format_num_components(enum vil_pixel_format f)
Return the number of components in pixel format f.
void deep_copy(const vil_image_view< T > &src)
Make a copy of the data in src and set this to view it.
void print(std::ostream &) const override
Print a 1-line summary of contents.
Indicates that a function call failed because the pixel types were incompatible.
Definition: vil_exception.h:47
unsigned nplanes_
Number of planes.
A base class reference-counting view of some image data.
bool const * const_iterator
unsigned long size() const
The number of pixels.
std::string is_a() const override
Return class name.
Ref. counted block of data on the heap.
std::ptrdiff_t jstep_
Add this to a pixel pointer to move one row down.
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
This is the appropriate pixel type for RGBA colour images.
Definition: vil_fwd.h:15
unsigned nplanes() const
Number of planes.
void set_to_memory(const T *top_left, unsigned ni, unsigned nj, unsigned nplanes, std::ptrdiff_t i_step, std::ptrdiff_t j_step, std::ptrdiff_t plane_step)
Set this view to look at someone else's memory data.
std::string vil_image_view_type_name(T *)
const vil_memory_chunk_sptr & memory_chunk() const
Smart pointer to the object holding the data for this view.
void vil_exception_warning(T exception)
Throw an exception indicating a potential problem.
Definition: vil_exception.h:37
unsigned nj_
Number of rasters.
vil_image_view()
Dflt ctor.
bool is_class(std::string const &s) const override
True if this is (or is derived from) class s.
T * top_left_
Pointer to pixel at origin.
const vil_image_view< T > & operator=(const vil_image_view< T > &rhs)
Copy a view. The rhs and lhs will point to the same image data.
bool operator==(const vil_image_view_base &other) const
True if they share same view of same image data.
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
vil_pixel_format vil_pixel_format_of(T)
The pixel format enumeration corresponding to the C++ type.
This is the appropriate pixel type for 24-bit colour images.
Definition: vil_fwd.h:14