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