Lagrange
ImageView.h
1/*
2 * Copyright 2023 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/image/ImageStorage.h>
15
16// clang-format off
17#include <lagrange/utils/warnoff.h>
18#include <tbb/parallel_for.h>
19#include <lagrange/utils/warnon.h>
20// clang-format on
21
22#include <vector>
23
24namespace lagrange {
25namespace image {
26
28{
29protected:
30 ImageViewBase() = default;
31 virtual ~ImageViewBase() = default;
32
33public: // virtual methods
34 virtual ImagePrecision get_precision() const = 0;
35 virtual ImageChannel get_channel() const = 0;
36 virtual bool is_compact_row() const = 0;
37 virtual bool is_compact() const = 0;
38 virtual const void* get_data() const = 0;
39 virtual void* get_data() = 0;
40
41public: // non-virtual methods
42 Eigen::Matrix<size_t, 2, 1> get_view_size() const { return m_view_size; }
43 Eigen::Matrix<size_t, 2, 1> get_view_stride_in_byte() const { return m_view_stride_in_byte; }
44 Eigen::Matrix<size_t, 2, 1> get_view_offset_in_byte() const { return m_view_offset_in_byte; }
45 std::shared_ptr<ImageStorage> get_storage() { return m_storage; }
46
47protected: // non-template variables
48 Eigen::Matrix<size_t, 2, 1> m_view_size;
49 Eigen::Matrix<size_t, 2, 1> m_view_stride_in_byte;
50 Eigen::Matrix<size_t, 2, 1> m_view_offset_in_byte;
51 std::shared_ptr<ImageStorage> m_storage;
52};
53
54template <typename T>
56{
57public:
58 ImageView();
59 ImageView(size_t width, size_t height, size_t alignment);
61 std::shared_ptr<ImageStorage> _storage,
62 const size_t width,
63 const size_t height,
64 const size_t stride_0_in_byte = sizeof(T),
65 const size_t stride_1_in_row = 1,
66 const size_t offset_0_in_byte = 0,
67 const size_t offset_1_in_row = 0);
68 ImageView(const ImageView<T>& other);
69 ImageView(ImageView<T>&& other);
70 virtual ~ImageView() = default;
71
72public:
73 ImageView<T>& operator=(const ImageView<T>& other);
74 ImageView<T>& operator=(ImageView<T>&& other);
75
76public:
77 void reset();
78 bool resize(size_t width, size_t height, size_t alignment);
79
80public:
81 bool view(
82 std::shared_ptr<ImageStorage> _storage,
83 const size_t width,
84 const size_t height,
85 const size_t stride_0_in_byte = sizeof(T),
86 const size_t stride_1_in_row = 1,
87 const size_t offset_0_in_byte = 0,
88 const size_t offset_1_in_row = 0);
89
90 ImageStorage::aligned_vector<unsigned char> pack() const;
91 bool unpack(const ImageStorage::aligned_vector<unsigned char>& buf);
92
93 template <typename S, typename CONVERTOR>
94 bool convert_from(const ImageView<S>& other, size_t alignment, const CONVERTOR& convertor);
95 template <typename S>
96 bool convert_from(const ImageView<S>& other, size_t alignment);
97
98 void clear(const T val);
99
100public:
101 // x is col, y is row
102 T& operator()(size_t x, size_t y);
103 const T& operator()(size_t x, size_t y) const;
104
105public: // for interfaces of ImageViewBase
106 virtual ImagePrecision get_precision() const final { return ImageTraits<T>::precision; };
107 virtual ImageChannel get_channel() const final { return ImageTraits<T>::channel; };
108 virtual bool is_compact_row() const final { return sizeof(T) == m_view_stride_in_byte(0); }
109 virtual bool is_compact() const final
110 {
111 return sizeof(T) * m_view_size(0) == m_view_stride_in_byte(1);
112 }
113 virtual const void* get_data() const final
114 {
115 return reinterpret_cast<const void*>(&(operator()(0, 0)));
116 };
117 virtual void* get_data() final { return reinterpret_cast<void*>(&(operator()(0, 0))); };
118};
119
120template <typename T>
122{
123 reset();
124}
125template <typename T>
126ImageView<T>::ImageView(size_t width, size_t height, size_t alignment)
127{
128 if (!resize(width, height, alignment)) {
129 throw std::runtime_error("ImageView::ImageView, cannot resize!");
130 }
131}
132template <typename T>
133ImageView<T>::ImageView(
134 std::shared_ptr<ImageStorage> _storage,
135 size_t width,
136 size_t height,
137 size_t stride_0_in_byte,
138 size_t stride_1_in_row,
139 size_t offset_0_in_byte,
140 size_t offset_1_in_row)
141{
142 if (!view(
143 _storage,
144 width,
145 height,
146 stride_0_in_byte,
147 stride_1_in_row,
148 offset_0_in_byte,
149 offset_1_in_row)) {
150 throw std::runtime_error("ImageView::ImageView, cannot construct from ImageStorage!");
151 }
152}
153template <typename T>
154ImageView<T>::ImageView(const ImageView<T>& other)
155{
156 *this = other;
157}
158template <typename T>
159ImageView<T>::ImageView(ImageView<T>&& other)
160{
161 *this = other;
162}
163
164template <typename T>
165ImageView<T>& ImageView<T>::operator=(const ImageView<T>& other)
166{
167 m_view_size = other.m_view_size;
168 m_view_stride_in_byte = other.m_view_stride_in_byte;
169 m_view_offset_in_byte = other.m_view_offset_in_byte;
170 m_storage = other.m_storage;
171 return *this;
172}
173template <typename T>
174ImageView<T>& ImageView<T>::operator=(ImageView<T>&& other)
175{
176 m_view_size = other.m_view_size;
177 m_view_stride_in_byte = other.m_view_stride_in_byte;
178 m_view_offset_in_byte = other.m_view_offset_in_byte;
179 m_storage = std::move(other.m_storage);
180 return *this;
181}
182
183template <typename T>
184void ImageView<T>::reset()
185{
186 m_storage.reset();
187 m_view_size.setZero();
188 m_view_stride_in_byte.setZero();
189 m_view_offset_in_byte.setZero();
190}
191template <typename T>
192bool ImageView<T>::resize(size_t width, size_t height, size_t alignment)
193{
194 if (0 == width || 0 == height) {
195 reset();
196 return false;
197 } else {
198 m_storage = std::make_shared<ImageStorage>(width * sizeof(T), height, alignment);
199 m_view_size = {width, height};
200 m_view_stride_in_byte(0) = sizeof(T);
201 m_view_stride_in_byte(1) = m_storage->get_full_stride();
202 m_view_offset_in_byte.setZero();
203 return true;
204 }
205}
206
207template <typename T>
208bool ImageView<T>::view(
209 std::shared_ptr<ImageStorage> _storage,
210 size_t width,
211 size_t height,
212 size_t stride_0_in_byte,
213 size_t stride_1_in_row,
214 size_t offset_0_in_byte,
215 size_t offset_1_in_row)
216{
217 if (_storage && 0 < width && 0 < height) {
218 auto full_size = _storage->get_full_size();
219 auto full_stride = _storage->get_full_stride();
220 if (sizeof(T) <= stride_0_in_byte &&
221 offset_0_in_byte + stride_0_in_byte * width <= full_size(0) && 0 < stride_1_in_row &&
222 offset_1_in_row + stride_1_in_row * height <= full_size(1)) {
223 m_storage = _storage;
224 m_view_size = {width, height};
225 m_view_stride_in_byte = {stride_0_in_byte, stride_1_in_row * full_stride};
226 m_view_offset_in_byte = {offset_0_in_byte, offset_1_in_row * full_stride};
227 return true;
228 }
229 }
230 reset();
231 return false;
232}
233
234template <typename T>
235ImageStorage::aligned_vector<unsigned char> ImageView<T>::pack() const
236{
237 ImageStorage::aligned_vector<unsigned char> buf(sizeof(T) * m_view_size(0) * m_view_size(1));
238 if (is_compact()) {
239 std::copy_n(
240 reinterpret_cast<const unsigned char*>(&(operator()(0, 0))),
241 buf.size(),
242 buf.data());
243 } else if (sizeof(T) == m_view_stride_in_byte(0)) {
244 auto src = reinterpret_cast<const unsigned char*>(&(operator()(0, 0)));
245 auto dst = buf.data();
246 auto dst_stride_in_byte_row = sizeof(T) * m_view_size(0);
247 for (size_t row = 0; row < m_view_size(1); ++row) {
248 std::copy_n(src, dst_stride_in_byte_row, dst);
249 src += m_view_stride_in_byte(1);
250 dst += dst_stride_in_byte_row;
251 }
252 } else {
253 auto src_row = reinterpret_cast<const unsigned char*>(&(operator()(0, 0)));
254 auto dst_row = buf.data();
255 auto dst_stride_in_byte_col = sizeof(T);
256 auto dst_stride_in_byte_row = sizeof(T) * m_view_size(0);
257 for (size_t row = 0; row < m_view_size(1); ++row) {
258 auto src_pix = src_row;
259 auto dst_pix = dst_row;
260 for (size_t col = 0; col < m_view_size(0); ++col) {
261 *reinterpret_cast<T*>(dst_pix) = *reinterpret_cast<const T*>(src_pix);
262 src_pix += m_view_stride_in_byte(0);
263 dst_pix += dst_stride_in_byte_col;
264 }
265 src_row += m_view_stride_in_byte(1);
266 dst_row += dst_stride_in_byte_row;
267 }
268 }
269 return buf;
270}
271template <typename T>
272bool ImageView<T>::unpack(const ImageStorage::aligned_vector<unsigned char>& buf)
273{
274 if (sizeof(T) * m_view_size(0) * m_view_size(1) != buf.size()) {
275 return false;
276 }
277
278 if (is_compact()) {
279 std::copy_n(buf.data(), buf.size(), reinterpret_cast<unsigned char*>(&(operator()(0, 0))));
280 } else if (sizeof(T) == m_view_stride_in_byte(0)) {
281 auto dst = reinterpret_cast<unsigned char*>(&(operator()(0, 0)));
282 auto src = buf.data();
283 auto src_stride_in_byte_row = sizeof(T) * m_view_size(0);
284 for (size_t row = 0; row < m_view_size(1); ++row) {
285 std::copy_n(src, src_stride_in_byte_row, dst);
286 dst += m_view_stride_in_byte(1);
287 src += src_stride_in_byte_row;
288 }
289 } else {
290 auto dst_row = reinterpret_cast<unsigned char*>(&(operator()(0, 0)));
291 auto src_row = buf.data();
292 auto src_stride_in_byte_col = sizeof(T);
293 auto src_stride_in_byte_row = sizeof(T) * m_view_size(0);
294 for (size_t row = 0; row < m_view_size(1); ++row) {
295 auto dst_pix = dst_row;
296 auto src_pix = src_row;
297 for (size_t col = 0; col < m_view_size(0); ++col) {
298 *reinterpret_cast<T*>(dst_pix) = *reinterpret_cast<const T*>(src_pix);
299 dst_pix += m_view_stride_in_byte(0);
300 src_pix += src_stride_in_byte_col;
301 }
302 dst_row += m_view_stride_in_byte(1);
303 src_row += src_stride_in_byte_row;
304 }
305 }
306 return true;
307}
308
309template <typename T>
310template <typename S, typename CONVERTOR>
311bool ImageView<T>::convert_from(
312 const ImageView<S>& other,
313 size_t alignment,
314 const CONVERTOR& convertor)
315{
316 const auto other_view_size = other.get_view_size();
317 if (!resize(other_view_size(0), other_view_size(1), alignment)) {
318 return false;
319 }
320
321 const char* src = reinterpret_cast<const char*>(&(other(0, 0)));
322 char* dst = reinterpret_cast<char*>(&(operator()(0, 0)));
323 const auto other_view_stride_in_byte = other.get_view_stride_in_byte();
324 tbb::parallel_for(static_cast<size_t>(0), other_view_size(1), [&](size_t y) {
325 const char* src_row = src + other_view_stride_in_byte(1) * y;
326 char* dst_row = dst + m_view_stride_in_byte(1) * y;
327 for (size_t x = 0; x < other_view_size(0); ++x) {
328 const S* src_pix =
329 reinterpret_cast<const S*>(src_row + other_view_stride_in_byte(0) * x);
330 T* dst_pix = reinterpret_cast<T*>(dst_row + m_view_stride_in_byte(0) * x);
331 convertor(*src_pix, *dst_pix);
332 }
333 });
334 return true;
335}
336
337template <typename T>
338template <typename S>
339bool ImageView<T>::convert_from(const ImageView<S>& other, size_t alignment)
340{
341 return convert_from(other, alignment, convert_image_pixel<S, T>());
342}
343
344template <typename T>
345void ImageView<T>::clear(const T val)
346{
347 tbb::parallel_for(static_cast<size_t>(0), m_view_size(1), [&](size_t h) {
348 auto* ptr = reinterpret_cast<unsigned char*>(&((*this)(0, h)));
349 for (size_t w = 0; w < m_view_size(0); ++w) {
350 auto* p = reinterpret_cast<T*>(ptr + w * m_view_stride_in_byte(0));
351 *p = val;
352 }
353 });
354}
355
356template <typename T>
357T& ImageView<T>::operator()(size_t x, size_t y)
358{
359 auto total_offset = m_view_offset_in_byte(0) + m_view_offset_in_byte(1) +
360 m_view_stride_in_byte(0) * x + m_view_stride_in_byte(1) * y;
361 return *reinterpret_cast<T*>(m_storage->data() + total_offset);
362}
363template <typename T>
364const T& ImageView<T>::operator()(size_t x, size_t y) const
365{
366 auto total_offset = m_view_offset_in_byte(0) + m_view_offset_in_byte(1) +
367 m_view_stride_in_byte(0) * x + m_view_stride_in_byte(1) * y;
368 return *reinterpret_cast<T*>(m_storage->data() + total_offset);
369}
370} // namespace image
371} // namespace lagrange
Definition: ImageView.h:28
Definition: ImageView.h:56
Main namespace for Lagrange.
Definition: AABBIGL.h:30
Definition: ImageType.h:58