farm-ng-core
mut_image_view.h
Go to the documentation of this file.
1 
2 // Copyright (c) 2011, Hauke Strasdat
3 // Copyright (c) 2012, Steven Lovegrove
4 // Copyright (c) 2021, farm-ng, inc.
5 //
6 // Use of this source code is governed by an MIT-style
7 // license that can be found in the LICENSE file or at
8 // https://opensource.org/licenses/MIT.
9 
10 /// ImageView and MutImageView, non owning images types.
11 ///
12 /// See image.h for Image and MutImage, owning images types.
13 ///
14 /// Note that it is a conscious API decision to follow "shallow-compare" type
15 /// semantic for ImageView, MutImageView, Image and MutImage. Similar
16 /// "shallow-compare" types are: std::span (shallow-compare reference type), and
17 /// std::unique_ptr (shallow compare unique ownership type).
18 /// This is in contrast to regular types such as std::vector, std::string and
19 /// reference types which mimic regular type semantic such as std::string_view.
20 /// Also see https://abseil.io/blog/20180531-regular-types.
21 
22 #pragma once
23 
24 #include "sophus/calculus/region.h"
26 
27 namespace sophus {
28 
29 namespace details {
30 
31 void pitchedCopy(
32  uint8_t* dst,
33  size_t dst_pitch_bytes,
34  uint8_t const* src,
35  size_t src_pitch_bytes,
36  sophus::ImageSize size,
37  uint8_t size_of_pixel);
38 }
39 
40 /// View of a mutable image, which does not own the data.
41 ///
42 /// The API of MutImageView allows for read and write access.
43 ///
44 /// MutImageView is nullable. In that case `this->isEmpty()` is true.
45 ///
46 ///
47 /// Details on equality comparison, the state of the object, and
48 /// const-correctness.
49 ///
50 /// MutImageView is a "shallow-compare type" similar to std::span<Pixel> and
51 /// std::unique_ptr<Pixel>. As ImageView, its state consists of the image layout
52 /// as well as the pointer address, and comparing those entities establishes
53 /// equality comparisons. Furthermore, giving mutable access to pixels is
54 /// considered a const operation, as in
55 ///
56 /// ```TPixel& mut(int u, int v) const```
57 ///
58 /// since this merely allows for changing a pixel value, but not its state
59 /// (data location and layout).
60 template <class TPixel>
61 class MutImageView : public ImageView<TPixel> {
62  public:
63  /// Default constructor creates an empty image.
64  MutImageView() = default;
65 
66  /// Creates view from layout and pointer to first pixel.
67  MutImageView(ImageLayout layout, TPixel* ptr) noexcept
69 
70  /// Creates view from image size and pointer to first pixel. The image is
71  /// assumed to be contiguous and the pitch is set accordingly.
72  MutImageView(sophus::ImageSize image_size, TPixel* ptr) noexcept
73  : ImageView<TPixel>(image_size, ptr) {}
74 
75  /// Creates mutable view from view.
76  ///
77  /// It is the user's responsibility to make sure that the data owned by
78  /// the view can be modified safely.
79  [[nodiscard]] static auto unsafeConstCast(ImageView<TPixel> view)
80  -> MutImageView {
81  return MutImageView(view.layout(), const_cast<TPixel*>(view.ptr()));
82  }
83 
84  /// Returns ImageView(*this).
85  ///
86  /// Returns non-mut version of view.
87  [[nodiscard]] auto view() const -> ImageView<TPixel> {
88  return ImageView<TPixel>(this->layout(), this->ptr());
89  }
90 
91  /// Copies data from view into this.
92  ///
93  /// Preconditions:
94  /// * this->isEmpty() == view.isEmpty()
95  /// * this->size() == view.size()
96  ///
97  /// No-op if view is empty.
99  SOPHUS_ASSERT_EQ(this->isEmpty(), view.isEmpty());
100 
101  if (this->isEmpty()) {
102  return;
103  }
104  SOPHUS_ASSERT_EQ(this->imageSize(), view.imageSize());
105  details::pitchedCopy(
106  (uint8_t*)this->ptr(),
107  this->layout().pitchBytes(),
108  (uint8_t const*)view.ptr(),
109  view.layout().pitchBytes(),
110  this->imageSize(),
111  sizeof(TPixel));
112  }
113 
114  /// Returns v-th row pointer of mutable pixel.
115  [[nodiscard]] auto rowPtrMut(int v) const -> TPixel* {
116  return (TPixel*)((uint8_t*)(this->ptr()) + v * this->layout_.pitchBytes());
117  }
118 
119  /// Mutable accessor to pixel u, v.
120  ///
121  /// Precondition: u must be in [0, width) and v must be in [0, height).
122  /// Silent UB on failure.
123  [[nodiscard]] auto mut(int u, int v) const -> TPixel& {
124  return rowPtrMut(v)[u];
125  }
126 
127  [[nodiscard]] auto mut(Eigen::Vector2i uv) const -> TPixel& {
128  return mut(uv[0], uv[1]);
129  }
130 
131  /// Mutates each pixel of this with given unary operation
132  ///
133  /// Preconditions: this must not be empty.
134  template <class TUnaryOperation>
135  void mutate(TUnaryOperation const& unary_op) const {
136  SOPHUS_ASSERT(!this->isEmpty());
137 
138  for (int v = 0; v < this->layout_.height(); ++v) {
139  TPixel* p = this->rowPtrMut(v);
140  TPixel const* end_of_row = p + this->layout_.width();
141  for (; p != end_of_row; ++p) {
142  *p = unary_op(*p);
143  }
144  }
145  }
146 
147  /// For each pixel in `this` with coordinates (u,v), populates with the user
148  /// provided function, evaluated as `uv_op(u,v)`, where u and v are integers
149  /// such that u in [0, width), v in [0, height)
150  ///
151  /// Preconditions: this must not be empty.
152  template <class TUVOperation>
153  void generate(TUVOperation const& uv_op) const {
154  SOPHUS_ASSERT(!this->isEmpty());
155 
156  for (int v = 0; v < this->layout_.height(); ++v) {
157  TPixel* p = this->rowPtrMut(v);
158  TPixel const* end_of_row = p + this->layout_.width();
159  for (int u = 0; p != end_of_row; ++p, ++u) {
160  *p = uv_op(u, v);
161  }
162  }
163  }
164 
165  /// Transforms view using unary operation and assigns result to this.
166  ///
167  /// Preconditions:
168  /// - this must not be empty.
169  /// - this->imageSize() == view.imageSize()
170  template <class TOtherPixel, class TUnaryOperation>
172  ImageView<TOtherPixel> view, TUnaryOperation const& unary_op) const {
173  SOPHUS_ASSERT(!this->isEmpty());
174  SOPHUS_ASSERT_EQ(view.imageSize(), this->imageSize());
175 
176  for (int v = 0; v < this->layout_.height(); ++v) {
177  TPixel* mut_p = this->rowPtrMut(v);
178  TOtherPixel const* p = view.rowPtr(v);
179  TOtherPixel const* end_of_row = p + view.layout().width();
180 
181  for (; p != end_of_row; ++p, ++mut_p) {
182  *mut_p = unary_op(*p);
183  }
184  }
185  }
186 
187  /// Transforms two views using binary operation and assigns result to this.
188  ///
189  /// Preconditions:
190  /// - this must not be empty.
191  /// - this->imageSize() == lhs.imageSize() == rhs.imageSize()
192  template <class TLhsPixel, class TRhsPixel, class TBinaryOperation>
196  TBinaryOperation const& binary_op) const {
197  SOPHUS_ASSERT(!this->isEmpty());
198  SOPHUS_ASSERT_EQ(lhs.imageSize(), this->imageSize());
199  SOPHUS_ASSERT_EQ(rhs.imageSize(), this->imageSize());
200 
201  for (int v = 0; v < this->layout_.height(); ++v) {
202  TPixel* mut_p = this->rowPtrMut(v);
203  TLhsPixel const* lhs_p = lhs.rowPtr(v);
204  TRhsPixel const* rhs_p = rhs.rowPtr(v);
205 
206  for (int u = 0; u < this->layout_.width(); ++u) {
207  mut_p[u] = binary_op(lhs_p[u], rhs_p[u]);
208  }
209  }
210  }
211 
212  /// Populates every pixel of this with val.
213  ///
214  /// Preconditions: this must not be empty.
215  void fill(TPixel const& val) const {
216  mutate([&](TPixel const& /*unused*/) { return val; });
217  }
218 
219  /// Returns pointer of mutable data to first pixel.
220  [[nodiscard]] auto ptrMut() const -> TPixel* {
221  return const_cast<TPixel*>(ImageView<TPixel>::ptr());
222  }
223 
224  /// Returns mutable subview.
225  [[nodiscard]] auto mutSubview(
226  Eigen::Vector2i uv, sophus::ImageSize size) const -> MutImageView {
227  SOPHUS_ASSERT(this->colInBounds(uv[0]));
228  SOPHUS_ASSERT(this->rowInBounds(uv[1]));
229  SOPHUS_ASSERT_LE(uv.x() + size.width, this->layout().width());
230  SOPHUS_ASSERT_LE(uv.y() + size.height, this->layout().height());
231 
232  return MutImageView(
233  ImageLayout::makeFromSizeAndPitch<TPixel>(
234  size, this->layout().pitchBytes()),
235  this->rowPtrMut(uv.y()) + uv.x());
236  }
237 };
238 
239 namespace details {
240 
241 template <class TPixel>
242 auto checkedPixelAccessMut(
243  MutImageView<TPixel> const& view,
244  int u,
245  int v,
246  std::string const& file,
247  int line,
248  std::string const& str) -> TPixel& {
249  if (!view.colInBounds(u) || !view.rowInBounds(v)) {
250  FARM_IMPL_LOG_PRINTLN("[SOPHUS_PIXEL_MUT in {}:{}]", file, line);
252  "pixel `{},{}` not in image with size {} x {}",
253  u,
254  v,
255  view.imageSize().width,
256  view.imageSize().height);
257  if (!str.empty()) {
258  ::fmt::print(stderr, "{}", str);
259  }
260  FARM_IMPL_ABORT();
261  }
262  return view.mut(u, v);
263 }
264 } // namespace details
265 
266 } // namespace sophus
267 
268 #define SOPHUS_PIXEL_MUT(img, u, v, ...) \
269  ::sophus::details::checkedPixelAccessMut( \
270  img, u, v, __FILE__, __LINE__, SOPHUS_FORMAT(__VA_ARGS__))
sophus::MutImageView::mut
auto mut(Eigen::Vector2i uv) const -> TPixel &
Definition: mut_image_view.h:127
sophus::MutImageView::rowPtrMut
auto rowPtrMut(int v) const -> TPixel *
Returns v-th row pointer of mutable pixel.
Definition: mut_image_view.h:115
sophus::ImageLayout::height
auto height() const -> int
Definition: layout.h:55
SOPHUS_ASSERT
#define SOPHUS_ASSERT(...)
Definition: common.h:40
FARM_IMPL_LOG_PRINTLN
#define FARM_IMPL_LOG_PRINTLN(...)
Definition: format.h:56
sophus::ImageView::isEmpty
auto isEmpty() const -> bool
Returns true if view is empty.
Definition: image_view.h:71
sophus::MutImageView::transformFrom
void transformFrom(ImageView< TOtherPixel > view, TUnaryOperation const &unary_op) const
Transforms view using unary operation and assigns result to this.
Definition: mut_image_view.h:171
sophus::ImageLayout::pitchBytes
auto pitchBytes() const -> size_t
Definition: layout.h:57
sophus::MutImageView::ptrMut
auto ptrMut() const -> TPixel *
Returns pointer of mutable data to first pixel.
Definition: mut_image_view.h:220
core.event_service.str
str
Definition: event_service.py:547
sophus::MutImageView::generate
void generate(TUVOperation const &uv_op) const
For each pixel in this with coordinates (u,v), populates with the user provided function,...
Definition: mut_image_view.h:153
sophus::ImageLayout
Layout of the image: width, height and pitch in bytes.
Definition: layout.h:23
sophus
Image MutImage, owning images types.
Definition: num_diff.h:20
sophus::ImageView::ptr
auto ptr() const -> TPixel const *
Returns pointer to first pixel.
Definition: image_view.h:140
sophus::ImageView
A view of an (immutable) image, which does not own the data.
Definition: image_view.h:55
sophus::ImageView::rowInBounds
auto rowInBounds(int v) const -> bool
Returns true if v is in [0, height).
Definition: image_view.h:104
sophus::ImageLayout::width
auto width() const -> int
Definition: layout.h:54
sophus::ImageView::layout
auto layout() const -> ImageLayout const &
Returns ImageLayout. It is {{0,0}, 0} is view is empty.
Definition: image_view.h:86
region.h
sophus::ImageView::imageSize
auto imageSize() const -> sophus::ImageSize const &
Returns ImageSize. It is {0,0} if view is empty.
Definition: image_view.h:80
sophus::MutImageView::transformFrom
void transformFrom(ImageView< TLhsPixel > lhs, ImageView< TRhsPixel > rhs, TBinaryOperation const &binary_op) const
Transforms two views using binary operation and assigns result to this.
Definition: mut_image_view.h:193
sophus::MutImageView::view
auto view() const -> ImageView< TPixel >
Returns ImageView(*this).
Definition: mut_image_view.h:87
sophus::MutImageView::unsafeConstCast
static auto unsafeConstCast(ImageView< TPixel > view) -> MutImageView
Creates mutable view from view.
Definition: mut_image_view.h:79
sophus::MutImageView::MutImageView
MutImageView(ImageLayout layout, TPixel *ptr) noexcept
Creates view from layout and pointer to first pixel.
Definition: mut_image_view.h:67
sophus::ImageView::colInBounds
auto colInBounds(int u) const -> bool
Returns true if u is in [0, width).
Definition: image_view.h:99
SOPHUS_ASSERT_EQ
#define SOPHUS_ASSERT_EQ(...)
Definition: common.h:41
sophus::MutImageView::MutImageView
MutImageView(sophus::ImageSize image_size, TPixel *ptr) noexcept
Creates view from image size and pointer to first pixel. The image is assumed to be contiguous and th...
Definition: mut_image_view.h:72
SOPHUS_ASSERT_LE
#define SOPHUS_ASSERT_LE(...)
Definition: common.h:44
sophus::MutImageView::copyDataFrom
void copyDataFrom(ImageView< TPixel > view) const
Copies data from view into this.
Definition: mut_image_view.h:98
sophus::ImageView::pitchBytes
auto pitchBytes() const -> size_t
Definition: image_view.h:91
FARM_IMPL_ABORT
#define FARM_IMPL_ABORT()
Definition: format.h:62
sophus::MutImageView::mut
auto mut(int u, int v) const -> TPixel &
Mutable accessor to pixel u, v.
Definition: mut_image_view.h:123
sophus::ImageView::layout_
ImageLayout layout_
Definition: image_view.h:241
sophus::ImageView::rowPtr
auto rowPtr(int v) const -> TPixel const *
Returns v-th row pointer.
Definition: image_view.h:111
sophus::MutImageView
View of a mutable image, which does not own the data.
Definition: mut_image_view.h:61
image_view.h
sophus::MutImageView::mutSubview
auto mutSubview(Eigen::Vector2i uv, sophus::ImageSize size) const -> MutImageView
Returns mutable subview.
Definition: mut_image_view.h:225
sophus::MutImageView::MutImageView
MutImageView()=default
Default constructor creates an empty image.
sophus::ImageSize
Image size, hence its width and height.
Definition: image_size.h:21
sophus::MutImageView::fill
void fill(TPixel const &val) const
Populates every pixel of this with val.
Definition: mut_image_view.h:215
sophus::MutImageView::mutate
void mutate(TUnaryOperation const &unary_op) const
Mutates each pixel of this with given unary operation.
Definition: mut_image_view.h:135