MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PixelOps.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * @file PixelOps.hpp
5 * @brief Pointwise pixel operations for MayaFlux::Kinesis::Vision
6 *
7 * Pure functions operating on contiguous normalised float spans.
8 * No MayaFlux type dependencies beyond std.
9 *
10 * ## Conventions
11 * - All inputs are normalised float in [0, 1]
12 * - RGBA layout: r, g, b, a interleaved, 4 floats per pixel
13 * - Gray layout: 1 float per pixel
14 * - w and h are pixel dimensions; callers are responsible for ensuring
15 * span size == w * h * channels
16 * - Parallelism is handled internally via std::execution::par_unseq
17 * - No allocation inside functions except for the returned vector
18 */
19
21
22// ============================================================================
23// Colour space conversion
24// ============================================================================
25
26/**
27 * @brief Convert RGBA to luminance gray using BT.601 coefficients.
28 *
29 * Output is one float per pixel. Alpha channel is discarded.
30 * Coefficients: R*0.299 + G*0.587 + B*0.114
31 *
32 * @param rgba Interleaved RGBA span, size must be w * h * 4.
33 * @param w Image width in pixels.
34 * @param h Image height in pixels.
35 * @return Grayscale float vector of length w * h.
36 */
37[[nodiscard]] MAYAFLUX_API std::vector<float> rgba_to_gray(
38 std::span<const float> rgba, uint32_t w, uint32_t h);
39
40/**
41 * @brief Convert RGBA to luminance gray using BT.601 coefficients.
42 *
43 * Output is one float per pixel. Alpha channel is discarded.
44 * Coefficients: R*0.299 + G*0.587 + B*0.114
45 *
46 * @param rgba Interleaved RGBA span, size must be w * h * 4.
47 * @param dst Output span, size must be w * h.
48 * @param w Image width in pixels.
49 * @param h Image height in pixels.
50 */
51MAYAFLUX_API void rgba_to_gray(std::span<const float> rgba, std::span<float> dst, uint32_t w, uint32_t h);
52
53/**
54 * @brief Convert RGBA to HSV.
55 *
56 * Output is interleaved HSV, 3 floats per pixel.
57 * H in [0, 1] (mapped from [0, 360]), S and V in [0, 1].
58 * Alpha channel is discarded.
59 *
60 * @param rgba Interleaved RGBA span, size must be w * h * 4.
61 * @param w Image width in pixels.
62 * @param h Image height in pixels.
63 * @return Interleaved HSV float vector of length w * h * 3.
64 */
65[[nodiscard]] MAYAFLUX_API std::vector<float> rgba_to_hsv(
66 std::span<const float> rgba, uint32_t w, uint32_t h);
67
68/**
69 * @brief Convert RGBA to HSV writing into caller-supplied buffer.
70 *
71 * Output is interleaved HSV, 3 floats per pixel. H in [0, 1], S and V in [0, 1].
72 * Alpha channel is discarded.
73 *
74 * @param rgba Interleaved RGBA span, size must be w * h * 4.
75 * @param dst Output span, size must be w * h * 3.
76 * @param w Image width in pixels.
77 * @param h Image height in pixels.
78 */
79MAYAFLUX_API void rgba_to_hsv(std::span<const float> rgba, std::span<float> dst, uint32_t w, uint32_t h);
80
81/**
82 * @brief Convert single-channel gray to RGBA.
83 *
84 * R, G, B are all set to the gray value. Alpha is 1.0f.
85 *
86 * @param gray Gray float span, size must be w * h.
87 * @param w Image width in pixels.
88 * @param h Image height in pixels.
89 * @return Interleaved RGBA float vector of length w * h * 4.
90 */
91[[nodiscard]] MAYAFLUX_API std::vector<float> gray_to_rgba(
92 std::span<const float> gray, uint32_t w, uint32_t h);
93
94/**
95 * @brief Global threshold writing into caller-supplied buffer.
96 *
97 * @param gray Input span, size must be w * h.
98 * @param dst Output span, size must be w * h.
99 * @param value Threshold value in [0, 1].
100 */
101MAYAFLUX_API void gray_to_rgba(std::span<const float> gray, std::span<float> dst, uint32_t w, uint32_t h);
102
103// ============================================================================
104// Thresholding
105// ============================================================================
106
107/**
108 * @brief Global threshold: output is 1.0f where input >= value, else 0.0f.
109 *
110 * @param gray Single-channel float span, size must be w * h.
111 * @param value Threshold value in [0, 1].
112 * @return Binary float vector of length w * h.
113 */
114[[nodiscard]] MAYAFLUX_API std::vector<float> threshold(
115 std::span<const float> gray, float value);
116
117/**
118 * @brief Global threshold writing into caller-supplied buffer.
119 *
120 * @param gray Input span, size must be w * h.
121 * @param dst Output span, size must be w * h.
122 * @param value Threshold value in [0, 1].
123 */
124MAYAFLUX_API void threshold(std::span<const float> gray, std::span<float> dst, float value);
125
126/**
127 * @brief Adaptive threshold using local block mean minus offset.
128 *
129 * Each pixel is thresholded against the mean of its block_size x block_size
130 * neighbourhood minus offset. Pixels at the border use a clamped neighbourhood.
131 *
132 * @param gray Single-channel float span, size must be w * h.
133 * @param w Image width in pixels.
134 * @param h Image height in pixels.
135 * @param block_size Neighbourhood size in pixels. Must be odd and >= 3.
136 * @param offset Subtracted from local mean before comparison.
137 * @return Binary float vector of length w * h.
138 */
139[[nodiscard]] MAYAFLUX_API std::vector<float> threshold_adaptive(
140 std::span<const float> gray, uint32_t w, uint32_t h,
141 uint32_t block_size, float offset);
142
143/**
144 * @brief Adaptive threshold writing into caller-supplied buffer.
145 *
146 * Each pixel is thresholded against the mean of its block_size x block_size
147 * neighbourhood minus offset. Pixels at the border use a clamped neighbourhood.
148 *
149 * @param gray Input span, size must be w * h.
150 * @param dst Output span, size must be w * h.
151 * @param w Image width in pixels.
152 * @param h Image height in pixels.
153 * @param block_size Neighbourhood size in pixels. Must be odd and >= 3.
154 * @param offset Subtracted from local mean before comparison.
155 */
156MAYAFLUX_API void threshold_adaptive(std::span<const float> gray, std::span<float> dst, uint32_t w, uint32_t h, uint32_t block_size, float offset);
157
158/**
159 * @brief Otsu threshold: finds the optimal global threshold by maximising
160 * inter-class variance, then applies it.
161 *
162 * @param gray Single-channel float span, size must be w * h.
163 * @return Binary float vector of length w * h.
164 */
165[[nodiscard]] MAYAFLUX_API std::vector<float> threshold_otsu(
166 std::span<const float> gray);
167
168/**
169 * @brief Otsu threshold writing into caller-supplied buffer.
170 *
171 * Finds the optimal global threshold by maximising inter-class variance,
172 * then applies it.
173 *
174 * @param gray Input span, size must be w * h.
175 * @param dst Output span, size must be w * h.
176 */
177MAYAFLUX_API void threshold_otsu(std::span<const float> gray, std::span<float> dst);
178
179// ============================================================================
180// Normalisation
181// ============================================================================
182
183/**
184 * @brief Stretch values to fill [0, 1] using the span's observed min and max.
185 *
186 * No-op if min == max. Operates in-place.
187 *
188 * @param data Float span to normalise in-place.
189 */
190MAYAFLUX_API void normalize_inplace(std::span<float> data);
191
192/**
193 * @brief Clamp and remap values from [lo, hi] to [0, 1] in-place.
194 *
195 * Values outside [lo, hi] are clamped before remapping.
196 *
197 * @param data Float span to remap in-place.
198 * @param lo Input range lower bound.
199 * @param hi Input range upper bound.
200 */
201MAYAFLUX_API void normalize_range_inplace(std::span<float> data, float lo, float hi);
202
203/**
204 * @brief 2x box-filter downsample.
205 *
206 * Each output pixel is the average of the corresponding 2x2 block in src.
207 * Output dimensions are floor(w/2) x floor(h/2). Odd-dimension remainders
208 * are dropped. new_w and new_h are written before return.
209 *
210 * @param src Single-channel float span, size must be w * h.
211 * @param w Input width in pixels.
212 * @param h Input height in pixels.
213 * @param new_w Receives output width (floor(w/2)).
214 * @param new_h Receives output height (floor(h/2)).
215 * @return Downsampled float vector of length new_w * new_h.
216 */
217[[nodiscard]] MAYAFLUX_API std::vector<float> downsample_2x(
218 std::span<const float> src,
219 uint32_t w, uint32_t h,
220 uint32_t& new_w, uint32_t& new_h);
221
222/**
223 * @brief 2x box-filter downsample writing into a caller-supplied buffer.
224 *
225 * @param src Input span, size w * h.
226 * @param dst Output span, size must be >= floor(w/2) * floor(h/2).
227 * @param w Input width in pixels.
228 * @param h Input height in pixels.
229 * @param new_w Receives output width.
230 * @param new_h Receives output height.
231 */
232MAYAFLUX_API void downsample_2x(
233 std::span<const float> src,
234 std::span<float> dst,
235 uint32_t w, uint32_t h,
236 uint32_t& new_w, uint32_t& new_h);
237
238/**
239 * @brief 2x box-filter downsample for multi-channel interleaved data.
240 *
241 * Each output pixel is the per-channel average of the corresponding 2x2
242 * block. Output dimensions are floor(w/2) x floor(h/2).
243 *
244 * @param src Interleaved float span, size must be w * h * channels.
245 * @param dst Output span, size must be >= floor(w/2) * floor(h/2) * channels.
246 * @param w Input width in pixels.
247 * @param h Input height in pixels.
248 * @param channels Channels per pixel (1 = existing behaviour, 4 = RGBA).
249 * @param new_w Receives output width.
250 * @param new_h Receives output height.
251 */
252MAYAFLUX_API void downsample_2x(
253 std::span<const float> src,
254 std::span<float> dst,
255 uint32_t w, uint32_t h,
256 uint32_t channels,
257 uint32_t& new_w, uint32_t& new_h);
258
259} // namespace MayaFlux::Kinesis::Vision
uint32_t h
Definition InkPress.cpp:28
float value
float lo
float threshold
float offset
uint32_t block_size
float hi
void normalize_range_inplace(std::span< float > data, float lo, float hi)
Clamp and remap values from [lo, hi] to [0, 1] in-place.
Definition PixelOps.cpp:398
void rgba_to_gray(std::span< const float > rgba, std::span< float > dst, uint32_t w, uint32_t h)
Convert RGBA to luminance gray using BT.601 coefficients.
Definition PixelOps.cpp:18
void normalize_inplace(std::span< float > data)
Stretch values to fill [0, 1] using the span's observed min and max.
Definition PixelOps.cpp:353
void gray_to_rgba(std::span< const float > gray, std::span< float > dst, uint32_t w, uint32_t h)
Global threshold writing into caller-supplied buffer.
Definition PixelOps.cpp:138
void rgba_to_hsv(std::span< const float > rgba, std::span< float > dst, uint32_t w, uint32_t h)
Convert RGBA to HSV writing into caller-supplied buffer.
Definition PixelOps.cpp:94
void threshold_otsu(std::span< const float > gray, std::span< float > dst)
Otsu threshold writing into caller-supplied buffer.
Definition PixelOps.cpp:299
void threshold_adaptive(std::span< const float > gray, std::span< float > dst, uint32_t w, uint32_t h, uint32_t block_size, float offset)
Adaptive threshold writing into caller-supplied buffer.
Definition PixelOps.cpp:258
void downsample_2x(std::span< const float > src, std::span< float > dst, uint32_t w, uint32_t h, uint32_t &new_w, uint32_t &new_h)
2x box-filter downsample writing into a caller-supplied buffer.
Definition PixelOps.cpp:443