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 static 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:
175 static std::pair<uint32_t, uint32_t> getFormatDefinition(ImgFormat fmt);
176 };
177
178 /*************************** begin MappedStruct implementations ************************************************/
179
180 template<class StructHeader>
183 : _accToData(accToData) {
184 static_assert(std::is_base_of<OpaqueStructHeader, StructHeader>::value,
185 "MappedStruct expects StructHeader to implement OpaqueStructHeader");
186 if(doInitData == InitData::Yes) {
187 initData();
188 }
189 }
190
191 template<class StructHeader>
193 return _accToData.data();
194 }
195
196 template<class StructHeader>
198 // reason for cast: getNElements not declared const
199 return const_cast<MappedStruct*>(this)->_accToData.getNElements();
200 }
201
202 template<class StructHeader>
204 size_t sh = sizeof(StructHeader);
205 if(capacity() < sh) {
206 throw logic_error("buffer provided to MappedStruct is too small for correct initialization");
207 }
208 auto* p = data();
209 new(p) StructHeader;
210 header()->totalLength = sh; // minimal length, could be larger
211 memset(p + sh, 0, capacity() - sh);
212 }
213
214 /*************************** begin MappedImage implementations ************************************************/
215
216 inline std::pair<uint32_t, uint32_t> MappedImage::getFormatDefinition(ImgFormat fmt) {
217 unsigned channels{0}, bytesPerPixel{0};
218 switch(fmt) {
219 case ImgFormat::Unset:
220 assert(false && "ImgFormat::Unset not allowed");
221 break;
222 case ImgFormat::Gray8:
223 channels = 1;
224 bytesPerPixel = 1;
225 break;
227 channels = 1;
228 bytesPerPixel = 2;
229 break;
230 case ImgFormat::RGB24:
231 channels = 3;
232 bytesPerPixel = 3;
233 break;
235 channels = 4;
236 bytesPerPixel = 4;
237 break;
239 channels = 1;
240 bytesPerPixel = 4 * channels;
241 break;
243 channels = 2;
244 bytesPerPixel = 4 * channels;
245 break;
247 channels = 3;
248 bytesPerPixel = 4 * channels;
249 break;
251 channels = 4;
252 bytesPerPixel = 4 * channels;
253 break;
255 channels = 1;
256 bytesPerPixel = 8 * channels;
257 break;
259 channels = 2;
260 bytesPerPixel = 8 * channels;
261 break;
263 channels = 3;
264 bytesPerPixel = 8 * channels;
265 break;
267 channels = 4;
268 bytesPerPixel = 8 * channels;
269 break;
270 }
271 return {channels, bytesPerPixel};
272 }
273
274 inline size_t MappedImage::lengthForShape(unsigned width, unsigned height, ImgFormat fmt) {
275 auto [channels, bytesPerPixel] = getFormatDefinition(fmt);
276 return sizeof(ImgHeader) + size_t(width) * height * bytesPerPixel;
277 }
278
279 inline void MappedImage::setShape(unsigned width, unsigned height, ImgFormat fmt) {
280 auto [channels, bytesPerPixel] = getFormatDefinition(fmt);
281 size_t totalLen = lengthForShape(width, height, fmt);
282 if(totalLen > capacity()) {
283 throw logic_error("MappedImage: provided buffer to small for requested image shape");
284 }
285 auto* h = header();
286 // start with default values
287 new(h) ImgHeader;
288 h->image_format = fmt;
289 h->totalLength = totalLen;
290 h->width = width;
291 h->height = height;
292 h->channels = channels;
293 h->bytesPerPixel = bytesPerPixel;
294 }
295
296 template<typename ValType, ImgOptions OPTIONS>
297 ValType& ImgView<ValType, OPTIONS>::operator()(unsigned dx, unsigned dy, unsigned channel) {
298 auto* h = header();
299 assert(dy < h->height);
300 assert(dx < h->width);
301 assert(channel < h->channels);
302 // this is the only place where row-major / column-major storage is decided
303 // note, definition of row major/column major is confusing for images.
304 // - for a matrix M(i,j) we say it is stored row-major if rows are stored without interleaving: M11, M12,...
305 // - for the same Matrix, if we write M(x,y) for pixel value at coordite (x,y) of an image, this means
306 // that pixel _columns_ are stored without interleaving
307 // So definition used here is opposite to matrix definition.
308 if constexpr((unsigned)OPTIONS & (unsigned)ImgOptions::RowMajor) {
309 return vec()[(dy * h->width + dx) * h->channels + channel];
310 }
311 else {
312 return vec()[(dy + dx * h->height) * h->channels + channel];
313 }
314 }
315
316 template<typename ValType, ImgOptions OPTIONS>
318 return _mi->header();
319 }
320
321 template<typename ValType, ImgOptions OPTIONS>
323 return reinterpret_cast<ValType*>(_mi->imgBody());
324 }
325
326} // 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.
static std::pair< uint32_t, uint32_t > getFormatDefinition(ImgFormat fmt)
Returns a pair of nChannels and nBytesPerPixel matching to the image format.
static 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