1 // This is core/vil/vil_image_view.h
2 #ifndef vil_image_view_h_
3 #define vil_image_view_h_
4 //:
5 // \file
6 // \brief A base class reference-counting view of some image data.
7 // \author Ian Scott - Manchester
8 // \verbatim
9 //  Modifications
10 //   Peter Vanroose - 21 Aug.2003 - support added for interleaved planes
11 // \endverbatim
12 
13 #include <iosfwd>
14 #include <string>
15 #include <cstddef>
16 #ifdef _MSC_VER
17 #  include <vcl_msvc_warnings.h>
18 #endif
19 #include <cassert>
20 #include "vil_image_view_base.h"
21 #include "vil_memory_chunk.h"
22 #include "vil_pixel_format.h"
23 
24 
25 //: Concrete view of image data of type T held in memory
26 //  Views nplanes() planes of data each of size ni() x nj().
27 //  The (i,j) element of the p'th plane is given by
28 //  im.top_left_ptr()[i*im.istep() + j*im.jstep() + p*im.planestep]
29 //  The actual image data is either allocated by the class
30 //  (using set_size), in which case it is deleted
31 //  only when it has no views observing it, or is allocated outside (and is not
32 //  deleted on destruction).  This allows external images to be accessed
33 //  without a deep copy.
34 //
35 //  Note that copying one vil_image_view<T> to another takes a shallow
36 //  copy by default - it copies the view, not the raw image data.
37 //  Use the explicit deep_copy() call to take a deep copy.
38 
39 template <class T>
40 class vil_image_view : public vil_image_view_base
41 {
42  private:
43 
44  protected:
45   //: Pointer to pixel at origin.
46   T * top_left_;
47   //: Add this to a pixel pointer to move one column left.
48   std::ptrdiff_t istep_{0};
49   //: Add this to a pixel pointer to move one row down.
50   std::ptrdiff_t jstep_{0};
51   //: Add this to a pixel pointer to move one plane back.
52   std::ptrdiff_t planestep_{0};
53 
54   //: Reference to actual image data.
55   vil_memory_chunk_sptr ptr_;
56 
57   //: Disconnect this view from the underlying data,
release_memory()58   void release_memory() { ptr_ = nullptr; }
59 
60  public:
61   //: Dflt ctor
62   //  Creates an empty one-plane image.
vil_image_view()63    vil_image_view() : top_left_(nullptr) {}
64 
65    //: Create an image of ni x nj pixels in (n_planes * n_interleaved_planes)
66    //planes
67    //  If n_interleaved_planes > 1, the planes are interleaved.
68    //  If n_planes > 1, each plane of pixels is stored contiguously.
69    //  n_planes and n_interleaved_planes should not be both different from 1.
70    //  n_planes * n_interleaved_planes should be 1 unless T is scalar.
71    vil_image_view(unsigned ni, unsigned nj, unsigned n_planes = 1,
72                   unsigned n_interleaved_planes = 1);
73 
74    //: Set this view to look at someone else's memory data.
75    //  If the data goes out of scope then this view could be invalid, and
76    //  there's no way of knowing until it's too late - so take care!
77    vil_image_view(const T *top_left, unsigned ni, unsigned nj, unsigned nplanes,
78                   std::ptrdiff_t i_step, std::ptrdiff_t j_step,
79                   std::ptrdiff_t plane_step);
80 
81    //: Set this view to look at another view's data
82    //  Typically used by functions which generate a manipulated view of
83    //  another's image data.
84    //  Need to pass the memory chunk to set up the internal smart ptr
85    //  appropriately
86    vil_image_view(const vil_memory_chunk_sptr &mem_chunk, const T *top_left,
87                   unsigned ni, unsigned nj, unsigned nplanes,
88                   std::ptrdiff_t i_step, std::ptrdiff_t j_step,
89                   std::ptrdiff_t plane_step);
90 
91    //: Copy constructor.
92    // The new object will point to the same underlying image as the rhs.
93    vil_image_view(const vil_image_view<T> &rhs);
94 
95    //: Construct from various vil_image_view types.
96    // The new object will point to the same underlying image as the rhs
97    // You can assign a vil_image_view<compound_type<T>> to a vil_image_view<T>
98    // in all reasonable cases - the lhs will have as many planes as the rhs has
99    // components. You can assign a vil_image_view<T> to a
100    // vil_image_view<compound_type<T>> when the underlying data is formatted
101    // appropriately and the lhs has as many components as the rhs has planes.
102    // O(1). If the view types are not compatible this object will be set to
103    // empty.
104    vil_image_view(const vil_image_view_base &rhs);
105 
106    //: Construct from various vil_image_view types.
107    // The new object will point to the same underlying image as the rhs.
108    //
109    // You can assign a vil_image_view<compound_type<T>> to a vil_image_view<T>
110    // in all reasonable cases - the lhs will have as many planes as the rhs has
111    // components. You can assign a vil_image_view<T> to a
112    // vil_image_view<compound_type<T>> when the underlying data is formatted
113    // appropriately and the lhs has as many components as the rhs has planes.
114    // O(1). \throws vil_exception_pixel_formats_incompatible if view types are
115    // not compatible. Or returns a null image if exceptions are disabled.
116    vil_image_view(const vil_image_view_base_sptr &rhs);
117 
118    //  Destructor
119    ~vil_image_view() override = default;
120 
121    // === Standard container stuff ===
122    // This assumes that the data is arranged contiguously.
123    // Is this assumption good?
124 
125    //: The pixel type of this image
126    typedef T pixel_type;
127 
128    //: True if data all in one unbroken block and top_left_ptr() is lowest data
129    //address
130    bool is_contiguous() const;
131 
132    // === iterators ===
133 
134    typedef T *iterator;
begin()135    inline iterator begin() {
136      assert(is_contiguous());
137      return top_left_; }
end()138   inline iterator end  () { assert(is_contiguous()); return top_left_ + size(); }
139 
140   typedef T const *const_iterator;
begin()141   inline const_iterator begin() const { assert(is_contiguous()); return top_left_; }
end()142   inline const_iterator end  () const { assert(is_contiguous()); return top_left_ + size(); }
143 
144   // === arithmetic indexing stuff ===
145 
146   //: Pointer to the first (top left in plane 0) pixel.
147   //  Note that this is not necessarily the lowest data memory address.
top_left_ptr()148   inline T * top_left_ptr() { return top_left_; }  // Make origin explicit
149   //: Pointer to the first (top left in plane 0) pixel.
150   //  Note that this is not necessarily the lowest data memory address.
top_left_ptr()151   inline const T * top_left_ptr() const { return top_left_; }
152 
153   //: Add this to your pixel pointer to get next i pixel.
154   //  Note that istep() may well be negative; see e.g. vil_flip_lr
istep()155   inline std::ptrdiff_t istep() const { return istep_; }
156   //: Add this to your pixel pointer to get next j pixel.
157   //  Note that jstep() may well be negative; see e.g. vil_flip_ud
jstep()158   inline std::ptrdiff_t jstep() const { return jstep_; }
159   //: Add this to your pixel pointer to get pixel on next plane.
160   //  Note that planestep() may well be negative, e.g. with BMP file images
planestep()161   inline std::ptrdiff_t planestep() const { return planestep_; }
162 
163   //: Cast to bool is true if pointing at some data.
164   /* The old 'safe_bool' did implicit conversions, best practice would be to use explicit operator bool */
165   operator bool() const
166   { return (top_left_ != nullptr)? true : false; }
167 
168   //: Return false if pointing at some data.
169   bool operator!() const
170   { return (top_left_ != nullptr)? false : true; }
171 
172   //: The number of bytes in the data
size_bytes()173   inline unsigned size_bytes() const { return size() * sizeof(T); }
174 
175   //: Smart pointer to the object holding the data for this view
176   // Will be a null pointer if this view looks at `third-party' data,
177   // e.g. using set_to_memory.
178   //
179   // Typically used when creating new views of the data
memory_chunk()180   inline const vil_memory_chunk_sptr& memory_chunk() const { return ptr_; }
181 
182   //: Smart pointer to the object holding the data for this view
183   // Will be a null pointer if this view looks at `third-party' data,
184   // e.g. using set_to_memory
185   //
186   // Typically used when creating new views of the data
memory_chunk()187   inline vil_memory_chunk_sptr& memory_chunk() { return ptr_; }
188 
189   // === Ordinary image indexing stuff. ===
190 
191   //: Return true if (i,j) is a valid index into this buffer.
in_range(int i,int j)192   inline bool in_range(int i, int j) const
193   { return (i>-1) && (i<(int)ni_) && (j>-1) && (j<(int)nj_); }
194 
195   //: Return true if (i,j,p) is a valid index into this buffer.
in_range(int i,int j,int p)196   inline bool in_range(int i, int j, int p) const
197   { return (i>-1) && (i<(int)ni_) && (j>-1) && (j<(int)nj_)
198            && (p>-1) && (p<(int)nplanes_); }
199 
200   //: Return read-only reference to pixel at (i,j) in plane 0.
operator()201   inline const T& operator()(unsigned i, unsigned j) const {
202     assert(i<ni_); assert(j<nj_);
203     return top_left_[jstep_*j+i*istep_]; }
204 
205   //: Return read/write reference to pixel at (i,j) in plane 0.
operator()206   inline T&       operator()(unsigned i, unsigned j) {
207     assert(i<ni_); assert(j<nj_);
208     return top_left_[istep_*i+j*jstep_]; }
209 
210   //: Return read-only reference to pixel at (i,j) in plane p.
operator()211   inline const T& operator()(unsigned i, unsigned j, unsigned p) const {
212     assert(i<ni_); assert(j<nj_); assert(p<nplanes_);
213     return top_left_[p*planestep_ + j*jstep_ + i*istep_]; }
214 
215   //: Return read-only reference to pixel at (i,j) in plane p.
operator()216   inline T&       operator()(unsigned i, unsigned j, unsigned p) {
217     assert(i<ni_); assert(j<nj_); assert(p<nplanes_);
218     return top_left_[p*planestep_ + j*jstep_ + i*istep_]; }
219 
220   // === image stuff ===
221 
222   //: resize current planes to ni x nj
223   // If already correct size, this function returns quickly
224   void set_size(unsigned ni, unsigned nj) override;
225 
226   //: resize to ni x nj x nplanes
227   // If already correct size, this function returns quickly
228   void set_size(unsigned ni, unsigned nj, unsigned nplanes) override;
229 
230   //: Make a copy of the data in src and set this to view it
231   void deep_copy(const vil_image_view<T>& src);
232 
233   //: Make empty.
234   // Disconnects view from underlying data.
clear()235   inline void clear() { release_memory(); ni_=nj_=nplanes_=0; top_left_=nullptr; istep_=jstep_=planestep_=0; }
236 
237   //: Set this view to look at someone else's memory data.
238   //  If the data goes out of scope then this view could be invalid, and
239   //  there's no way of knowing until it's too late -- so take care!
240   //
241   //  Note that though top_left is passed in as const, the data may be manipulated
242   //  through the view.
243   void set_to_memory(const T* top_left, unsigned ni, unsigned nj, unsigned nplanes,
244                      std::ptrdiff_t i_step, std::ptrdiff_t j_step, std::ptrdiff_t plane_step);
245 
246   //: Fill view with given value
247   void fill(T value);
248 
249   //: Print a 1-line summary of contents
250   void print(std::ostream&) const override;
251 
252   //: Return class name
253   std::string is_a() const override;
254 
255   //: True if this is (or is derived from) class s
256   bool is_class(std::string const& s) const override;
257 
258   //: Return a description of the concrete data pixel type.
259   // The value corresponds directly to pixel_type.
pixel_format()260   inline vil_pixel_format pixel_format() const override { return vil_pixel_format_of(T()); }
261 
262   //: True if they share same view of same image data.
263   //  This does not do a deep equality on image data. If the images point
264   //  to different image data objects that contain identical images, then
265   //  the result will still be false.
266   bool operator==(const vil_image_view_base& other) const;
267 
268   //: True if they do not share same view of same image data.
269   //  This does not do a deep inequality on image data. If the images point
270   //  to different image data objects that contain identical images, then
271   //  the result will still be true.
272   inline bool operator!=(const vil_image_view_base& rhs) const { return !operator==(rhs); }
273 
274   //: Provides an ordering.
275   //  Useful for ordered containers.
276   //  There is no guaranteed meaning to the less than operator, except that
277   //  (a<b && b<a)  is false and  !(a<b) && !(b<a)  is equivalent to  a==b
278   bool operator<(const vil_image_view_base& rhs) const;
279 
280   //: Provides an ordering.
281   inline bool operator>=(const vil_image_view_base& rhs) const { return !operator<(rhs); }
282 
283   //: Provides an ordering.
284   bool operator>(const vil_image_view_base& rhs) const;
285 
286   //: Provides an ordering.
287   inline bool operator<=(const vil_image_view_base & rhs) const { return !operator>(rhs); }
288 
289   //: Copy a view. The rhs and lhs will point to the same image data.
290   const vil_image_view<T>& operator=(const vil_image_view<T>& rhs);
291 
292   //: Copy a view. The rhs and lhs will point to the same image data.
293   // You can assign a vil_image_view<compound_type<T>> to a vil_image_view<T>
294   // in all reasonable cases - the lhs will have as many planes as the rhs has
295   // components. You can assign a vil_image_view<T> to a vil_image_view<compound_type<T>>
296   // when the underlying data is formatted appropriately and the lhs has
297   // as many components as the rhs has planes. O(1).
298   // If the view types are not compatible this object will be set to empty.
299   const vil_image_view<T>& operator=(const vil_image_view_base & rhs);
300 
301   //: Copy a view. The rhs and lhs will point to the same image data.
302   // You can assign a vil_image_view<compound_type<T>> to a vil_image_view<T>
303   // in all reasonable cases - the lhs will have as many planes as the rhs has
304   // components. You can assign a vil_image_view<T> to a vil_image_view<compound_type<T>>
305   // when the underlying data is formatted appropriately and the lhs has
306   // as many components as the rhs has planes. O(1).
307   // If the view types are not compatible this object will be set to empty.
308   // If the pointer is null, this object will be set to empty.
309   // See also vil_convert_to_component_order().
310   inline const vil_image_view<T>& operator=(const vil_image_view_base_sptr& rhs)
311   {
312     if (!rhs) clear();
313     else *this = *rhs;
314     return *this;
315   }
316 };
317 
318 //: Print a 1-line summary of contents
319 template <class T>
320 inline
321 std::ostream& operator<<(std::ostream& s, vil_image_view<T> const& im)
322 {
323   im.print(s); return s;
324 }
325 
326 //: True if the actual images are identical.
327 // $\bigwedge_{i,j,p} {\textstyle src}(i,j,p) == {\textstyle dest}(i,j,p)$
328 // The data may be formatted differently in each memory chunk.
329 //  O(size).
330 // \relatesalso vil_image_view
331 template<class T>
332 bool vil_image_view_deep_equality(const vil_image_view<T> &lhs, const vil_image_view<T> &rhs);
333 
334 #endif // vil_image_view_h_
335