OPAL
Image.h
1 #pragma once
2 
3 #include <stdexcept>
4 #include <cassert>
5 #include <iostream>
6 #include <vector>
7 #include <string>
8 
9 
10 template <class T>
11 class Image {
12 public:
13  using PixelType = T;
14 
15  Image() : Height(0), Width(0), data() {}
16 
17  // Creates a new image and fills it with \p value.
18  Image(size_t h, size_t w, const T &value = T())
19  : Height(h), Width(w), data(h * w, value)
20  {
21  if (!h || !w)
22  Height = Width = 0;
23  }
24 
25  Image(const Image<T> &other) = default;
26  Image(Image<T> &&other) = default;
27 
28  virtual ~Image() = default;
29 
30 
31  void Resize(size_t h, size_t w, const T &value = T()) {
32  if (!h || !w)
33  Height = Width = 0;
34  else {
35  Height = h;
36  Width = w;
37  }
38  data.resize(Height * Width, value);
39  }
40 
41 
42  // Fill the whole image with the given value.
43  void Fill(const T &value) {
44  for (auto &pixel : data)
45  pixel = value;
46  }
47 
48 
49  // Reads the input stream as plain text image.
50  // Extension of the file name is NOT considered!
51  //
52  // Format:
53  // * 2 integers: height and width respectively;
54  // * <height>*<width> values separated by a whitespace.
55  //
56  // Throws sts::bad_alloc, std::invalid_argument, std ios exceptions.
57  friend std::istream &operator>>(std::istream &is, Image<T> &m) {
58  std::ios_base::sync_with_stdio(false);
59  is.exceptions(std::ios_base::failbit | std::ios_base::badbit);
60 
61  is >> m.Height >> m.Width;
62  m.data.resize(m.Height * m.Width);
63 
64  for (auto &pixel : m.data) {
65  // If stream containes less data than declared - stop reading.
66  if (!is.good())
67  break;
68  is >> pixel;
69  }
70 
71  return is;
72  }
73 
74 
75  friend std::ostream &operator<<(std::ostream &os, const Image<T> &m) {
76  std::ios_base::sync_with_stdio(false);
77  os.exceptions(std::ios_base::failbit | std::ios_base::badbit);
78 
79  os << m.getHeight() << ' ' << m.getWidth() << '\n';
80  for (size_t i = 0; i < m.getHeight(); ++i) {
81  for (size_t j = 0; j < m.getWidth(); ++j) {
82  os << m(i,j) << ' ';
83  }
84  os << '\n';
85  }
86  return os;
87  }
88 
89 
90  inline size_t getHeight() const { return Height; }
91  inline size_t getWidth() const { return Width; }
92  inline size_t getSize() const {
93  assert(data.size() == Height * Width &&
94  "Image size is different than Height * Width!");
95  return data.size();
96  }
97 
98 
99  inline bool isEmpty() const { return data.empty(); }
100 
101 
102  Image<T> &operator=(Image<T> other) {
103  swap(*this, other);
104  return *this;
105  }
106 
107 
108  friend void swap(Image<T> &first, Image<T> &second) {
109  using std::swap;
110  swap(first.Height, second.Height);
111  swap(first.Width, second.Width);
112  swap(first.data, second.data);
113  }
114 
115 
116  template<class U>
117  Image<U> castTo() const {
118  Image<U> result(Height, Width);
119 
120  for (size_t i = 0; i < data.size(); ++i)
121  result[i] = static_cast<U>(data[i]);
122 
123  return result;
124  }
125 
126 
127  bool operator==(const Image<T> &other) const {
128  // Not actually needed check, but let's make this explicit for readability.
129  if (isEmpty() != other.isEmpty())
130  return false;
131  if (Height != other.getHeight() || Width != other.getWidth())
132  return false;
133 
134  for (size_t i = 0; i < data.size(); ++i)
135  if (data[i] != other[i])
136  return false;
137  return true;
138  }
139 
140 
141  bool operator!=(const Image<T> &other) const {
142  return !(*this == other);
143  }
144 
145 
146  Image<T> &operator+=(const Image<T> &other) {
147  assert(Height == other.getHeight() && "Height mismatch!");
148  assert(Width == other.getWidth() && "Width mismatch!");
149 
150  for (size_t i = 0; i < data.size(); ++i)
151  data[i] += other[i];
152 
153  return *this;
154  }
155 
156 
157  Image<T> &operator-=(const Image<T> &other) {
158  assert(Height == other.getHeight() && "Height mismatch!");
159  assert(Width == other.getWidth() && "Width mismatch!");
160 
161  for (size_t i = 0; i < data.size(); ++i)
162  data[i] -= other[i];
163 
164  return *this;
165  }
166 
167 
168  friend Image<T> operator+(Image<T> lhs, const Image<T> &rhs) {
169  lhs += rhs;
170  return lhs;
171  }
172 
173 
174  friend Image<T> operator-(Image<T> lhs, const Image<T> &rhs) {
175  lhs -= rhs;
176  return lhs;
177  }
178 
179 
180 protected:
181  size_t Height;
182  size_t Width;
183  std::vector<T> data;
184 
185 
186 public:
187  auto operator()(size_t i, size_t j) -> decltype(data[0]) {
188  assert(i < Height && "i index out of range!");
189  assert(j < Width && "i index out of range!");
190 
191  return data[i * Width + j];
192  }
193 
194 
195  auto operator()(size_t i, size_t j) const -> decltype(data[0]) {
196  assert(i < Height && "i index out of range!");
197  assert(j < Width && "i index out of range!");
198 
199  return data[i * Width + j];
200  }
201 
202 
203  auto operator[](size_t i) -> decltype(data.at(i)) { return data.at(i); }
204  auto operator[](size_t i) const -> decltype(data.at(i)) { return data.at(i); }
205 
206  auto begin() -> decltype(data.begin()) { return data.begin(); }
207  auto begin() const -> decltype(data.begin()) { return data.begin(); }
208  auto end() -> decltype(data.end()) { return data.end(); }
209  auto end() const -> decltype(data.end()) { return data.end(); }
210 };
211 
Definition: Image.h:11