ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
MappedImage.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#pragma once
4
6
7#include <cassert>
8#include <cstring>
9#include <iostream>
10#include <type_traits>
11#include <typeindex>
12#include <typeinfo>
13#include <vector>
14
15namespace ChimeraTK {
16
24 std::type_index dataTypeId;
25 uint32_t totalLength = 0; // 0: unknown/not set. length includes header.
26 explicit OpaqueStructHeader(std::type_index dataTypeId_) : dataTypeId(dataTypeId_) {}
27 };
28
37 template<class StructHeader>
39 public:
40 enum class InitData { Yes, No };
43 explicit MappedStruct(
45
48 unsigned char* data();
50 size_t capacity() const;
52 size_t size() const { return static_cast<OpaqueStructHeader*>(header())->totalLength; }
54 StructHeader* header() { return reinterpret_cast<StructHeader*>(data()); }
56 void initData();
57
58 protected:
59 // We keep the accessor instead of the naked pointer to simplify usage, like this the object stays valid even after
60 // memory used by accessor was swapped.
62 };
63
64 /******************************* application to Image encoding *********************************/
65
66 enum class ImgFormat : unsigned {
67 Unset = 0,
68 Gray8,
69 Gray16,
70 RGB24,
71 RGBA32,
72 // floating point formats for communication of intermediate results
73 FLOAT1,
74 FLOAT2,
75 FLOAT3,
76 FLOAT4,
77 DOUBLE1,
78 DOUBLE2,
79 DOUBLE3,
81 };
82 // values are defined for a bit field
83 enum class ImgOptions { RowMajor = 1, ColMajor = 0 };
84
86 struct ImgHeader : public OpaqueStructHeader {
88
89 uint32_t width = 0;
90 uint32_t height = 0;
92 int32_t x_start = 0;
93 int32_t y_start = 0;
95 float scale_x = 1;
96 float scale_y = 1;
98 uint32_t channels = 0;
99 uint32_t bytesPerPixel = 0;
101 uint32_t effBitsPerPixel = 0;
105 uint64_t frame = 0;
106 };
107
108 class MappedImage;
112 template<typename ValType, ImgOptions OPTIONS>
113 class ImgView {
114 public:
115 ImgView(MappedImage* owner) : _mi(owner) {}
122 ValType& operator()(unsigned dx, unsigned dy, unsigned channel = 0);
123
124 // simply define iterator access via pointers
125 using iterator = ValType*;
126 using value_type = ValType;
127 // for iteration over whole image
128 ValType* begin() { return beginRow(0); }
129 ValType* end() { return beginRow(header()->height); }
130 // these assume ROW-MAJOR ordering
131 ValType* beginRow(unsigned row) { return vec() + row * header()->width * header()->channels; }
132 ValType* endRow(unsigned row) { return beginRow(row + 1); }
133 ImgHeader* header();
134
135 protected:
136 ValType* vec();
138 };
139
147 class MappedImage : public MappedStruct<ImgHeader> {
148 public:
149 using MappedStruct<ImgHeader>::MappedStruct;
150
153 void setShape(unsigned width, unsigned height, ImgFormat fmt);
154 size_t lengthForShape(unsigned width, unsigned height, ImgFormat fmt);
156 unsigned char* imgBody() { return data() + sizeof(ImgHeader); }
157
160 template<typename UserType, ImgOptions OPTIONS = ImgOptions::RowMajor>
162 [[maybe_unused]] auto* h = header();
163 assert(h->channels > 0 && "call setShape() before interpretedView()!");
164 assert(h->bytesPerPixel == h->channels * sizeof(UserType) &&
165 "choose correct bytesPerPixel and channels value before conversion!");
166 assert(((unsigned)h->options & (unsigned)ImgOptions::RowMajor) ==
167 ((unsigned)OPTIONS & (unsigned)ImgOptions::RowMajor) &&
168 "inconsistent data ordering col/row major");
170 return ret;
171 }
172
173 protected:
174 void formatsDefinition(ImgFormat fmt, unsigned& channels, unsigned& bytesPerPixel);
175 };
176
177 /*************************** begin MappedStruct implementations ************************************************/
178
179 template<class StructHeader>
182 : _accToData(accToData) {
183 static_assert(std::is_base_of<OpaqueStructHeader, StructHeader>::value,
184 "MappedStruct expects StructHeader to implement OpaqueStructHeader");
185 if(doInitData == InitData::Yes) {
186 initData();
187 }
188 }
189
190 template<class StructHeader>
192 return _accToData.data();
193 }
194
195 template<class StructHeader>
197 // reason for cast: getNElements not declared const
198 return const_cast<MappedStruct*>(this)->_accToData.getNElements();
199 }
200
201 template<class StructHeader>
203 size_t sh = sizeof(StructHeader);
204 if(capacity() < sh) {
205 throw logic_error("buffer provided to MappedStruct is too small for correct initialization");
206 }
207 auto* p = data();
208 new(p) StructHeader;
209 header()->totalLength = sh; // minimal length, could be larger
210 memset(p + sh, 0, capacity() - sh);
211 }
212
213 /*************************** begin MappedImage implementations ************************************************/
214
215 inline void MappedImage::formatsDefinition(ImgFormat fmt, unsigned& channels, unsigned& bytesPerPixel) {
216 switch(fmt) {
217 case ImgFormat::Unset:
218 assert(false && "ImgFormat::Unset not allowed");
219 break;
220 case ImgFormat::Gray8:
221 channels = 1;
222 bytesPerPixel = 1;
223 break;
225 channels = 1;
226 bytesPerPixel = 2;
227 break;
228 case ImgFormat::RGB24:
229 channels = 3;
230 bytesPerPixel = 3;
231 break;
233 channels = 4;
234 bytesPerPixel = 4;
235 break;
240 channels = unsigned(fmt) - unsigned(ImgFormat::FLOAT1) + 1;
241 bytesPerPixel = 4 * channels;
242 break;
247 channels = unsigned(fmt) - unsigned(ImgFormat::DOUBLE1) + 1;
248 bytesPerPixel = 8 * channels;
249 break;
250 }
251 }
252
253 inline size_t MappedImage::lengthForShape(unsigned width, unsigned height, ImgFormat fmt) {
254 unsigned channels;
255 unsigned bytesPerPixel;
256 formatsDefinition(fmt, channels, bytesPerPixel);
257 return sizeof(ImgHeader) + (size_t)width * height * bytesPerPixel;
258 }
259
260 inline void MappedImage::setShape(unsigned width, unsigned height, ImgFormat fmt) {
261 unsigned channels;
262 unsigned bytesPerPixel;
263 formatsDefinition(fmt, channels, bytesPerPixel);
264 size_t totalLen = lengthForShape(width, height, fmt);
265 if(totalLen > capacity()) {
266 throw logic_error("MappedImage: provided buffer to small for requested image shape");
267 }
268 auto* h = header();
269 // start with default values
270 new(h) ImgHeader;
271 h->image_format = fmt;
272 h->totalLength = totalLen;
273 h->width = width;
274 h->height = height;
275 h->channels = channels;
276 h->bytesPerPixel = bytesPerPixel;
277 }
278
279 template<typename ValType, ImgOptions OPTIONS>
280 ValType& ImgView<ValType, OPTIONS>::operator()(unsigned dx, unsigned dy, unsigned channel) {
281 auto* h = header();
282 assert(dy < h->height);
283 assert(dx < h->width);
284 assert(channel < h->channels);
285 // this is the only place where row-major / column-major storage is decided
286 // note, definition of row major/column major is confusing for images.
287 // - for a matrix M(i,j) we say it is stored row-major if rows are stored without interleaving: M11, M12,...
288 // - for the same Matrix, if we write M(x,y) for pixel value at coordite (x,y) of an image, this means
289 // that pixel _columns_ are stored without interleaving
290 // So definition used here is opposite to matrix definition.
291 if constexpr((unsigned)OPTIONS & (unsigned)ImgOptions::RowMajor) {
292 return vec()[(dy * h->width + dx) * h->channels + channel];
293 }
294 else {
295 return vec()[(dy + dx * h->height) * h->channels + channel];
296 }
297 }
298
299 template<typename ValType, ImgOptions OPTIONS>
301 return _mi->header();
302 }
303
304 template<typename ValType, ImgOptions OPTIONS>
306 return reinterpret_cast<ValType*>(_mi->imgBody());
307 }
308
309} // namespace ChimeraTK
provides convenient matrix-like access for MappedImage
ValType * begin()
ValType & operator()(unsigned dx, unsigned dy, unsigned channel=0)
This allows to read/write image pixel values, for given coordinates.
ValType * endRow(unsigned row)
ImgView(MappedImage *owner)
MappedImage * _mi
ImgHeader * header()
ValType * beginRow(unsigned row)
interface to an image that is mapped onto a 1D array of ValType
ImgView< UserType, OPTIONS > interpretedView()
returns an ImgView object which can be used like a matrix.
void formatsDefinition(ImgFormat fmt, unsigned &channels, unsigned &bytesPerPixel)
size_t lengthForShape(unsigned width, unsigned height, ImgFormat fmt)
void setShape(unsigned width, unsigned height, ImgFormat fmt)
needs to be called after construction.
unsigned char * imgBody()
returns pointer to image payload data
Provides interface to a struct that is mapped onto a 1D array of ValType StructHeader must be derived...
Definition MappedImage.h:38
StructHeader * header()
returns header, e.g. for setting meta data
Definition MappedImage.h:54
ChimeraTK::OneDRegisterAccessor< unsigned char > & _accToData
Definition MappedImage.h:61
void initData()
default initialize header and zero out data that follows
MappedStruct(ChimeraTK::OneDRegisterAccessor< unsigned char > &accToData, InitData doInitData=InitData::No)
This keeps a reference to given OneDRegisterAccessor.
size_t capacity() const
capacity of used container
size_t size() const
currently used size
Definition MappedImage.h:52
unsigned char * data()
returns pointer to data for header and struct content.
Accessor class to read and write registers transparently by using the accessor object like a vector o...
Exception thrown when a logic error has occured.
Definition Exception.h:51
Image header.
Definition MappedImage.h:86
float scale_x
can be used in output to provide scaled coordinates
Definition MappedImage.h:95
int32_t x_start
start coordinates, in output
Definition MappedImage.h:92
uint32_t channels
gray=1, rgb=3, rgba=4
Definition MappedImage.h:98
uint64_t frame
frame number/counter
uint32_t effBitsPerPixel
effective bits per pixel
generic header for opaque struct handling It has fields needed for communication in the same process,...
Definition MappedImage.h:23
OpaqueStructHeader(std::type_index dataTypeId_)
Definition MappedImage.h:26