libcvd
image.h
1 //-*- c++ -*-
3 // //
4 // CVD::image.h //
5 // //
6 // Definitions for of template class CVD::Image, fast_image //
7 // //
8 // derived from IPRS_* developed by Tom Drummond //
9 // Reworked to provide class heirachy and memory managementby E. Rosten//
10 // //
12 
13 #ifndef CVD_IMAGE_H
14 #define CVD_IMAGE_H
15 
16 #include <cstring>
17 #include <cvd/exceptions.h>
18 #include <cvd/image_ref.h>
19 #include <iterator>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 
24 namespace CVD
25 {
26 
27 namespace Exceptions
28 {
29 
31  namespace Image
32  {
35  struct All : public CVD::Exceptions::All
36  {
37  using CVD::Exceptions::All::All;
38  };
39 
42  struct IncompatibleImageSizes : public All
43  {
44  IncompatibleImageSizes(const std::string& function)
45  : All("Incompatible image sizes in " + function) {};
46  };
47 
50  struct ImageRefNotInImage : public All
51  {
52  ImageRefNotInImage(const std::string& function)
53  : All("Input ImageRefs not in image in " + function) {};
54  };
55  }
56 }
57 
58 #ifndef DOXYGEN_IGNORE_INTERNAL
59 namespace Internal
60 {
61  template <class C>
62  struct ImagePromise
63  {
64  };
65 
66  [[noreturn]] void error_abort(const char* f, int l, const char* code);
67 };
68 #endif
69 
70 #ifdef CVD_DEBUG
71 #define CVD_ASSERT(X) \
72  do \
73  { \
74  if(!(X)) \
75  CVD::Internal::error_abort(__FILE__, __LINE__, #X); \
76  } while(0)
77 #elif defined(_MSC_VER)
78 #define CVD_ASSERT(X) __assume(X)
79 #elif defined(__GNUC__) || defined(__clang__)
80 #define CVD_ASSERT(X) \
81  do \
82  { \
83  if(!(X)) \
84  __builtin_unreachable(); \
85  } while(0)
86 #elif
87 #define CVD_ASSERT(X) \
88  do \
89  { \
90  } while(0)
91 #endif
92 
93 #ifdef CVD_IMAGE_DEBUG
94 #define CVD_IMAGE_ASSERT(X, Y) \
95  if(!(X)) \
96  throw Y()
97 #define CVD_IMAGE_ASSERT2(X, Y, Z) \
98  if(!(X)) \
99  throw Y(Z)
100 #else
101 #define CVD_IMAGE_ASSERT(X, Y)
102 #define CVD_IMAGE_ASSERT2(X, Y, Z)
103 #endif
104 
111 namespace ImageError
112 {
117  {
118  };
119 }
120 
121 namespace Internal
122 {
123  template <class T>
124  inline void memfill(T* data, int n, const T val)
125  {
126  T* de = data + n;
127  for(; data < de; data++)
128  *data = val;
129  }
130 
131  template <>
132  inline void memfill(unsigned char* data, int n, const unsigned char val)
133  {
134  memset(data, val, n);
135  }
136 
137  template <>
138  inline void memfill(signed char* data, int n, const signed char val)
139  {
140  memset(data, val, n);
141  }
142 
143  template <>
144  inline void memfill(char* data, int n, const char val)
145  {
146  memset(data, val, n);
147  }
148 
149  //Detecting a typedef...
150  template <class C>
151  struct IsDummy
152  {
153  //Fake function to pretend to return an instance of a type
154  template <class S>
155  static const C& get();
156 
157  //Two typedefs guaranteed to have different sizes
158  typedef char One[1];
159  typedef char Two[2];
160 
161  //Class to give us a size 2 return value or fail on
162  //substituting S
163  template <unsigned long S>
165  {
166  typedef Two Type;
167  };
168 
169  static One& detect_dummy(...);
170 
171  template <class S>
172  static typename SFINAE_dummy<sizeof(typename S::dummy)>::Type& detect_dummy(const S&);
173 
174  static const bool Is = (sizeof(detect_dummy(get<C>())) == 2);
175  };
176 }
177 
178 template <class T>
180 {
181  public:
182  //Make it look like a standard iterator
183  typedef std::forward_iterator_tag iterator_category;
184  typedef T value_type;
185  typedef std::ptrdiff_t difference_type;
186  typedef T* pointer;
187  typedef T& reference;
188 
189  const BasicImageIterator& operator++()
190  {
191  ptr++;
192  if(ptr == row_end)
193  {
194  ptr += row_increment;
195  row_end += total_width;
196 
197  if(ptr >= end)
198  end = NULL;
199  }
200  return *this;
201  }
202 
203  void operator++(int)
204  {
205  operator++();
206  }
207 
208  T* operator->() const { return ptr; }
209  T& operator*() const { return *ptr; }
210 
211  bool operator<(const BasicImageIterator& s) const
212  {
213  //It's illegal to iterate _past_ end(), so < is equivalent to !=
214  //for end iterators.
215  if(is_end && s.is_end)
216  return 0;
217  else if(is_end)
218  return s.end != NULL;
219  else if(s.is_end)
220  return end != NULL;
221  else
222  return ptr < s.ptr;
223  }
224 
225  bool operator==(const BasicImageIterator& s) const
226  {
227  return !((*this) != s);
228  }
229 
230  bool operator!=(const BasicImageIterator& s) const
231  {
232  if(is_end && s.is_end)
233  return 0;
234  else if(is_end)
235  return s.end != NULL;
236  else if(s.is_end)
237  return end != NULL;
238  else
239  return ptr != s.ptr;
240  }
241 
243  {
244  }
245 
246  BasicImageIterator(T* start, int image_width, int row_stride, T* off_end)
247  : ptr(start)
248  , row_end(start + image_width)
249  , end(off_end)
250  , is_end(0)
251  , row_increment(row_stride - image_width)
252  , total_width(row_stride)
253  {
254  }
255 
256  //Prevent automatic conversion from a pointer (ie Image::iterator)
257  explicit BasicImageIterator(T* endptr)
258  : ptr(endptr)
259  , is_end(1)
260  , row_increment(0)
261  , total_width(0)
262  {
263  }
264 
265  protected:
266  T* ptr;
267  T *row_end, *end;
268  bool is_end;
269  int row_increment, total_width;
270 };
271 
272 template <class C>
274 template <class C>
275 using SubImage = BasicImage<C>;
276 
277 namespace Internal
278 {
279 
280  //The structure is a little funny. We use inheritance here as a way of conditional
281  //namespacing. So think of it like that not subclassing :)
282  //
283  //Essentially there are two image "types". One is an image of pixels, and includes
284  //all the per-pixel types like byte, Rgb<byte> float, etc. These have the properties
285  //that there is precisely one element per pixel. That makes pixel access obvious and
286  //straightforward, so slicing (sub images) works fine and so on. Types need not be POD
287  //
288  //The other type is for images of crud. This includes yuv422, yuv420p and MJPEG. These
289  //have no easy way of accessing pixels in general and no wasy way of creating sub images.
290  //Technically, the types like YUV422 can be sub-imaged and have strides, but I've got no
291  //use case for that and no one wants it.
292  //
293  //Silly types have a typedef called "dummy" because they're a placeholder and so don't
294  //actually represent the underlying data.
295  //
296  //Dummy types are usually of fixed size (e.g. yuv types) and so the size is/should be known
297  //at compile time. In this case, the dummy struct must provide a std::ratio called bytes_per_pixel
298 
299  //This is the image data holder for silly types lilke
300  template <class T, bool D = Internal::IsDummy<T>::Is>
301  class ImageData
302  {
303  public:
304  ImageData(const ImageData&) = default;
305  ImageData& operator=(const ImageData&) = default;
306 
307  ImageData(void* data, size_t len, ImageRef sz)
308  : my_data(data)
309  , my_size(sz)
310  , data_length(len)
311  {
312  }
313 
314  ImageData(void* data, ImageRef sz)
315  : my_data(data)
316  , my_size(sz)
317  , data_length(T::bytes_per_pixel::num * sz.area() / T::bytes_per_pixel::den)
318  {
319  }
320 
322  inline size_t datalength() const
323  {
324  return data_length;
325  }
326 
327  ImageData()
328  {
329  my_data = 0;
330  my_size = ImageRef(0, 0);
331  data_length = 0;
332  }
333 
334  protected:
335  void* my_data;
336  ImageRef my_size;
337  size_t data_length;
338 
339  using PointerType = void*;
340  using ConstPointerType = const void*;
341  };
342 
343  template <class T>
344  class ImageData<T, false>
345  {
346  public:
350  ImageData(T* data, const ImageRef& size)
351  : my_data(data)
352  , my_size(size)
353  , my_stride(size.x)
354  {
355  }
356 
361  ImageData(T* data, const ImageRef& size, int stride)
362  : my_data(data)
363  , my_size(size)
364  , my_stride(stride)
365  {
366  }
367 
368  //We need them here in order to provide the functionality for
369  //the asserts below. Technically they can apply to dummy types but
370  //why bother?
371 
374  bool in_image(const ImageRef& ir) const
375  {
376  return ir.x >= 0 && ir.y >= 0 && ir.x < my_size.x && ir.y < my_size.y;
377  }
378 
382  bool in_image_with_border(const ImageRef& ir, int border) const
383  {
384  return ir.x >= border && ir.y >= border && ir.x < my_size.x - border && ir.y < my_size.y - border;
385  }
386 
390  inline T& operator[](const ImageRef& pos)
391  {
392  CVD_IMAGE_ASSERT(in_image(pos), ImageError::AccessOutsideImage);
393  return (my_data[pos.y * my_stride + pos.x]);
394  }
395 
399  inline const T& operator[](const ImageRef& pos) const
400  {
401  CVD_IMAGE_ASSERT(in_image(pos), ImageError::AccessOutsideImage);
402  return (my_data[pos.y * my_stride + pos.x]);
403  }
404 
409  inline T* operator[](int row)
410  {
411  CVD_IMAGE_ASSERT(in_image(ImageRef(0, row)), ImageError::AccessOutsideImage);
412  return my_data + row * my_stride;
413  }
414 
419  inline const T* operator[](int row) const
420  {
421  CVD_IMAGE_ASSERT(in_image(ImageRef(0, row)), ImageError::AccessOutsideImage);
422  return my_data + row * my_stride;
423  }
424 
426  inline ImageRef pos(const T* ptr) const
427  {
428  int diff = ptr - my_data;
429  return ImageRef(diff % my_stride, diff / my_size.x);
430  }
431 
434 
436  typedef T value_type;
437 
439  inline iterator begin()
440  {
441  return BasicImageIterator<T>(my_data, my_size.x, my_stride, end_ptr());
442  }
444  inline const_iterator begin() const
445  {
446  return BasicImageIterator<const T>(my_data, my_size.x, my_stride, end_ptr());
447  }
448 
450  inline iterator end()
451  {
452  //Operator [] would always throw here!
453  return BasicImageIterator<T>(end_ptr());
454  }
456  inline const_iterator end() const
457  {
458  //Operator [] would always throw here!
459  return BasicImageIterator<const T>(end_ptr());
460  }
461 
463  inline int row_stride() const
464  {
465  return my_stride;
466  }
467 
471  BasicImage<T> sub_image(const ImageRef& start, const ImageRef& size);
472 
476  const BasicImage<T> sub_image(const ImageRef& start, const ImageRef& size) const;
477 
478  ImageData(const ImageData&) = default;
479  ImageData& operator=(const ImageData&) = default;
480 
481  ImageData()
482  {
483  my_data = nullptr;
484  my_size = ImageRef(0, 0);
485  my_stride = 0;
486  }
487 
488  protected:
490  T* end_ptr() { return my_data + my_size.y * my_stride; }
491 
493  const T* end_ptr() const { return my_data + my_size.y * my_stride; }
494 
495  T* my_data;
496  ImageRef my_size;
497  int my_stride;
498  using PointerType = T*;
499  using ConstPointerType = const T*;
500  };
501 
502 }
503 
514 template <class T>
515 class BasicImage : public Internal::ImageData<T>
516 {
517  static const bool IsDummy = Internal::IsDummy<T>::Is;
518 
519  protected:
522  using typename Internal::ImageData<T>::PointerType;
523  using typename Internal::ImageData<T>::ConstPointerType;
524 
525  public:
526  //Inherit all constructors
528 
530  virtual ~BasicImage()
531  {
532  }
533 
535  inline ConstPointerType data() const
536  {
537  return my_data;
538  }
539 
541  inline PointerType data()
542  {
543  return my_data;
544  }
545 
546  inline void copy_from(const BasicImage<T>& other)
547  {
548  CVD_IMAGE_ASSERT2(other.size() == this->size(), Exceptions::Image::IncompatibleImageSizes, "copy_from");
549  for(int y = 0; y < my_size.y; y++)
550  if constexpr(std::is_trivially_copyable_v<T>)
551  std::memcpy((*this)[y], other[y], sizeof(T) * my_size.x);
552  else
553  std::copy(other[y], other[y] + my_size.x, (*this)[y]);
554  }
555 
557  inline ImageRef size() const
558  {
559  return my_size;
560  }
561 
564  inline void zero()
565  {
566  static_assert(std::is_trivially_copyable<T>::value, "Error: zero() only works on POD types");
567  for(int y = 0; y < my_size.y; y++)
568  memset((*this)[y], 0, sizeof(T) * my_size.x);
569  }
570 
574  inline void fill(const T d)
575  {
576  for(int y = 0; y < my_size.y; y++)
577  Internal::memfill((*this)[y], my_size.x, d);
578  }
579 
582  BasicImage(const BasicImage& copyof) = default;
583 
586  BasicImage& operator=(const BasicImage& copyof) = default;
587 
588  protected:
589  BasicImage() = default;
590 };
591 
592 template <class C>
594 {
595  CVD_IMAGE_ASSERT(in_image(start), ImageError::AccessOutsideImage);
596  CVD_IMAGE_ASSERT(in_image(start + size - ImageRef(1, 1)), ImageError::AccessOutsideImage);
597  return BasicImage<C>(&operator[](start), size, my_stride);
598 }
599 
600 template <class C>
601 const BasicImage<C> Internal::ImageData<C, false>::sub_image(const ImageRef& start, const ImageRef& size) const
602 {
603  CVD_IMAGE_ASSERT(in_image(start), ImageError::AccessOutsideImage);
604  CVD_IMAGE_ASSERT(in_image(start + size - ImageRef(1, 1)), ImageError::AccessOutsideImage);
605 
606  C* ptr = my_data + start.y * my_stride + start.x;
607  return BasicImage<C>(ptr, size, my_stride);
608 }
609 
622 template <class T>
623 class Image : public SubImage<T>
624 {
625  private:
626  struct CopyPlaceHolder
627  {
628  const Image* im;
629  };
630 
631  using SubImage<T>::my_size;
632  //using SubImage<T>::my_stride;
633  using SubImage<T>::my_data;
634 
635  public:
637  typedef T value_type;
638 
639  inline Image& copy_from(const SubImage<T>& other)
640  {
641  resize(other.size());
642  SubImage<T>::copy_from(other);
643  return *this;
644  }
645 
648  Image(const SubImage<T>& i)
649  : Image(i.size())
650  {
651  copy_from(i);
652  }
653 
656  Image(const Image& i)
657  : Image(i.size())
658  {
659  copy_from(i);
660  }
661 
663  Image(Image&& move_from)
664  {
665  static_cast<Internal::ImageData<T>&>(*this) = move_from;
666  move_from.erase_fields();
667  }
668 
671  Image& operator=(const Image& i)
672  {
673  resize(i.size());
674  copy_from(i);
675  return *this;
676  }
677 
678  Image& operator=(Image&& move_from)
679  {
680  if(this != &move_from)
681  {
682  delete_old();
683  static_cast<Internal::ImageData<T>&>(*this) = move_from;
684  move_from.erase_fields();
685  }
686 
687  return *this;
688  }
689 
690 #ifndef DOXYGEN_IGNORE_INTERNAL
691  template <class C>
692  const Image& operator=(Internal::ImagePromise<C> p)
693  {
694  p.execute(*this);
695  return *this;
696  }
697 
698  template <class C>
700  : SubImage<T>()
701  {
702  p.execute(*this);
703  }
704 #endif
705 
708  {
709 
710  erase_fields();
711  }
712 
715  Image(const ImageRef& size)
716  {
717  resize(size);
718  }
719 
723  Image(const ImageRef& size, const T& val)
724  {
725  resize(size);
726  this->fill(val);
727  }
728 
731  void resize(const ImageRef& size)
732  {
733  resize_(size, DD<Internal::IsDummy<T>::Is> {});
734  }
735 
737  //The resized image is filled with val.
740  void resize(const ImageRef& size, const T& val)
741  {
742  resize(size);
743  fill(val);
744  }
745 
748  {
749  delete_old();
750  }
751 
752  private:
753  void delete_old()
754  {
755  delete_(DD<Internal::IsDummy<T>::Is> {});
756  erase_fields();
757  }
758 
759  void erase_fields()
760  {
761  static_cast<Internal::ImageData<T>&>(*this) = Internal::ImageData<T>();
762  }
763 
764  //Allow type switching on dummy data: the internals are quite different
765  //for dummy types.
766  template <int Dummy>
767  struct DD
768  {
769  };
770 
771  template <int Dummy>
772  void resize_(const ImageRef& size, DD<Dummy>)
773  {
774  if(size == ImageRef(0, 0))
775  {
776  delete_old();
777  }
778  else if(size != BasicImage<T>::my_size)
779  {
780  delete_old();
781  static_cast<BasicImage<T>&>(*this) = BasicImage<T>(new T[size.area()], size);
782  }
783  }
784 
785  void resize_(const ImageRef& size, DD<true>)
786  {
787  if(size == ImageRef(0, 0))
788  {
789  delete_old();
790  }
791  else if(size != BasicImage<T>::my_size)
792  {
793  delete_old();
794  static_cast<BasicImage<T>&>(*this) = BasicImage<T>(nullptr, size);
795  my_data = new char[this->datalength()];
796  }
797  }
798 
799  template <int Dummy>
800  void delete_(DD<Dummy>)
801  {
802  delete[] my_data;
803  }
804 
805  void delete_(DD<true>)
806  {
807  delete[] static_cast<char*>(my_data);
808  }
809 };
810 
811 } // end namespace
812 #endif
ImageRef ir(const TooN::Vector< 2 > &v)
Convert a Vector into an image co-ordinate.
Definition: vector_image_ref.h:24
size_t datalength() const
What is the row stride of the image?
Definition: image.h:322
Image(const SubImage< T > &i)
Copy-ish constructor: new allocation and copy the data.
Definition: image.h:648
T value_type
The data type of the pixels in the image.
Definition: image.h:436
constexpr int area() const
Area (product of x and y; signed)
Definition: image_ref.h:213
int row_stride() const
What is the row stride of the image?
Definition: image.h:463
All classes and functions are within the CVD namespace.
Definition: argb.h:6
PointerType data()
Returns the raw image data.
Definition: image.h:541
ImageRef size() const
What is the size of this image?
Definition: image.h:557
const_iterator begin() const
Returns a const iterator referencing the first (top-left) pixel in the image.
Definition: image.h:444
bool in_image_with_border(const ImageRef &ir, int border) const
Is this pixel co-ordinate inside the image, and not too close to the edges?
Definition: image.h:382
void copy(const BasicImage< S > &in, BasicImage< T > &out, ImageRef size=ImageRef(-1, -1), ImageRef begin=ImageRef(), ImageRef dst=ImageRef())
Generic image copy function for copying sub rectangles of images into other images.
Definition: utility.h:30
Image()
Default constructor: everything set to zero.
Definition: image.h:707
Definition: image.h:179
void resize(const ImageRef &size)
Resize the image (destroying the data).
Definition: image.h:731
An attempt was made to access a pixel outside the image.
Definition: image.h:116
~Image()
The destructor removes the image data.
Definition: image.h:747
Image(Image &&move_from)
Move constructor: steal the pointer.
Definition: image.h:663
void zero()
Set image data to all zero bytes.
Definition: image.h:564
Input ImageRef not within image dimensions.
Definition: image.h:50
virtual ~BasicImage()
The image data is not destroyed when a BasicImage is destroyed.
Definition: image.h:530
ImageData(T *data, const ImageRef &size, int stride)
Construct an image from a block of data.
Definition: image.h:361
Definition: image.h:151
ConstPointerType data() const
Returns the raw image data.
Definition: image.h:535
const T & operator[](const ImageRef &pos) const
Access a pixel from the image.
Definition: image.h:399
int x
The x co-ordinate.
Definition: image_ref.h:172
Base class for all CVD exceptions.
Definition: exceptions.h:15
Definition: image.h:301
Definition: image_ref.h:29
Image & operator=(const Image &i)
Copy the data.
Definition: image.h:671
ImageRef pos(const T *ptr) const
Given a pointer, this returns the image position as an ImageRef.
Definition: image.h:426
void resize(const ImageRef &size, const T &val)
Resize the image (destroying the data).
Definition: image.h:740
void fill(const T d)
Set all the pixels in the image to a value.
Definition: image.h:574
iterator begin()
Returns an iterator referencing the first (top-left) pixel in the image.
Definition: image.h:439
Definition: image.h:62
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
ImageData(T *data, const ImageRef &size)
Construct an image from a block of data, assuming tight packing.
Definition: image.h:350
Image(const ImageRef &size, const T &val)
Create a filled image of a given size.
Definition: image.h:723
bool in_image(const ImageRef &ir) const
Is this pixel co-ordinate inside the image?
Definition: image.h:374
int y
The y co-ordinate.
Definition: image_ref.h:173
A full image which manages its own data.
Definition: image.h:623
Input images have incompatible dimensions.
Definition: image.h:42
const T * end_ptr() const
Return an off-the-end pointer without ever throwing AccessOutsideImage.
Definition: image.h:493
Image(const ImageRef &size)
Create an empty image of a given size.
Definition: image.h:715
const T * operator[](int row) const
Access pointer to pixel row.
Definition: image.h:419
T * operator[](int row)
Access pointer to pixel row.
Definition: image.h:409
Base class for all Image_IO exceptions.
Definition: image.h:35
T value_type
The data type of the pixels in the image.
Definition: image.h:637
Image(const Image &i)
Copy constructor: new allocation and copy the data.
Definition: image.h:656
T & operator[](const ImageRef &pos)
Access a pixel from the image.
Definition: image.h:390
T * end_ptr()
Return an off-the-end pointer without ever throwing AccessOutsideImage.
Definition: image.h:490
const_iterator end() const
Returns a const iterator pointing to one past the end of the image.
Definition: image.h:456
iterator end()
Returns an iterator pointing to one past the end of the image.
Definition: image.h:450