mmcfilters
Public API documentation
Loading...
Searching...
No Matches
Image.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <memory>
9#include <cstdint>
10#include <cstddef>
11#include <algorithm>
12#include <utility>
13#include <cstdlib>
14#include <limits>
15#include <stdexcept>
16
17#include "Common.hpp"
18#include "Contract.hpp"
19
20namespace mmcfilters {
21
22namespace detail {
23class CommittedImageAccess;
24}
25
43template <typename PixelType> class Image {
44 private:
45 friend class detail::CommittedImageAccess;
46 struct EstablishedDimensionsTag {};
48 int numRows;
50 int numColumns;
52 std::shared_ptr<PixelType[]> data;
54 using Ptr = std::shared_ptr<Image<PixelType>>;
55
63 static std::size_t checkedSize(int rows, int columns) {
64 MMCFILTERS_CONTRACT_REQUIRE(rows > 0 && columns > 0, throw std::invalid_argument("Image dimensions must be positive."));
65 const auto rowCount = static_cast<std::size_t>(rows);
66 const auto columnCount = static_cast<std::size_t>(columns);
67 MMCFILTERS_CONTRACT_REQUIRE(rowCount <= static_cast<std::size_t>(std::numeric_limits<int>::max()) / columnCount,
68 throw std::overflow_error("Image dimensions exceed the supported int-indexed size."));
69 return rowCount * columnCount;
70 }
71
78 Image(int rows, int columns, [[maybe_unused]] EstablishedDimensionsTag tag)
79 : numRows(rows), numColumns(columns),
80 data(new PixelType[static_cast<std::size_t>(rows) * static_cast<std::size_t>(columns)], [](PixelType* pixels) { delete[] pixels; }) {}
81
82 public:
84 using Type = PixelType;
85
94 Image(int rows, int columns) : numRows(rows), numColumns(columns), data(new PixelType[checkedSize(rows, columns)], [](PixelType* pixels) { delete[] pixels; }) {}
95
105 [[nodiscard]] static Ptr create(int rows, int columns) { return std::make_shared<Image>(rows, columns); }
106
117 [[nodiscard]] static Ptr create(int rows, int columns, PixelType initValue) {
118 auto img = create(rows, columns);
119 img->fill(initValue);
120 return img;
121 }
122
136 [[nodiscard]] static Ptr fromExternal(PixelType* rawPtr, int rows, int columns) {
137 MMCFILTERS_CONTRACT_REQUIRE(rawPtr != nullptr, throw std::invalid_argument("Image::fromExternal requires a non-null raw pointer."));
138 auto img = create(rows, columns);
139 img->data = std::shared_ptr<PixelType[]>(rawPtr, [](PixelType*) {
140 // Empty deleter: the wrapper does not release external memory.
141 });
142 return img;
143 }
144
155 [[nodiscard]] static Ptr fromRaw(PixelType* rawPtr, int rows, int columns) {
156 MMCFILTERS_CONTRACT_REQUIRE(rawPtr != nullptr, throw std::invalid_argument("Image::fromRaw requires a non-null raw pointer."));
157 auto img = create(rows, columns);
158 img->data = std::shared_ptr<PixelType[]>(rawPtr, [](PixelType* pixels) { delete[] pixels; });
159 return img;
160 }
161
169 void fill(PixelType value) { std::fill_n(data.get(), numRows * numColumns, value); }
170
179 bool isEqual(const Ptr& other) const {
180 if (numRows != other->numRows || numColumns != other->numColumns)
181 return false;
182 int n = numRows * numColumns;
183 for (int i = 0; i < n; ++i) {
184 if (data[i] != (*other)[i])
185 return false;
186 }
187 return true;
188 }
189
197 [[nodiscard]] Ptr clone() const {
198 auto newImg = create(numRows, numColumns);
199 std::copy(data.get(), data.get() + (numRows * numColumns), newImg->data.get());
200 return newImg;
201 }
202
212 std::shared_ptr<PixelType[]> rawDataPtr() { return data; }
213
222 PixelType* rawData() { return data.get(); }
223
229 int getNumRows() const { return numRows; }
230
236 int getNumColumns() const { return numColumns; }
237
243 int getSize() const { return numRows * numColumns; }
244
254 PixelType& operator[](PixelId index) { return data[index]; }
255
265 const PixelType& operator[](PixelId index) const { return data[index]; }
266};
267
274
276using ImageUInt8Ptr = std::shared_ptr<ImageUInt8>;
278using ImageInt32Ptr = std::shared_ptr<ImageInt32>;
280using ImageFloatPtr = std::shared_ptr<ImageFloat>;
281
285template <typename PixelType> using ImagePtr = std::shared_ptr<Image<PixelType>>;
286
294 public:
303 inline static PixelId to1D(int row, int column, int numColumns) noexcept { return row * numColumns + column; }
304
312 inline static std::pair<int, int> to2D(PixelId index, int numColumns) noexcept {
313 int row = index / numColumns;
314 int column = index - row * numColumns;
315 return {row, column};
316 }
317
332 int max = 0;
334 for (int i = 0; i < sizeImage; i++) {
335 if (img[i] > max)
336 max = img[i];
337 }
338
339 std::unique_ptr<int[]> r(new int[max + 1]);
340 std::unique_ptr<int[]> g(new int[max + 1]);
341 std::unique_ptr<int[]> b(new int[max + 1]);
342 r[0] = 0;
343 g[0] = 0;
344 r[0] = 0;
345 for (int i = 1; i <= max; i++) {
346 r[i] = rand() % 256;
347 g[i] = rand() % 256;
348 b[i] = rand() % 256;
349 }
350
351 int sizeOutput = sizeImage * 3; // [(R,G,B), (R,G,B), ...]
352 ImageUInt8Ptr outImage = ImageUInt8::create(numRowsOfImage, numColumnsOfImage * 3);
353
354 auto output = outImage->rawData();
355 // Initialise with zero.
356 std::fill_n(output, sizeOutput, 0);
357
358 for (int pidx = 0; pidx < sizeImage; pidx++) {
359 int cpidx = pidx * 3; // (coloured) for 3 channels
360 output[cpidx] = r[img[pidx]];
361 output[cpidx + 1] = g[img[pidx]];
362 output[cpidx + 2] = b[img[pidx]];
363 }
364 return outImage;
365 }
366};
367
368} // namespace mmcfilters
Shared scalar conventions used by the C++ API.
Compile-time policy for defensive checks at untrusted API boundaries.
#define MMCFILTERS_CONTRACT_REQUIRE(condition,...)
Evaluates a caller precondition and its failure action only in checked builds.
Definition Contract.hpp:53
std::shared_ptr< ImageFloat > ImageFloatPtr
Shared pointer to a single-precision floating-point image.
Definition Image.hpp:280
std::shared_ptr< ImageInt32 > ImageInt32Ptr
Shared pointer to a 32-bit signed integer image.
Definition Image.hpp:278
std::shared_ptr< Image< PixelType > > ImagePtr
Shared pointer alias for an image with arbitrary pixel type.
Definition Image.hpp:285
std::shared_ptr< ImageUInt8 > ImageUInt8Ptr
Shared pointer to an 8-bit unsigned image.
Definition Image.hpp:276
Utility functions for basic image conversion and manipulation.
Definition Image.hpp:293
static ImageUInt8Ptr createRandomColor(int *img, int numRowsOfImage, int numColumnsOfImage)
Creates a random-colour visualisation from an integer-labelled image.
Definition Image.hpp:331
static std::pair< int, int > to2D(PixelId index, int numColumns) noexcept
Converts a row-major linear index to (row, column).
Definition Image.hpp:312
static PixelId to1D(int row, int column, int numColumns) noexcept
Converts (row, column) to a row-major linear index.
Definition Image.hpp:303
Generic row-major 2D image with contiguous storage and shared ownership.
Definition Image.hpp:43
int getNumColumns() const
Returns the number of image columns.
Definition Image.hpp:236
int getSize() const
Returns the total number of pixels.
Definition Image.hpp:243
PixelType & operator[](PixelId index)
Returns mutable linear access to pixel index.
Definition Image.hpp:254
static Ptr fromRaw(PixelType *rawPtr, int rows, int columns)
Wraps row-major memory and takes ownership through delete[].
Definition Image.hpp:155
void fill(PixelType value)
Fills every pixel with value.
Definition Image.hpp:169
bool isEqual(const Ptr &other) const
Returns true when shape and pixel values match other.
Definition Image.hpp:179
Image(int rows, int columns)
Allocates an owned row-major image buffer.
Definition Image.hpp:94
static Ptr create(int rows, int columns, PixelType initValue)
Creates an owned image and fills every pixel with initValue.
Definition Image.hpp:117
Ptr clone() const
Returns a deep copy with its own owned buffer.
Definition Image.hpp:197
static Ptr fromExternal(PixelType *rawPtr, int rows, int columns)
Wraps external row-major memory without taking ownership.
Definition Image.hpp:136
PixelType * rawData()
Returns a mutable pointer to the contiguous row-major buffer.
Definition Image.hpp:222
static Ptr create(int rows, int columns)
Creates an owned image with uninitialised pixel values.
Definition Image.hpp:105
std::shared_ptr< PixelType[]> rawDataPtr()
Returns the shared pointer that owns or wraps the raw buffer.
Definition Image.hpp:212
const PixelType & operator[](PixelId index) const
Returns immutable linear access to pixel index.
Definition Image.hpp:265
int getNumRows() const
Returns the number of image rows.
Definition Image.hpp:229
Owning result for one computed scalar attribute layout and buffer.