Ocean
Loading...
Searching...
No Matches
IntegralImage.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_CV_INTEGRAL_IMAGE_H
9#define META_OCEAN_CV_INTEGRAL_IMAGE_H
10
11#include "ocean/cv/CV.h"
12
13#include "ocean/base/Frame.h"
14
15#include "ocean/math/Numeric.h"
16
17#include <limits>
18#include <type_traits>
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26/**
27 * This class provides functions to create an integral image from a gray scale image.
28 * @ingroup cv
29 */
30class OCEAN_CV_EXPORT IntegralImage
31{
32 public:
33
34 /**
35 * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
36 * Best practice is to avoid using these functions if binary size matters,<br>
37 * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.<br>
38 */
39 class OCEAN_CV_EXPORT Comfort
40 {
41 public:
42
43 /**
44 * Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
45 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
46 * The resulting lined integral image has the following scheme:
47 * <pre>
48 * ------------ ---------
49 * |000000000000| |
50 * |0|----------| |
51 * |0| | padding |
52 * |0| Integral | |
53 * |0| | |
54 * ------------ ---------
55 * </pre>
56 * The resolution of the integral image is: (width + 1)x(height + 1).
57 * @param frame The frame for which the integral image will be returned, must be valid
58 * @return The resulting integral image, invalid if the pixel format of the given frame is not supported
59 */
60 static Frame createLinedImage(const Frame& frame);
61
62 /**
63 * Creates a bordered integral image from a given 1-plane image and adds an extra border to the resulting integral image.
64 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
65 * The resulting integral image has a (non interfering) border.<br>
66 * The bordered integral image has the following scheme:
67 * <pre>
68 * ------------------------- ---------
69 * |0000000000000000000000000| |
70 * |0|-----------------------| |
71 * |0| | | | |
72 * |0| 0 | 0 | 0 | |
73 * |0| | | | |
74 * |0|-----|-----------|-----| |
75 * |0| | | > | |
76 * |0| | | > | |
77 * |0| 0 | Integral | > | padding |
78 * |0| | | > | |
79 * |0| | | > | |
80 * |0|-----|-----------|-----| |
81 * |0| | | | |
82 * |0| 0 | V | V | |
83 * |0| | | | |
84 * -----------------------------------
85 * </pre>
86 * Columns or rows with '0' receive a null value.<br>
87 * Rows with '>' receive the last valid integral value from the left.<br>
88 * Rows with 'v' receive the last valid integral value from the top.<br>
89 * Further, additionally to the border, the integral image contains one column at the left border and one row at the top border with zeros.<br>
90 * The resolution of the integral image is: (width + 1 + 2 * border)x(height + 1 + 2 * border).
91 * @param frame The image for which the integral image will be returned, with size width x height, must be valid
92 * @param border The thickness of the border in pixel, with range [1, infinity)
93 * @return The resulting integral image, invalid if the pixel format of the given frame is not supported
94 */
95 static Frame createBorderedImage(const Frame& frame, const unsigned int border);
96
97 protected:
98
99 /**
100 * Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
101 * @param frame The frame for which the integral image will be returned, must be valid
102 * @return The resulting integral image, invalid if the pixel format of the given frame is not supported
103 * @tparam T The data type of each frame element
104 * @tparam TIntegral The data type of each integral element
105 */
106 template <typename T, typename TIntegral>
107 static Frame createLinedImage(const Frame& frame);
108
109 /**
110 * Creates a bordered integral image from a given 1-plane image and adds an extra border to the resulting integral image.
111 * @param frame The frame for which the integral image will be returned, must be valid
112 * @param border The thickness of the border in pixel, with range [1, infinity)
113 * @return The resulting integral image, invalid if the pixel format of the given frame is not supported
114 * @tparam T The data type of each frame element
115 * @tparam TIntegral The data type of each integral element
116 */
117 template <typename T, typename TIntegral>
118 static Frame createBorderedImage(const Frame& frame, const unsigned int border);
119 };
120
121 public:
122
123 /**
124 * Creates an integral image from a given 1-plane image.
125 * The resulting integral image will have the same resolution as the given image (without any extra borders).<br>
126 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
127 * The resulting integral image has the following scheme:
128 * <pre>
129 * ---------- ---------
130 * | | |
131 * | Integral | padding |
132 * | | |
133 * ---------- ---------
134 * </pre>
135 * The resolution of the integral image is: width x height.
136 * @param source The source frame for which the integral image will be created, must be valid
137 * @param integral The target integral image, must be valid
138 * @param width The width of the source frame in pixel, with range [0, infinity)
139 * @param height The height of the source frame in pixel, with range [0, infinity)
140 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
141 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
142 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
143 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
144 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
145 * @see createLinedImage().
146 */
147 template <typename T, typename TIntegral, unsigned int tChannels>
148 static void createImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
149
150 /**
151 * Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
152 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
153 * The resulting lined integral image has the following scheme:
154 * <pre>
155 * ------------ ---------
156 * |000000000000| |
157 * |0|----------| |
158 * |0| | padding |
159 * |0| Integral | |
160 * |0| | |
161 * ------------ ---------
162 * </pre>
163 * The resolution of the integral image is: (width + 1)x(height + 1).
164 * @param source The image for which the integral image will be determined, with size width x height, must be valid
165 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
166 * @param width The width of the source frame in pixel, with range [0, infinity)
167 * @param height The height of the source frame in pixel, with range [0, infinity)
168 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
169 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
170 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
171 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
172 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
173 * @see createImage(), createBorderedImage().
174 */
175 template <typename T, typename TIntegral, unsigned int tChannels>
176 static void createLinedImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
177
178 /**
179 * Creates an integral image with squared pixel intensities from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
180 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
181 * The resulting lined integral image has the following scheme:
182 * <pre>
183 * -------------- ---------
184 * |00000000000000| |
185 * |0|------------| |
186 * |0| | padding |
187 * |0| Integral^2 | |
188 * |0| | |
189 * -------------- ---------
190 * </pre>
191 * The resolution of the integral image is: (width + 1)x(height + 1).
192 * @param source The image for which the integral image will be determined, with size width x height, must be valid
193 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
194 * @param width The width of the source frame in pixel, with range [0, infinity)
195 * @param height The height of the source frame in pixel, with range [0, infinity)
196 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
197 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
198 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
199 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
200 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
201 * @see createLinedImageAndSquared(), createImage(), createBorderedImage().
202 */
203 template <typename T, typename TIntegral, unsigned int tChannels>
204 static void createLinedImageSquared(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
205
206 /**
207 * Creates an integral image and squared integral image from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
208 * The resulting integral image provides access to pixel intensities and squared pixel intensities.<br>
209 * Beware: As the same data type is used for both integral data, the depth of the data type must be large enough, or the image resolution must be small enough to avoid overflows.<br>
210 * Pixel intensities and squared pixel intensities are interleaved so that both values can be looked-up at the same memory location.<br>
211 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
212 * The resulting lined integral image has the following scheme:
213 * <pre>
214 * ------------------------------------ ---------
215 * |000000000000000000000000000000000000| |
216 * |00|---------------------------------| |
217 * |00| | padding |
218 * |00| I0 I1 I0^2 I1^2 I0 I1 I0^2 I1^2 | |
219 * |00| | |
220 * ------------------------------------ ---------
221 * With I0 integral value of the first channel,
222 * I1 integral value of the second channel,
223 * I0^2 integral squared value of the first channel,
224 * I1^2 integral squared value of the second channel.
225 * </pre>
226 * The resolution of the integral image is: ((width + 1) * 2)x(height + 1).
227 * @param source The image for which the integral image will be determined, with size width x height, must be valid
228 * @param integralAndSquared The resulting integral (and squared integral) image, with size ((width + 1) * 2)x(height + 1), must be valid
229 * @param width The width of the source frame in pixel, with range [1, infinity)
230 * @param height The height of the source frame in pixel, with range [1, infinity)
231 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
232 * @param integralAndSquaredPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
233 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
234 * @tparam TIntegralAndSquared The data type of each integral (and squared integral) pixel element, e.g., 'unsigned int' or 'double'
235 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
236 * @see createLinedImage(), createLinedImageSquared().
237 */
238 template <typename T, typename TIntegralAndSquared, unsigned int tChannels>
239 static void createLinedImageAndSquared(const T* source, TIntegralAndSquared* integralAndSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralAndSquaredPaddingElements);
240
241 /**
242 * Creates an integral image and squared integral image from a given 1-plane image and adds an extra line (one column and one row) with zeros to the left and top image border.
243 * The result are two individual integral images, one for the pixel intensities and one for the squared pixel intensities.<br>
244 * The resulting lined integral images have the following scheme:
245 * <pre>
246 * Integral image: Integral squared image:
247 * ---------------- --------- ------------------------ ---------
248 * |0000000000000000| | |000000000000000000000000| |
249 * |00|-------------| | |00|---------------------| |
250 * |00| | padding | |00| | padding |
251 * |00| I0 I1 I0 I1 | | |00| I0^2 I1^2 I0^2 I1^2 | |
252 * |00| | | |00| | |
253 * ---------------- --------- ------------------------ ---------
254 * With I0 integral value of the first channel,
255 * I1 integral value of the second channel,
256 * I0^2 integral squared value of the first channel,
257 * I1^2 integral squared value of the second channel.
258 * </pre>
259 * The resolution of the integral image are: (width + 1)x(height + 1).
260 * @param source The image for which the integral image will be determined, with size width x height, must be valid
261 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
262 * @param integralSquared The resulting squared integral image, with size (width + 1)x(height + 1), must be valid
263 * @param width The width of the source frame in pixel, with range [1, infinity)
264 * @param height The height of the source frame in pixel, with range [1, infinity)
265 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
266 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
267 * @param integralSquaredPaddingElements The number of padding elements at the end of each row of the integral squared frame, in elements, with range [0, infinity)
268 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
269 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
270 * @tparam TIntegralSquared The data type of each squared integral pixel element, e.g., 'unsigned int' or 'double'
271 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
272 * @see createLinedImage(), createLinedImageSquared().
273 */
274 template <typename T, typename TIntegral, typename TIntegralSquared, unsigned int tChannels>
275 static void createLinedImageAndSquared(const T* source, TIntegral* integral, TIntegralSquared* integralSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements, const unsigned int integralSquaredPaddingElements);
276
277 /**
278 * Creates a bordered integral image from a given 1-plane image and adds an extra border to the resulting integral image.
279 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
280 * The resulting integral image has a (non interfering) border.<br>
281 * The bordered integral image has the following scheme:
282 * <pre>
283 * ------------------------- ---------
284 * |0000000000000000000000000| |
285 * |0|-----------------------| |
286 * |0| | | | |
287 * |0| 0 | 0 | 0 | |
288 * |0| | | | |
289 * |0|-----|-----------|-----| |
290 * |0| | | > | |
291 * |0| | | > | |
292 * |0| 0 | Integral | > | padding |
293 * |0| | | > | |
294 * |0| | | > | |
295 * |0|-----|-----------|-----| |
296 * |0| | | | |
297 * |0| 0 | V | V | |
298 * |0| | | | |
299 * -----------------------------------
300 * </pre>
301 * Columns or rows with '0' receive a null value.<br>
302 * Rows with '>' receive the last valid integral value from the left.<br>
303 * Rows with 'v' receive the last valid integral value from the top.<br>
304 * Further, additionally to the border, the integral image contains one column at the left border and one row at the top border with zeros.<br>
305 * Therefore, the entire integral image width is: 1 + 2 * border + originalWidth,<br>
306 * and the entire height is: 1 + 2 * border + originalHeight.<br>
307 * @param source The image for which the integral image will be determined, with size width x height, must be valid
308 * @param integral The resulting integral image, with size (width + 1 + 2 * border)x(height + 1 + 2 * border), must be valid
309 * @param width The width of the source frame in pixel, with range [0, infinity)
310 * @param height The height of the source frame in pixel, with range [0, infinity)
311 * @param border The thickness of the border in pixel, with range [1, infinity)
312 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
313 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
314 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
315 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
316 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
317 * @see createLinedImage().
318 */
319 template <typename T, typename TIntegral, unsigned int tChannels>
320 static void createBorderedImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
321
322 /**
323 * Creates a bordered squared integral image from a given 1-plane image and adds an extra border to the resulting integral image.
324 * In case, the given frame has more than one channel, the channels of the resulting integral image will be interleaved (not stored as individual planes).<br>
325 * The resulting integral image has a (non interfering) border.<br>
326 * The bordered integral image has the following scheme:
327 * <pre>
328 * -------------------------- ---------
329 * |00000000000000000000000000| |
330 * |0|------------------------| |
331 * |0| | | | |
332 * |0| 0 | 0 | 0 | |
333 * |0| | | | |
334 * |0|-----|------------|-----| |
335 * |0| | | > | |
336 * |0| | | > | |
337 * |0| 0 | Integral^2 | > | padding |
338 * |0| | | > | |
339 * |0| | | > | |
340 * |0|-----|------------|-----| |
341 * |0| | | | |
342 * |0| 0 | V | V | |
343 * |0| | | | |
344 * ------------------------------------
345 * </pre>
346 * Columns or rows with '0' receive a null value.<br>
347 * Rows with '>' receive the last valid integral value from the left.<br>
348 * Rows with 'v' receive the last valid integral value from the top.<br>
349 * Further, additionally to the border, the integral image contains one column at the left border and one row at the top border with zeros.<br>
350 * Therefore, the entire integral image width is: 1 + 2 * border + originalWidth,<br>
351 * and the entire height is: 1 + 2 * border + originalHeight.<br>
352 * @param source The image for which the integral image will be determined, with size width x height, must be valid
353 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
354 * @param width The width of the source frame in pixel, with range [0, infinity)
355 * @param height The height of the source frame in pixel, with range [0, infinity)
356 * @param border The thickness of the border in pixel, with range [1, infinity)
357 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
358 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
359 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
360 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
361 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
362 * @see createLinedImage().
363 */
364 template <typename T, typename TIntegral, unsigned int tChannels>
365 static void createBorderedImageSquared(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
366
367 /**
368 * Creates a bordered integral image from a given 1-plane image and adds an extra border with mirrored image content to the resulting integral image.
369 * The resulting integral image has an extra border created from the original frame with mirrored border pixels.<br>
370 * Additionally, independent from the border size, the integral image contains one column at the left border and one row at the top border with zeros.<br>
371 * Therefore, the entire integral image width is: 1 + 2 * border + originalWidth,<br>
372 * and the entire height is: 1 + 2 * border + originalHeight.<br>
373 * The bordered integral image has the following scheme:
374 * <pre>
375 * ------------------------- ---------
376 * |0000000000000000000000000| |
377 * |0|-----------------------| |
378 * |0| | | | |
379 * |0| m | mirrored | m | |
380 * |0| | | | |
381 * |0|-----|-----------|-----| |
382 * |0| | | | |
383 * |0| | | | |
384 * |0| m | Integral | m | padding |
385 * |0| | | | |
386 * |0| | | | |
387 * |0|-----|-----------|-----| |
388 * |0| | | | |
389 * |0| m | mirrored | m | |
390 * |0| | | | |
391 * -----------------------------------
392 * </pre>
393 * @param source The image for which the integral image will be determined, with size width x height, must be valid
394 * @param integral The resulting integral image, with size (1 + border + width)x(1 + border + height), must be valid
395 * @param width The width of the source frame in pixel, with range [0, infinity)
396 * @param height The height of the source frame in pixel, with range [0, infinity)
397 * @param border The thickness of the border in pixel, with range [1, min(width, height)]
398 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
399 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
400 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
401 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
402 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
403 */
404 template <typename T, typename TIntegral, unsigned int tChannels>
405 static void createBorderedImageMirror(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
406
407 /**
408 * Creates a bordered squared integral image from a given 1-plane image and adds an extra border with mirrored image content to the resulting integral image.
409 * The resulting integral image has an extra border created from the original frame with mirrored border pixels.<br>
410 * Additionally, independent from the border size, the integral image contains one column at the left border and one row at the top border with zeros.<br>
411 * Therefore, the entire integral image width is: 1 + 2 * border + originalWidth,<br>
412 * and the entire height is: 1 + 2 * border + originalHeight.<br>
413 * The bordered integral image has the following scheme:
414 * <pre>
415 * ------------------------------- ---------
416 * |0000000000000000000000000000000| |
417 * |0|-----------------------------| |
418 * |0| | | | |
419 * |0| m^2 | mirrored^2 | m^2 | |
420 * |0| | | | |
421 * |0|-------|-------------|-------| |
422 * |0| | | | |
423 * |0| | | | |
424 * |0| m^2 | Integral^2 | m^2 | padding |
425 * |0| | | | |
426 * |0| | | | |
427 * |0|-------|-------------|-------| |
428 * |0| | | | |
429 * |0| m^2 | mirrored^2 | m^2 | |
430 * |0| | | | |
431 * -----------------------------------------
432 * </pre>
433 * @param source The image for which the integral image will be determined, with size width x height, must be valid
434 * @param integral The resulting integral image, with size (1 + border + width)x(1 + border + height), must be valid
435 * @param width The width of the source frame in pixel, with range [0, infinity)
436 * @param height The height of the source frame in pixel, with range [0, infinity)
437 * @param border The thickness of the border in pixel, with range [1, min(width, height)]
438 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
439 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
440 * @tparam T The data type of each pixel element of the source frame e.g., 'uint8_t' or 'float'
441 * @tparam TIntegral The data type of each integral pixel element, e.g., 'unsigned int' or 'double'
442 * @tparam tChannels The number of channels the source frame has, with range [1, infinity)
443 */
444 template <typename T, typename TIntegral, unsigned int tChannels>
445 static void createBorderedImageSquaredMirror(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
446
447 /**
448 * Determines the sum of elements within a window from an integral image.
449 * The lined integral image must have the following scheme:
450 * <pre>
451 * integralStrideElements
452 * |<------------------------>|
453 *
454 * ---------------- ---------
455 * |0000000000000000| |
456 * |0|--------------| |
457 * |0| | padding |
458 * |0| Integral | |
459 * |0| | |
460 * ----------------- ---------
461 *
462 * |<------------>|
463 * original width
464 *
465 * |<-------------->|
466 * lined integral width
467 * </pre>
468 * @param linedIntegral The lined integral image, must be valid
469 * @param linedIntegralStrideElements The number of elements between two row start positions in the lined integral image, in elements, may contain padding elements at the end of each row, with range [originalImageWidth + 1, infinity)
470 * @param windowLeft The left starting point of the window, in pixel, with range [0, originalImageWidth - 1]
471 * @param windowTop The top starting point of the window, in pixel, with range [0, originalImageHeight - 1]
472 * @param windowWidth The width of the window, in pixel, with range [1, originalImageWidth - windowLeft]
473 * @param windowHeight The height of the window, in pixel, with range [1, originalImageHeight - windowTop]
474 * @return The resulting sum of elements
475 * @tparam TIntegral The data type of the elements in the integral image
476 */
477 template <typename TIntegral>
478 static OCEAN_FORCE_INLINE TIntegral linedIntegralSum(const TIntegral* const linedIntegral, const unsigned int linedIntegralStrideElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight);
479
480 /**
481 * Determines the variance of elements within a window from two integral images.
482 * Variance is calculated based on the following equation:
483 * <pre>
484 * Var(x) = E[(x - E[x])^2] = E[x^2] - E[x]^2
485 * </pre>
486 * The variance is determined based on the standard lined integral image and the lined integral image for squared values.<br>
487 * The lined integral image must have the following scheme:
488 * <pre>
489 * integralStrideElements integralSquaredStrideElements
490 * |<------------------------>| |<------------------------------>|
491 *
492 * ---------------- --------- -------------------- -----------
493 * |0000000000000000| | |00000000000000000000| |
494 * |0|--------------| | |0|------------------| |
495 * |0| | padding | |0| | padding |
496 * |0| Integral | | |0| Integral^2 | |
497 * |0| | | |0| | |
498 * ----------------- --------- -------------------- -----------
499 *
500 * |<------------>| |<---------------->|
501 * original width original width
502 *
503 * |<-------------->| |<------------------>|
504 * lined integral width lined integral squared width
505 * </pre>
506 * @param linedIntegral The lined integral image, must be valid
507 * @param linedIntegralSquared The lined integral image with squared values, must be valid
508 * @param integralStrideElements The number of elements between two row starts in the lined integral image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
509 * @param integralStrideSquaredElements The number of elements between two row starts in the lined integral squared image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
510 * @param windowLeft The left starting point of the window, in pixel, with range [0, originalImageWidth - 1]
511 * @param windowTop The top starting point of the window, in pixel, with range [0, originalImageHeight - 1]
512 * @param windowWidth The width of the window, in pixel, with range [1, originalImageWidth - windowLeft]
513 * @param windowHeight The height of the window, in pixel, with range [1, originalImageHeight - windowTop]
514 * @param mean Optional resulting mean value and (`tReturnMean = true`), nullptr otherwise (and `tReturnMean = false`)
515 * @return The resulting variance, with range [0, infinity)
516 * @tparam TIntegral The data type of the elements in the integral image
517 * @tparam TIntegralSquared The data type of the elements in the integral squared image
518 * @tparam TVariance The data type of the resulting variance (also used for intermediate calculations)
519 * @tparam tReturnMean True, to return the mean value (`mean` must be defined); False, to skip calculating of mean (`mean` must be nullptr)
520 */
521 template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean = false>
522 static inline TVariance linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight, TVariance* mean = nullptr);
523
524 /**
525 * Determines the variance of elements within two windows from two integral images.
526 * The two windows are treated as one joined area.<br>
527 * Variance is calculated based on the following equation:
528 * <pre>
529 * Var(x) = E[(x - E[x])^2] = E[x^2] - E[x]^2
530 * </pre>
531 * The variance is determined based on the standard lined integral image and the lined integral image for squared values.<br>
532 * The lined integral image must have the following scheme:
533 * <pre>
534 * integralStrideElements integralSquaredStrideElements
535 * |<------------------------>| |<------------------------------>|
536 *
537 * ---------------- --------- -------------------- -----------
538 * |0000000000000000| | |00000000000000000000| |
539 * |0|--------------| | |0|------------------| |
540 * |0| | padding | |0| | padding |
541 * |0| Integral | | |0| Integral^2 | |
542 * |0| | | |0| | |
543 * ----------------- --------- -------------------- -----------
544 *
545 * |<------------>| |<---------------->|
546 * original width original width
547 *
548 * |<-------------->| |<------------------>|
549 * lined integral width lined integral squared width
550 * </pre>
551 * @param linedIntegral The lined integral image, must be valid
552 * @param linedIntegralSquared The lined integral image with squared values, must be valid
553 * @param integralStrideElements The number of elements between two row starts in the lined integral image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
554 * @param integralStrideSquaredElements The number of elements between two row starts in the lined integral squared image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
555 * @param windowALeft The left starting point of the first window, in pixel, with range [0, originalImageWidth - 1]
556 * @param windowATop The top starting point of the first window, in pixel, with range [0, originalImageHeight - 1]
557 * @param windowAWidth The width of the first window, in pixel, with range [1, originalImageWidth - windowALeft]
558 * @param windowAHeight The height of the first window, in pixel, with range [1, originalImageHeight - windowATop]
559 * @param windowBLeft The left starting point of the second window, in pixel, with range [0, originalImageWidth - 1]
560 * @param windowBTop The top starting point of the second window, in pixel, with range [0, originalImageHeight - 1]
561 * @param windowBWidth The width of the second window, in pixel, with range [1, originalImageWidth - windowBLeft]
562 * @param windowBHeight The height of the second window, in pixel, with range [1, originalImageHeight - windowBTop]
563 * @param mean Optional resulting mean value and (`tReturnMean = true`), nullptr otherwise (and `tReturnMean = false`)
564 * @return The resulting variance, with range [0, infinity)
565 * @tparam TIntegral The data type of the elements in the integral image
566 * @tparam TIntegralSquared The data type of the elements in the integral squared image
567 * @tparam TVariance The data type of the resulting variance (also used for intermediate calculations)
568 * @tparam tReturnMean True, to return the mean value (`mean` must be defined); False, to skip calculating of mean (`mean` must be nullptr)
569 */
570 template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean = false>
571 static inline TVariance linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowALeft, const unsigned int windowATop, const unsigned int windowAWidth, const unsigned int windowAHeight, const unsigned int windowBLeft, const unsigned int windowBTop, const unsigned int windowBWidth, const unsigned int windowBHeight, TVariance* mean = nullptr);
572
573 /**
574 * Determines the variance of elements within three windows from two integral images.
575 * The three windows are treated as one joined area.<br>
576 * @param linedIntegral The lined integral image, must be valid
577 * @param linedIntegralSquared The lined integral image with squared values, must be valid
578 * @param integralStrideElements The number of elements between two row starts in the lined integral image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
579 * @param integralStrideSquaredElements The number of elements between two row starts in the lined integral squared image, in elements, may contain padding elements at the end of each row, with range [2, infinity)
580 * @param windowALeft The left starting point of the first window, in pixel, with range [0, originalImageWidth - 1]
581 * @param windowATop The top starting point of the first window, in pixel, with range [0, originalImageHeight - 1]
582 * @param windowAWidth The width of the first window, in pixel, with range [1, originalImageWidth - windowALeft]
583 * @param windowAHeight The height of the first window, in pixel, with range [1, originalImageHeight - windowATop]
584 * @param windowBLeft The left starting point of the second window, in pixel, with range [0, originalImageWidth - 1]
585 * @param windowBTop The top starting point of the second window, in pixel, with range [0, originalImageHeight - 1]
586 * @param windowBWidth The width of the second window, in pixel, with range [1, originalImageWidth - windowBLeft]
587 * @param windowBHeight The height of the second window, in pixel, with range [1, originalImageHeight - windowBTop]
588 * @param windowCLeft The left starting point of the third window, in pixel, with range [0, originalImageWidth - 1]
589 * @param windowCTop The top starting point of the third window, in pixel, with range [0, originalImageHeight - 1]
590 * @param windowCWidth The width of the third window, in pixel, with range [1, originalImageWidth - windowCLeft]
591 * @param windowCHeight The height of the third window, in pixel, with range [1, originalImageHeight - windowCTop]
592 * @param mean Optional resulting mean value and (`tReturnMean = true`), nullptr otherwise (and `tReturnMean = false`)
593 * @return The resulting variance, with range [0, infinity)
594 * @tparam TIntegral The data type of the elements in the integral image
595 * @tparam TIntegralSquared The data type of the elements in the integral squared image
596 * @tparam TVariance The data type of the resulting variance (also used for intermediate calculations)
597 * @tparam tReturnMean True, to return the mean value (`mean` must be defined); False, to skip calculating of mean (`mean` must be nullptr)
598 */
599 template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean = false>
600 static inline TVariance linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowALeft, const unsigned int windowATop, const unsigned int windowAWidth, const unsigned int windowAHeight, const unsigned int windowBLeft, const unsigned int windowBTop, const unsigned int windowBWidth, const unsigned int windowBHeight, const unsigned int windowCLeft, const unsigned int windowCTop, const unsigned int windowCWidth, const unsigned int windowCHeight, TVariance* mean = nullptr);
601
602 private:
603
604#if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
605
606#if defined(__aarch64__)
607
608 /**
609 * Creates an integral image from 8 bit images with 1 channel and adds an extra line with zeros to the left and top image border and applies NEON instructions.
610 * @param source The image for which the integral image will be determined, with size width x height, must be valid
611 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
612 * @param width The width of the given image in pixel, with range [8, 4096^2]
613 * @param height The height of the given image in pixel, with range [1, 4096^2 / width]
614 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
615 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
616 * @see createLinedImage8BitPerChannel<tChannels>().
617 */
618 static void createLinedImage1Channel8BitNEON(const uint8_t* source, uint32_t* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
619
620#endif // defined(__aarch64__)
621
622#endif // OCEAN_HARDWARE_NEON_VERSION >= 10
623
624 /**
625 * Returns the square value of the given parameter.
626 * @param value The value to be squared
627 * @return Square value
628 * @tparam T The data type of the value to be squared
629 * @tparam TSquared The data type of the squared value
630 */
631 template <typename T, typename TSquared>
632 static inline TSquared sqr(const T& value);
633};
634
635template <typename T, typename TIntegral, unsigned int tChannels>
636void IntegralImage::createImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
637{
638 static_assert(std::is_signed<T>::value == std::is_signed<TIntegral>::value, "The integral image must have the same sign-properties as the source image!");
639 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
640 static_assert(tChannels >= 1u, "Invalid channel number!");
641
642 ocean_assert(source != nullptr && integral != nullptr);
643 ocean_assert(width >= 1u && height >= 1u);
644
645 ocean_assert(sizeof(T) >=4 || double(NumericT<T>::maxValue()) * double(width * height) <= double(NumericT<TIntegral>::maxValue()));
646
647 const T* const sourceFirstRowEnd = source + width * tChannels;
648 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
649 const TIntegral* integralPreviousRow = integral;
650
651 TIntegral previousIntegral[tChannels];
652 for (unsigned int n = 0u; n < tChannels; ++n)
653 {
654 previousIntegral[n] = TIntegral(0);
655 }
656
657 // the first row
658
659 while (source != sourceFirstRowEnd)
660 {
661 for (unsigned int n = 0u; n < tChannels; ++n)
662 {
663 previousIntegral[n] += TIntegral(*source++);
664 }
665
666 for (unsigned int n = 0u; n < tChannels; ++n)
667 {
668 *integral++ = previousIntegral[n];
669 }
670 }
671
672 source += sourcePaddingElements;
673 integral += integralPaddingElements;
674
675
676 // the remaining rows
677
678 while (source != sourceEnd)
679 {
680 const T* const sourceRowEnd = source + width * tChannels;
681
682 for (unsigned int n = 0u; n < tChannels; ++n)
683 {
684 previousIntegral[n] = TIntegral(0);
685 }
686
687 while (source != sourceRowEnd)
688 {
689 for (unsigned int n = 0u; n < tChannels; ++n)
690 {
691 previousIntegral[n] += TIntegral(*source++);
692 }
693
694 for (unsigned int n = 0u; n < tChannels; ++n)
695 {
696 *integral++ = previousIntegral[n] + *integralPreviousRow++;
697 }
698 }
699
700 source += sourcePaddingElements;
701 integral += integralPaddingElements;
702 integralPreviousRow += integralPaddingElements;
703 }
704}
705
706template <typename T, typename TIntegral, unsigned int tChannels>
707void IntegralImage::createLinedImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
708{
709 static_assert(std::is_signed<T>::value == std::is_signed<TIntegral>::value, "The integral image must have the same sign-properties as the source image!");
710 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
711 static_assert(tChannels >= 1u, "Invalid channel number!");
712
713 ocean_assert(source != nullptr && integral != nullptr);
714 ocean_assert(width >= 1u && height >= 1u);
715
716 ocean_assert((std::is_floating_point<T>::value) || (double(NumericT<T>::maxValue()) * double(width * height) <= double(NumericT<TIntegral>::maxValue())));
717
718#if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10 && defined(__aarch64__)
719
720 if (std::is_same<T, uint8_t>::value && std::is_same<TIntegral, uint32_t>::value && tChannels == 1u && width >= 8u)
721 {
722 createLinedImage1Channel8BitNEON((const uint8_t*)source, (uint32_t*)integral, width, height, sourcePaddingElements, integralPaddingElements);
723 return;
724 }
725
726#endif // OCEAN_HARDWARE_NEON_VERSION >= 10 && defined(__aarch64__)
727
728 /*
729 * This is the resulting lined integral image.
730 * ------------
731 * |000000000000|
732 * |0|----------|
733 * |0| |
734 * |0| Integral |
735 * |0| |
736 * |------------
737 */
738
739 // entire top line will be set to zero
740 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
741
742#ifdef OCEAN_DEBUG
743 for (unsigned int n = 0u; n < width + 1u; ++n)
744 {
745 ocean_assert(integral[n] == TIntegral(0));
746 }
747#endif
748
749 // we calculate the first row of the integral image
750
751 const T* const sourceFirstRowEnd = source + width * tChannels;
752 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
753
754 integral += (width + 1u) * tChannels + integralPaddingElements;
755 const TIntegral* integralPreviousRow = integral;
756
757 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
758
759 // left pixel
760 for (unsigned int n = 0u; n < tChannels; ++n)
761 {
762 *integral++ = TIntegral(0);
763 }
764
765 // the remaining pixels of the first row
766
767 while (source != sourceFirstRowEnd)
768 {
769 for (unsigned int n = 0u; n < tChannels; ++n)
770 {
771 previousIntegral[n] += *source++;
772 }
773
774 for (unsigned int n = 0u; n < tChannels; ++n)
775 {
776 *integral++ = previousIntegral[n];
777 }
778 }
779
780 source += sourcePaddingElements;
781 integral += integralPaddingElements;
782
783
784 // we calculate the remaining rows
785
786 while (source != sourceEnd)
787 {
788 const T* const sourceRowEnd = source + width * tChannels;
789
790 for (unsigned int n = 0u; n < tChannels; ++n)
791 {
792 previousIntegral[n] = TIntegral(0);
793 }
794
795 // left pixel
796 for (unsigned int n = 0u; n < tChannels; ++n)
797 {
798 *integral++ = TIntegral(0);
799 }
800
801 integralPreviousRow += tChannels;
802
803 while (source != sourceRowEnd)
804 {
805 for (unsigned int n = 0u; n < tChannels; ++n)
806 {
807 previousIntegral[n] += *source++;
808 }
809
810 for (unsigned int n = 0u; n < tChannels; ++n)
811 {
812 *integral++ = previousIntegral[n] + *integralPreviousRow++;
813 }
814 }
815
816 source += sourcePaddingElements;
817 integral += integralPaddingElements;
818 integralPreviousRow += integralPaddingElements;
819 }
820}
821
822template <typename T, typename TIntegral, unsigned int tChannels>
823void IntegralImage::createLinedImageSquared(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
824{
825 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
826 static_assert(tChannels >= 1u, "Invalid channel number!");
827
828 ocean_assert(source != nullptr && integral != nullptr);
829 ocean_assert(width >= 1u && height >= 1u);
830
831 ocean_assert((std::is_floating_point<T>::value) || (NumericD::sqr(double(NumericT<T>::maxValue())) * double(width * height) <= double(NumericT<TIntegral>::maxValue())));
832
833 // entire top line will be set to zero
834 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
835
836#ifdef OCEAN_DEBUG
837 for (unsigned int n = 0u; n < width + 1u; ++n)
838 {
839 ocean_assert(integral[n] == TIntegral(0));
840 }
841#endif
842
843 // we calculate the first row of the integral image
844
845 const T* const sourceFirstRowEnd = source + width * tChannels;
846 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
847
848 integral += (width + 1u) * tChannels + integralPaddingElements;
849 const TIntegral* integralPreviousRow = integral;
850
851 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
852
853 // left pixel
854 for (unsigned int n = 0u; n < tChannels; ++n)
855 {
856 *integral++ = TIntegral(0);
857 }
858
859 // the remaining pixels of the first row
860
861 while (source != sourceFirstRowEnd)
862 {
863 for (unsigned int n = 0u; n < tChannels; ++n)
864 {
865 previousIntegral[n] += *source * *source;
866 ++source;
867 }
868
869 for (unsigned int n = 0u; n < tChannels; ++n)
870 {
871 *integral++ = previousIntegral[n];
872 }
873 }
874
875 source += sourcePaddingElements;
876 integral += integralPaddingElements;
877
878
879 // we calculate the remaining rows
880
881 while (source != sourceEnd)
882 {
883 const T* const sourceRowEnd = source + width * tChannels;
884
885 for (unsigned int n = 0u; n < tChannels; ++n)
886 {
887 previousIntegral[n] = TIntegral(0);
888 }
889
890 // left pixel
891 for (unsigned int n = 0u; n < tChannels; ++n)
892 {
893 *integral++ = TIntegral(0);
894 }
895
896 integralPreviousRow += tChannels;
897
898 while (source != sourceRowEnd)
899 {
900 for (unsigned int n = 0u; n < tChannels; ++n)
901 {
902 previousIntegral[n] += *source * *source;
903 ++source;
904 }
905
906 for (unsigned int n = 0u; n < tChannels; ++n)
907 {
908 *integral++ = previousIntegral[n] + *integralPreviousRow++;
909 }
910 }
911
912 source += sourcePaddingElements;
913 integral += integralPaddingElements;
914 integralPreviousRow += integralPaddingElements;
915 }
916}
917
918template <typename T, typename TIntegralAndSquared, unsigned int tChannels>
919void IntegralImage::createLinedImageAndSquared(const T* source, TIntegralAndSquared* integralAndSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralAndSquaredPaddingElements)
920{
921 static_assert(sizeof(T) <= sizeof(TIntegralAndSquared), "Invalid integral elements!");
922 static_assert(tChannels >= 1u, "Invalid channel number!");
923
924 ocean_assert(source != nullptr && integralAndSquared != nullptr);
925 ocean_assert(width >= 1u && height >= 1u);
926
927 ocean_assert((std::is_floating_point<T>::value) || (NumericD::sqr(double(NumericT<T>::maxValue())) * double(width * height) <= double(NumericT<TIntegralAndSquared>::maxValue())));
928
929 // entire top line will be set to zero
930 memset(integralAndSquared, 0x00, (width + 1u) * tChannels * sizeof(TIntegralAndSquared) * 2u);
931
932#ifdef OCEAN_DEBUG
933 for (unsigned int n = 0u; n < (width + 1u) * 2u; ++n)
934 {
935 ocean_assert(integralAndSquared[n] == TIntegralAndSquared(0));
936 }
937#endif
938
939 // we calculate the first row of the integral image
940
941 const T* const sourceFirstRowEnd = source + width * tChannels;
942 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
943
944 integralAndSquared += (width + 1u) * tChannels * 2u + integralAndSquaredPaddingElements;
945 const TIntegralAndSquared* integralAndSquaredPreviousRow = integralAndSquared;
946
947 TIntegralAndSquared previousIntegral[tChannels] = {TIntegralAndSquared(0)};
948 TIntegralAndSquared previousIntegralSquared[tChannels] = {TIntegralAndSquared(0)};
949
950 // left pixel integral and squared integral
951 for (unsigned int n = 0u; n < tChannels * 2u; ++n)
952 {
953 *integralAndSquared++ = TIntegralAndSquared(0);
954 }
955
956 // the remaining pixels of the first row
957
958 while (source != sourceFirstRowEnd)
959 {
960 for (unsigned int n = 0u; n < tChannels; ++n)
961 {
962 previousIntegral[n] += *source;
963 previousIntegralSquared[n] += *source * *source;
964 ++source;
965 }
966
967 for (unsigned int n = 0u; n < tChannels; ++n)
968 {
969 *integralAndSquared++ = previousIntegral[n];
970 }
971
972 for (unsigned int n = 0u; n < tChannels; ++n)
973 {
974 *integralAndSquared++ = previousIntegralSquared[n];
975 }
976 }
977
978 source += sourcePaddingElements;
979 integralAndSquared += integralAndSquaredPaddingElements;
980
981 // we calculate the remaining rows
982
983 while (source != sourceEnd)
984 {
985 const T* const sourceRowEnd = source + width * tChannels;
986
987 for (unsigned int n = 0u; n < tChannels; ++n)
988 {
989 previousIntegral[n] = TIntegralAndSquared(0);
990 }
991 for (unsigned int n = 0u; n < tChannels; ++n)
992 {
993 previousIntegralSquared[n] = TIntegralAndSquared(0);
994 }
995
996 // left pixel integral and squared integral
997 for (unsigned int n = 0u; n < tChannels * 2u; ++n)
998 {
999 *integralAndSquared++ = TIntegralAndSquared(0);
1000 }
1001
1002 integralAndSquaredPreviousRow += tChannels * 2u;
1003
1004 while (source != sourceRowEnd)
1005 {
1006 for (unsigned int n = 0u; n < tChannels; ++n)
1007 {
1008 previousIntegral[n] += *source;
1009 previousIntegralSquared[n] += *source * *source;
1010 ++source;
1011 }
1012
1013 for (unsigned int n = 0u; n < tChannels; ++n)
1014 {
1015 *integralAndSquared++ = previousIntegral[n] + *integralAndSquaredPreviousRow++;
1016 }
1017 for (unsigned int n = 0u; n < tChannels; ++n)
1018 {
1019 *integralAndSquared++ = previousIntegralSquared[n] + *integralAndSquaredPreviousRow++;
1020 }
1021 }
1022
1023 source += sourcePaddingElements;
1024 integralAndSquared += integralAndSquaredPaddingElements;
1025 integralAndSquaredPreviousRow += integralAndSquaredPaddingElements;
1026 }
1027}
1028
1029template <typename T, typename TIntegral, typename TIntegralSquared, unsigned int tChannels>
1030void IntegralImage::createLinedImageAndSquared(const T* source, TIntegral* integral, TIntegralSquared* integralSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements, const unsigned int integralSquaredPaddingElements)
1031{
1032 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1033 static_assert(sizeof(TIntegral) <= sizeof(TIntegralSquared), "Invalid integral elements!");
1034 static_assert(tChannels >= 1u, "Invalid channel number!");
1035
1036 ocean_assert(source != nullptr && integral != nullptr && integralSquared != nullptr);
1037 ocean_assert(width >= 1u && height >= 1u);
1038
1039 ocean_assert((std::is_floating_point<T>::value) || (double(NumericT<T>::maxValue()) * double(width * height) <= double(NumericT<TIntegral>::maxValue()) && NumericD::sqr(double(NumericT<T>::maxValue())) * double(width * height) <= double(NumericT<TIntegralSquared>::maxValue())));
1040
1041 // entire top line will be set to zero
1042 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
1043 memset(integralSquared, 0x00, (width + 1u) * tChannels * sizeof(TIntegralSquared));
1044
1045#ifdef OCEAN_DEBUG
1046 for (unsigned int n = 0u; n < width + 1u; ++n)
1047 {
1048 ocean_assert(integral[n] == TIntegral(0));
1049 ocean_assert(integralSquared[n] == TIntegralSquared(0));
1050 }
1051#endif
1052
1053 // we calculate the first row of the integral image
1054
1055 const T* const sourceFirstRowEnd = source + width * tChannels;
1056 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
1057
1058 integral += (width + 1u) * tChannels + integralPaddingElements;
1059 integralSquared += (width + 1u) * tChannels + integralSquaredPaddingElements;
1060 const TIntegral* integralPreviousRow = integral;
1061 const TIntegralSquared* integralSquaredPreviousRow = integralSquared;
1062
1063 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1064 TIntegralSquared previousIntegralSquared[tChannels] = {TIntegralSquared(0)};
1065
1066 // left pixel integral
1067 for (unsigned int n = 0u; n < tChannels; ++n)
1068 {
1069 *integral++ = TIntegral(0);
1070 }
1071 // left pixel squared integral
1072 for (unsigned int n = 0u; n < tChannels; ++n)
1073 {
1074 *integralSquared++ = TIntegralSquared(0);
1075 }
1076
1077 // the remaining pixels of the first row
1078
1079 while (source != sourceFirstRowEnd)
1080 {
1081 for (unsigned int n = 0u; n < tChannels; ++n)
1082 {
1083 previousIntegral[n] += *source;
1084 previousIntegralSquared[n] += *source * *source;
1085 ++source;
1086 }
1087
1088 for (unsigned int n = 0u; n < tChannels; ++n)
1089 {
1090 *integral++ = previousIntegral[n];
1091 }
1092
1093 for (unsigned int n = 0u; n < tChannels; ++n)
1094 {
1095 *integralSquared++ = previousIntegralSquared[n];
1096 }
1097 }
1098
1099 source += sourcePaddingElements;
1100 integral += integralPaddingElements;
1101 integralSquared += integralSquaredPaddingElements;
1102
1103 // we calculate the remaining rows
1104
1105 while (source != sourceEnd)
1106 {
1107 const T* const sourceRowEnd = source + width * tChannels;
1108
1109 for (unsigned int n = 0u; n < tChannels; ++n)
1110 {
1111 previousIntegral[n] = TIntegral(0);
1112 }
1113 for (unsigned int n = 0u; n < tChannels; ++n)
1114 {
1115 previousIntegralSquared[n] = TIntegralSquared(0);
1116 }
1117
1118 // left pixel integral
1119 for (unsigned int n = 0u; n < tChannels; ++n)
1120 {
1121 *integral++ = TIntegral(0);
1122 }
1123 // left pixel squared integral
1124 for (unsigned int n = 0u; n < tChannels; ++n)
1125 {
1126 *integralSquared++ = TIntegralSquared(0);
1127 }
1128
1129 integralPreviousRow += tChannels;
1130 integralSquaredPreviousRow += tChannels;
1131
1132 while (source != sourceRowEnd)
1133 {
1134 for (unsigned int n = 0u; n < tChannels; ++n)
1135 {
1136 previousIntegral[n] += *source;
1137 previousIntegralSquared[n] += *source * *source;
1138 ++source;
1139 }
1140
1141 for (unsigned int n = 0u; n < tChannels; ++n)
1142 {
1143 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1144 }
1145 for (unsigned int n = 0u; n < tChannels; ++n)
1146 {
1147 *integralSquared++ = previousIntegralSquared[n] + *integralSquaredPreviousRow++;
1148 }
1149 }
1150
1151 source += sourcePaddingElements;
1152
1153 integral += integralPaddingElements;
1154 integralSquared += integralSquaredPaddingElements;
1155
1156 integralPreviousRow += integralPaddingElements;
1157 integralSquaredPreviousRow += integralSquaredPaddingElements;
1158 }
1159}
1160
1161template <typename T, typename TIntegral, unsigned int tChannels>
1162void IntegralImage::createBorderedImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
1163{
1164 static_assert(std::is_signed<T>::value == std::is_signed<TIntegral>::value, "The integral image must have the same sign-properties as the source image!");
1165 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1166 static_assert(tChannels >= 1u, "Invalid channel number!");
1167
1168 ocean_assert(source != nullptr && integral != nullptr);
1169 ocean_assert(width >= 1u && height >= 1u);
1170 ocean_assert(border >= 1u);
1171
1172 /**
1173 * This is the resulting bordered integral image.
1174 * Columns or rows with '0' receive a null value.
1175 * Rows with '>' receive the last valid integral value from the left
1176 * Rows with 'v' receive the last valid integral value from the top
1177 * -------------------------
1178 * |0000000000000000000000000|
1179 * |0|-----------------------|
1180 * |0| | | |
1181 * |0| 0 | 0 | 0 |
1182 * |0| | | |
1183 * |0|-----|-----------|-----|
1184 * |0| | | > |
1185 * |0| | | > |
1186 * |0| 0 | Integral | > |
1187 * |0| | | > |
1188 * |0| | | > |
1189 * |0|-----|-----------|-----|
1190 * |0| | | |
1191 * |0| 0 | V | V |
1192 * |0| | | |
1193 * -------------------------
1194 */
1195
1196 const unsigned int integralWidth = width + (border * 2u) + 1u;
1197
1198 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1199 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1200
1201 // entire top border (plus the extra zero-row) will be set to zero
1202
1203 if (integralPaddingElements == 0u)
1204 {
1205 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral) * (border + 1u));
1206
1207#ifdef OCEAN_DEBUG
1208 for (unsigned int n = 0u; n < integralWidth; ++n)
1209 {
1210 ocean_assert(integral[n] == TIntegral(0));
1211 }
1212#endif
1213
1214 integral += integralStrideElements * (border + 1u);
1215 }
1216 else
1217 {
1218 for (unsigned int y = 0u; y < border + 1u; ++y)
1219 {
1220 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral));
1221
1222#ifdef OCEAN_DEBUG
1223 for (unsigned int n = 0u; n < integralWidth; ++n)
1224 {
1225 ocean_assert(integral[n] == TIntegral(0));
1226 }
1227#endif
1228
1229 integral += integralStrideElements;
1230 }
1231 }
1232
1233 // computing the first row of the integral image
1234
1235 // setting left border (plus the extra zero-column) to zero
1236 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1237 integral += (border + 1u) * tChannels;
1238
1239 const T* const sourceFirstRowEnd = source + tChannels * width;
1240 const T* const sourceEnd = source + sourceStrideElements * height;
1241 const TIntegral* integralPreviousRow = integral;
1242
1243 TIntegral previousIntegral[tChannels] = {0u};
1244
1245 while (source != sourceFirstRowEnd)
1246 {
1247 for (unsigned int n = 0u; n < tChannels; ++n)
1248 {
1249 previousIntegral[n] += *source++;
1250 }
1251
1252 for (unsigned int n = 0u; n < tChannels; ++n)
1253 {
1254 *integral++ = previousIntegral[n];
1255 }
1256 }
1257
1258 // setting right border to last value
1259
1260 for (unsigned int n = 0u; n < border; ++n)
1261 {
1262 for (unsigned int c = 0u; c < tChannels; ++c)
1263 {
1264 *integral++ = previousIntegral[c];
1265 }
1266 }
1267
1268 integral += integralPaddingElements;
1269 source += sourcePaddingElements;
1270
1271 // computing the following rows of the integral image
1272
1273 while (source != sourceEnd)
1274 {
1275 ocean_assert(source < sourceEnd);
1276
1277 // setting left border (plus the extra zero-column) to zero
1278 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1279 integral += (border + 1u) * tChannels;
1280
1281 const T* const sourceRowEnd = source + tChannels * width;
1282
1283 for (unsigned int n = 0u; n < tChannels; ++n)
1284 {
1285 previousIntegral[n] = TIntegral(0);
1286 }
1287
1288 while (source != sourceRowEnd)
1289 {
1290 for (unsigned int n = 0u; n < tChannels; ++n)
1291 {
1292 previousIntegral[n] += *source++;
1293 }
1294
1295 for (unsigned int n = 0u; n < tChannels; ++n)
1296 {
1297 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1298 }
1299 }
1300
1301 // setting right border to last value
1302
1303 for (unsigned int n = 0u; n < tChannels; ++n)
1304 {
1305 previousIntegral[n] = *(integral - tChannels + n);
1306 }
1307
1308 for (unsigned int n = 0u; n < border; ++n)
1309 {
1310 for (unsigned int c = 0u; c < tChannels; ++c)
1311 {
1312 *integral++ = previousIntegral[c];
1313 }
1314 }
1315
1316 source += sourcePaddingElements;
1317 integral += integralPaddingElements;
1318 integralPreviousRow += (border * 2u + 1u) * tChannels + integralPaddingElements;
1319 }
1320
1321 // bottom border will be set to the last column of the integral image
1322
1323 integralPreviousRow -= (border + 1u) * tChannels;
1324
1325 for (unsigned int n = 0u; n < border; ++n)
1326 {
1327 memcpy(integral, integralPreviousRow, integralWidth * tChannels * sizeof(TIntegral));
1328 integral += integralStrideElements;
1329 }
1330}
1331
1332template <typename T, typename TIntegral, unsigned int tChannels>
1333void IntegralImage::createBorderedImageSquared(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
1334{
1335 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1336 static_assert(tChannels >= 1u, "Invalid channel number!");
1337
1338 ocean_assert(source != nullptr && integral != nullptr);
1339 ocean_assert(width >= 1u && height >= 1u);
1340 ocean_assert(border >= 1u);
1341
1342 /**
1343 * This is the resulting bordered integral image.
1344 * Columns or rows with '0' receive a null value.
1345 * Rows with '>' receive the last valid integral value from the left
1346 * Rows with 'v' receive the last valid integral value from the top
1347 * --------------------------
1348 * |00000000000000000000000000|
1349 * |0|------------------------|
1350 * |0| | | |
1351 * |0| 0 | 0 | 0 |
1352 * |0| | | |
1353 * |0|-----|------------|-----|
1354 * |0| | | > |
1355 * |0| | | > |
1356 * |0| 0 | Integral^2 | > |
1357 * |0| | | > |
1358 * |0| | | > |
1359 * |0|-----|------------|-----|
1360 * |0| | | |
1361 * |0| 0 | V | V |
1362 * |0| | | |
1363 * --------------------------
1364 */
1365
1366 const unsigned int integralWidth = width + (border * 2u) + 1u;
1367
1368 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1369 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1370
1371 // entire top border (plus the extra zero-row) will be set to zero
1372
1373 if (integralPaddingElements == 0u)
1374 {
1375 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral) * (border + 1u));
1376
1377#ifdef OCEAN_DEBUG
1378 for (unsigned int n = 0u; n < integralWidth; ++n)
1379 {
1380 ocean_assert(integral[n] == TIntegral(0));
1381 }
1382#endif
1383
1384 integral += integralStrideElements * (border + 1u);
1385 }
1386 else
1387 {
1388 for (unsigned int y = 0u; y < border + 1u; ++y)
1389 {
1390 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral));
1391
1392#ifdef OCEAN_DEBUG
1393 for (unsigned int n = 0u; n < integralWidth; ++n)
1394 {
1395 ocean_assert(integral[n] == TIntegral(0));
1396 }
1397#endif
1398
1399 integral += integralStrideElements;
1400 }
1401 }
1402
1403 // computing the first row of the integral image
1404
1405 // setting left border (plus the extra zero-column) to zero
1406 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1407 integral += (border + 1u) * tChannels;
1408
1409 const T * const sourceFirstRowEnd = source + tChannels * width;
1410 const T * const sourceEnd = source + sourceStrideElements * height;
1411 const TIntegral * integralPreviousRow = integral;
1412
1413 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1414
1415 while (source != sourceFirstRowEnd)
1416 {
1417 for (unsigned int n = 0u; n < tChannels; ++n)
1418 {
1419 previousIntegral[n] += *source * *source;
1420 source++;
1421 }
1422
1423 for (unsigned int n = 0u; n < tChannels; ++n)
1424 {
1425 *integral++ = previousIntegral[n];
1426 }
1427 }
1428
1429 // setting right border to last value
1430
1431 for (unsigned int n = 0u; n < border; ++n)
1432 {
1433 for (unsigned int c = 0u; c < tChannels; ++c)
1434 {
1435 *integral++ = previousIntegral[c];
1436 }
1437 }
1438
1439 integral += integralPaddingElements;
1440 source += sourcePaddingElements;
1441
1442 // computing the following rows of the integral image
1443
1444 while (source != sourceEnd)
1445 {
1446 ocean_assert(source < sourceEnd);
1447
1448 // setting left border (plus the extra zero-column) to zero
1449 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1450 integral += (border + 1u) * tChannels;
1451
1452 const T * const sourceRowEnd = source + tChannels * width;
1453
1454 for (unsigned int n = 0u; n < tChannels; ++n)
1455 {
1456 previousIntegral[n] = TIntegral(0);
1457 }
1458
1459 while (source != sourceRowEnd)
1460 {
1461 for (unsigned int n = 0u; n < tChannels; ++n)
1462 {
1463 previousIntegral[n] += *source * *source;
1464 source++;
1465 }
1466
1467 for (unsigned int n = 0u; n < tChannels; ++n)
1468 {
1469 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1470 }
1471 }
1472
1473 // setting right border to last value
1474
1475 for (unsigned int n = 0u; n < tChannels; ++n)
1476 {
1477 previousIntegral[n] = *(integral - tChannels + n);
1478 }
1479
1480 for (unsigned int n = 0u; n < border; ++n)
1481 {
1482 for (unsigned int c = 0u; c < tChannels; ++c)
1483 {
1484 *integral++ = previousIntegral[c];
1485 }
1486 }
1487
1488 source += sourcePaddingElements;
1489 integral += integralPaddingElements;
1490 integralPreviousRow += (border * 2u + 1u) * tChannels + integralPaddingElements;
1491 }
1492
1493 // bottom border will be set to the last column of the integral image
1494
1495 integralPreviousRow -= (border + 1u) * tChannels;
1496
1497 for (unsigned int n = 0u; n < border; ++n)
1498 {
1499 memcpy(integral, integralPreviousRow, integralWidth * tChannels * sizeof(TIntegral));
1500 integral += integralStrideElements;
1501 }
1502}
1503
1504template <typename T, typename TIntegral, unsigned int tChannels>
1505void IntegralImage::createBorderedImageMirror(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
1506{
1507 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1508 static_assert(tChannels >= 1u, "Invalid channel number!");
1509
1510 ocean_assert(source != nullptr && integral != nullptr);
1511 ocean_assert(width >= 1u && height >= 1u);
1512 ocean_assert(border >= 1u && border <= min(width, height));
1513
1514 /**
1515 * This is the resulting bordered integral image.
1516 * Columns or rows with '0' receive a null value.
1517 * -------------------------
1518 * |0000000000000000000000000|
1519 * |0|-----------------------|
1520 * |0| | | |
1521 * |0| m | mirrored | m |
1522 * |0| | | |
1523 * |0|-----|-----------|-----|
1524 * |0| | | |
1525 * |0| | | |
1526 * |0| m | Integral | m |
1527 * |0| | | |
1528 * |0| | | |
1529 * |0|-----|-----------|-----|
1530 * |0| | | |
1531 * |0| m | mirrored | m |
1532 * |0| | | |
1533 * -------------------------
1534 */
1535
1536 const unsigned int integralWidth = width + border * 2u + 1u;
1537
1538 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1539 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1540
1541 // entire first row (plus the extra zero-column) will be set to zero
1542 memset(integral, 0, integralWidth * sizeof(TIntegral) * tChannels);
1543 integral += integralStrideElements;
1544
1545 const TIntegral* integralPreviousRow = integral + tChannels;
1546 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1547
1548 const T* sourcePtr = source + sourceStrideElements * (border - 1u);
1549
1550 // setting first column to zero
1551
1552 for (unsigned int n = 0u; n < tChannels; ++n)
1553 {
1554 integral[n] = TIntegral(0);
1555 }
1556 integral += tChannels;
1557
1558 // first row left border
1559
1560 for (unsigned int x = (border - 1u); x != (unsigned int)(-1); --x)
1561 {
1562 for (unsigned int n = 0u; n < tChannels; ++n)
1563 {
1564 previousIntegral[n] += TIntegral(sourcePtr[x * tChannels + n]);
1565 }
1566
1567 for (unsigned int n = 0u; n < tChannels; ++n)
1568 {
1569 *integral++ = previousIntegral[n];
1570 }
1571 }
1572
1573 // first row center pixels
1574
1575 const T* const sourceRowEnd0 = sourcePtr + width * tChannels;
1576 while (sourcePtr != sourceRowEnd0)
1577 {
1578 for (unsigned int n = 0u; n < tChannels; ++n)
1579 {
1580 previousIntegral[n] += TIntegral(*sourcePtr++);
1581 }
1582
1583 for (unsigned int n = 0u; n < tChannels; ++n)
1584 {
1585 *integral++ = previousIntegral[n];
1586 }
1587 }
1588
1589 // first row right border
1590
1591 for (unsigned int x = 0u; x < border; ++x)
1592 {
1593 for (unsigned int n = 0u; n < tChannels; ++n)
1594 {
1595 previousIntegral[n] += TIntegral(*(sourcePtr - int((x + 1u) * tChannels) + int(n)));
1596 }
1597
1598 for (unsigned int n = 0u; n < tChannels; ++n)
1599 {
1600 *integral++ = previousIntegral[n];
1601 }
1602 }
1603
1604 integral += integralPaddingElements;
1605
1606 // following rows
1607
1608 int y = -int(border) + 1;
1609
1610 while (y != int(height + border))
1611 {
1612 if (y < 0)
1613 {
1614 ocean_assert(-y - 1 >= 0 && -y - 1 < int(border));
1615 sourcePtr = source + int(sourceStrideElements) * (-y - 1);
1616 }
1617 else if (y < int(height))
1618 {
1619 sourcePtr = source + int(sourceStrideElements) * y;
1620 }
1621 else
1622 {
1623 sourcePtr = source + int(sourceStrideElements) * (2 * int(height) - y - 1);
1624 }
1625
1626 // left column
1627
1628 for (unsigned int n = 0u; n < tChannels; ++n)
1629 {
1630 previousIntegral[n] = TIntegral(0);
1631 }
1632
1633 for (unsigned int n = 0u; n < tChannels; ++n)
1634 {
1635 *integral++ = TIntegral(0);
1636 }
1637
1638 // left border
1639
1640 for (unsigned int x = border - 1u; x != (unsigned int)(-1); --x)
1641 {
1642 for (unsigned int n = 0u; n < tChannels; ++n)
1643 {
1644 previousIntegral[n] += TIntegral(sourcePtr[x * tChannels + n]);
1645 }
1646
1647 for (unsigned int n = 0u; n < tChannels; ++n)
1648 {
1649 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1650 }
1651 }
1652
1653 // center
1654
1655 const T* const followingSourceRowEnd0 = sourcePtr + width * tChannels;
1656 while (sourcePtr != followingSourceRowEnd0)
1657 {
1658 ocean_assert(sourcePtr < followingSourceRowEnd0);
1659
1660 for (unsigned int n = 0u; n < tChannels; ++n)
1661 {
1662 previousIntegral[n] += TIntegral(*sourcePtr++);
1663 }
1664
1665 for (unsigned int n = 0u; n < tChannels; ++n)
1666 {
1667 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1668 }
1669 }
1670
1671 // right border
1672
1673 for (unsigned int x = 0u; x < border; ++x)
1674 {
1675 for (unsigned int n = 0u; n < tChannels; ++n)
1676 {
1677 previousIntegral[n] += TIntegral(*(sourcePtr - int((x + 1u) * tChannels) + int(n)));
1678 }
1679
1680 for (unsigned int n = 0u; n < tChannels; ++n)
1681 {
1682 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1683 }
1684 }
1685
1686 integral += integralPaddingElements;
1687 integralPreviousRow += tChannels + integralPaddingElements;
1688
1689 ++y;
1690 }
1691}
1692
1693template <typename T, typename TIntegral, unsigned int tChannels>
1694void IntegralImage::createBorderedImageSquaredMirror(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
1695{
1696 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1697 static_assert(tChannels >= 1u, "Invalid channel number!");
1698
1699 ocean_assert(source != nullptr && integral != nullptr);
1700 ocean_assert(width >= 1u && height >= 1u);
1701 ocean_assert(border >= 1u && border <= min(width, height));
1702
1703 /**
1704 * This is the resulting bordered integral image.
1705 * Columns or rows with '0' receive a null value.
1706 * -------------------------------
1707 * |0000000000000000000000000000000|
1708 * |0|-----------------------------|
1709 * |0| | | |
1710 * |0| m^2 | mirrored^2 | m^2 |
1711 * |0| | | |
1712 * |0|-------|-------------|-------|
1713 * |0| | | |
1714 * |0| | | |
1715 * |0| m^2 | Integral^2 | m^2 |
1716 * |0| | | |
1717 * |0| | | |
1718 * |0|-------|-------------|-------|
1719 * |0| | | |
1720 * |0| m^2 | mirrored^2 | m^2 |
1721 * |0| | | |
1722 * -------------------------------
1723 */
1724
1725 const unsigned int integralWidth = width + border * 2u + 1u;
1726
1727 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1728 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1729
1730 // entire first row (plus the extra zero-column) will be set to zero
1731 memset(integral, 0, integralWidth * sizeof(TIntegral) * tChannels);
1732 integral += integralStrideElements;
1733
1734 const TIntegral* integralPreviousRow = integral + tChannels;
1735 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1736
1737 const T* sourcePtr = source + sourceStrideElements * (border - 1u);
1738
1739 // setting first column to zero
1740
1741 for (unsigned int n = 0u; n < tChannels; ++n)
1742 {
1743 integral[n] = TIntegral(0);
1744 }
1745 integral += tChannels;
1746
1747 // first row left border
1748
1749 for (unsigned int x = (border - 1u); x != (unsigned int)(-1); --x)
1750 {
1751 for (unsigned int n = 0u; n < tChannels; ++n)
1752 {
1753 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(sourcePtr[x * tChannels + n]));
1754 }
1755
1756 for (unsigned int n = 0u; n < tChannels; ++n)
1757 {
1758 *integral++ = previousIntegral[n];
1759 }
1760 }
1761
1762 // first row center pixels
1763
1764 const T* const sourceRowEnd0 = sourcePtr + width * tChannels;
1765 while (sourcePtr != sourceRowEnd0)
1766 {
1767 for (unsigned int n = 0u; n < tChannels; ++n)
1768 {
1769 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*sourcePtr++));
1770 }
1771
1772 for (unsigned int n = 0u; n < tChannels; ++n)
1773 {
1774 *integral++ = previousIntegral[n];
1775 }
1776 }
1777
1778 // first row right border
1779
1780 for (unsigned int x = 0u; x < border; ++x)
1781 {
1782 for (unsigned int n = 0u; n < tChannels; ++n)
1783 {
1784 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*(sourcePtr - int((x + 1u) * tChannels) + int(n))));
1785 }
1786
1787 for (unsigned int n = 0u; n < tChannels; ++n)
1788 {
1789 *integral++ = previousIntegral[n];
1790 }
1791 }
1792
1793 integral += integralPaddingElements;
1794
1795 // following rows
1796
1797 int y = -int(border) + 1;
1798
1799 while (y != int(height + border))
1800 {
1801 if (y < 0)
1802 {
1803 ocean_assert(-y - 1 >= 0 && -y - 1 < int(border));
1804 sourcePtr = source + int(sourceStrideElements) * (-y - 1);
1805 }
1806 else if (y < int(height))
1807 {
1808 sourcePtr = source + int(sourceStrideElements) * y;
1809 }
1810 else
1811 {
1812 sourcePtr = source + int(sourceStrideElements) * (2 * int(height) - y - 1);
1813 }
1814
1815 // left column
1816
1817 for (unsigned int n = 0u; n < tChannels; ++n)
1818 {
1819 previousIntegral[n] = TIntegral(0);
1820 }
1821
1822 for (unsigned int n = 0u; n < tChannels; ++n)
1823 {
1824 *integral++ = TIntegral(0);
1825 }
1826
1827 // left border
1828
1829 for (unsigned int x = border - 1u; x != (unsigned int)(-1); --x)
1830 {
1831 for (unsigned int n = 0u; n < tChannels; ++n)
1832 {
1833 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(sourcePtr[x * tChannels + n]));
1834 }
1835
1836 for (unsigned int n = 0u; n < tChannels; ++n)
1837 {
1838 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1839 }
1840 }
1841
1842 // center
1843
1844 const T* const followingSourceRowEnd0 = sourcePtr + width * tChannels;
1845 while (sourcePtr != followingSourceRowEnd0)
1846 {
1847 ocean_assert(sourcePtr < followingSourceRowEnd0);
1848
1849 for (unsigned int n = 0u; n < tChannels; ++n)
1850 {
1851 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*sourcePtr++));
1852 }
1853
1854 for (unsigned int n = 0u; n < tChannels; ++n)
1855 {
1856 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1857 }
1858 }
1859
1860 // right border
1861
1862 for (unsigned int x = 0u; x < border; ++x)
1863 {
1864 for (unsigned int n = 0u; n < tChannels; ++n)
1865 {
1866 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*(sourcePtr - int((x + 1u) * tChannels) + int(n))));
1867 }
1868
1869 for (unsigned int n = 0u; n < tChannels; ++n)
1870 {
1871 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1872 }
1873 }
1874
1875 integral += integralPaddingElements;
1876 integralPreviousRow += tChannels + integralPaddingElements;
1877
1878 ++y;
1879 }
1880}
1881
1882template <typename TIntegral>
1883inline TIntegral IntegralImage::linedIntegralSum(const TIntegral* const linedIntegral, const unsigned int linedIntegralStrideElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight)
1884{
1885 ocean_assert(linedIntegral != nullptr);
1886 ocean_assert(windowLeft + windowWidth < linedIntegralStrideElements);
1887 ocean_assert(windowWidth != 0u);
1888 ocean_assert(windowHeight != 0u);
1889
1890 const unsigned int windowRight = windowLeft + windowWidth;
1891 const unsigned int windowBottom = windowTop + windowHeight;
1892
1893 return linedIntegral[windowTop * linedIntegralStrideElements + windowLeft] - linedIntegral[windowTop * linedIntegralStrideElements + windowRight]
1894 - linedIntegral[windowBottom * linedIntegralStrideElements + windowLeft] + linedIntegral[windowBottom * linedIntegralStrideElements + windowRight];
1895}
1896
1897template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
1898inline TVariance IntegralImage::linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight, TVariance* mean)
1899{
1900 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
1901
1902 ocean_assert(linedIntegral != nullptr);
1903 ocean_assert(windowLeft + windowWidth < integralStrideElements);
1904
1905 ocean_assert(linedIntegralSquared != nullptr);
1906 ocean_assert(windowLeft + windowWidth < integralStrideSquaredElements);
1907
1908 ocean_assert(windowWidth != 0u);
1909 ocean_assert(windowHeight != 0u);
1910
1911 if (windowWidth == 1u && windowHeight == 1u)
1912 {
1913 return TVariance(0);
1914 }
1915
1916 const TIntegral sum = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowLeft, windowTop, windowWidth, windowHeight);
1917 const TIntegralSquared squaredSum = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowLeft, windowTop, windowWidth, windowHeight);
1918
1919 const TVariance size = TVariance(windowWidth * windowHeight);
1920
1921 if constexpr (tReturnMean)
1922 {
1923 ocean_assert(mean != nullptr);
1924 *mean = TVariance(sum) / size;
1925 }
1926 else
1927 {
1928 ocean_assert(mean == nullptr);
1929 }
1930
1931 const TVariance variance = (TVariance(squaredSum) - TVariance(TIntegralSquared(sum) * TIntegralSquared(sum)) / size) / size;
1932
1933 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
1934}
1935
1936template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
1937inline TVariance IntegralImage::linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowALeft, const unsigned int windowATop, const unsigned int windowAWidth, const unsigned int windowAHeight, const unsigned int windowBLeft, const unsigned int windowBTop, const unsigned int windowBWidth, const unsigned int windowBHeight, TVariance* mean)
1938{
1939 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
1940
1941 ocean_assert(linedIntegral != nullptr);
1942 ocean_assert(windowALeft + windowAWidth < integralStrideElements);
1943 ocean_assert(windowBLeft + windowBWidth < integralStrideElements);
1944
1945 ocean_assert(linedIntegralSquared != nullptr);
1946 ocean_assert(windowALeft + windowAWidth < integralStrideSquaredElements);
1947 ocean_assert(windowBLeft + windowBWidth < integralStrideSquaredElements);
1948
1949 ocean_assert(windowAWidth != 0u && windowAHeight != 0u);
1950 ocean_assert(windowBWidth != 0u && windowBHeight != 0u);
1951
1952 const TIntegral sumA = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowALeft, windowATop, windowAWidth, windowAHeight);
1953 const TIntegral sumB = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
1954
1955 const TIntegralSquared squaredSumA = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowALeft, windowATop, windowAWidth, windowAHeight);
1956 const TIntegralSquared squaredSumB = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
1957
1958 const unsigned int sizeA = windowAWidth * windowAHeight;
1959 const unsigned int sizeB = windowBWidth * windowBHeight;
1960 const TVariance size = TVariance(sizeA + sizeB);
1961
1962 const TVariance squaredSum = TVariance(squaredSumA + squaredSumB);
1963 const TIntegralSquared sum = TIntegralSquared(sumA + sumB);
1964
1965 if constexpr (tReturnMean)
1966 {
1967 ocean_assert(mean != nullptr);
1968 *mean = TVariance(sum) / size;
1969 }
1970 else
1971 {
1972 ocean_assert(mean == nullptr);
1973 }
1974
1975 const TVariance variance = (squaredSum - TVariance(sum * sum) / size) / size;
1976
1977 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
1978}
1979
1980template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
1981inline TVariance IntegralImage::linedIntegralVariance(const TIntegral* linedIntegral, const TIntegralSquared* linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowALeft, const unsigned int windowATop, const unsigned int windowAWidth, const unsigned int windowAHeight, const unsigned int windowBLeft, const unsigned int windowBTop, const unsigned int windowBWidth, const unsigned int windowBHeight, const unsigned int windowCLeft, const unsigned int windowCTop, const unsigned int windowCWidth, const unsigned int windowCHeight, TVariance* mean)
1982{
1983 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
1984
1985 ocean_assert(linedIntegral != nullptr);
1986 ocean_assert(windowALeft + windowAWidth < integralStrideElements);
1987 ocean_assert(windowBLeft + windowBWidth < integralStrideElements);
1988 ocean_assert(windowCLeft + windowCWidth < integralStrideElements);
1989
1990 ocean_assert(linedIntegralSquared != nullptr);
1991 ocean_assert(windowALeft + windowAWidth < integralStrideSquaredElements);
1992 ocean_assert(windowBLeft + windowBWidth < integralStrideSquaredElements);
1993 ocean_assert(windowCLeft + windowCWidth < integralStrideSquaredElements);
1994
1995 ocean_assert(windowAWidth != 0u && windowAHeight != 0u);
1996 ocean_assert(windowBWidth != 0u && windowBHeight != 0u);
1997 ocean_assert(windowCWidth != 0u && windowCHeight != 0u);
1998
1999 const TIntegral sumA = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowALeft, windowATop, windowAWidth, windowAHeight);
2000 const TIntegral sumB = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
2001 const TIntegral sumC = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowCLeft, windowCTop, windowCWidth, windowCHeight);
2002
2003 const TIntegralSquared squaredSumA = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowALeft, windowATop, windowAWidth, windowAHeight);
2004 const TIntegralSquared squaredSumB = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
2005 const TIntegralSquared squaredSumC = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowCLeft, windowCTop, windowCWidth, windowCHeight);
2006
2007 const unsigned int sizeA = windowAWidth * windowAHeight;
2008 const unsigned int sizeB = windowBWidth * windowBHeight;
2009 const unsigned int sizeC = windowCWidth * windowCHeight;
2010 const TVariance size = TVariance(sizeA + sizeB + sizeC);
2011
2012 const TVariance squaredSum = TVariance(squaredSumA + squaredSumB + squaredSumC);
2013 const TIntegralSquared sum = TIntegralSquared(sumA + sumB + sumC);
2014
2015 if constexpr (tReturnMean)
2016 {
2017 ocean_assert(mean != nullptr);
2018 *mean = TVariance(sum) / size;
2019 }
2020 else
2021 {
2022 ocean_assert(mean == nullptr);
2023 }
2024
2025 const TVariance variance = (squaredSum - TVariance(sum * sum) / size) / size;
2026
2027 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
2028}
2029
2030template <typename T, typename TSquared>
2031inline TSquared IntegralImage::sqr(const T& value)
2032{
2033 return TSquared(value * value);
2034}
2035
2036}
2037
2038}
2039
2040#endif // META_OCEAN_CV_INTEGRAL_IMAGE_H
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition IntegralImage.h:40
static Frame createBorderedImage(const Frame &frame, const unsigned int border)
Creates a bordered integral image from a given 1-plane image and adds an extra border to the resultin...
static Frame createBorderedImage(const Frame &frame, const unsigned int border)
Creates a bordered integral image from a given 1-plane image and adds an extra border to the resultin...
static Frame createLinedImage(const Frame &frame)
Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) ...
static Frame createLinedImage(const Frame &frame)
Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) ...
This class provides functions to create an integral image from a gray scale image.
Definition IntegralImage.h:31
static void createBorderedImageMirror(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates a bordered integral image from a given 1-plane image and adds an extra border with mirrored i...
Definition IntegralImage.h:1505
static void createLinedImage1Channel8BitNEON(const uint8_t *source, uint32_t *integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates an integral image from 8 bit images with 1 channel and adds an extra line with zeros to the l...
static void createLinedImageSquared(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates an integral image with squared pixel intensities from a given 1-plane image and adds an extra...
Definition IntegralImage.h:823
static TVariance linedIntegralVariance(const TIntegral *linedIntegral, const TIntegralSquared *linedIntegralSquared, const unsigned int integralStrideElements, const unsigned int integralStrideSquaredElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight, TVariance *mean=nullptr)
Determines the variance of elements within a window from two integral images.
Definition IntegralImage.h:1898
static void createImage(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates an integral image from a given 1-plane image.
Definition IntegralImage.h:636
static void createBorderedImageSquaredMirror(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates a bordered squared integral image from a given 1-plane image and adds an extra border with mi...
Definition IntegralImage.h:1694
static TSquared sqr(const T &value)
Returns the square value of the given parameter.
Definition IntegralImage.h:2031
static void createBorderedImage(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates a bordered integral image from a given 1-plane image and adds an extra border to the resultin...
Definition IntegralImage.h:1162
static void createLinedImageAndSquared(const T *source, TIntegralAndSquared *integralAndSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralAndSquaredPaddingElements)
Creates an integral image and squared integral image from a given 1-plane image and adds an extra lin...
Definition IntegralImage.h:919
static OCEAN_FORCE_INLINE TIntegral linedIntegralSum(const TIntegral *const linedIntegral, const unsigned int linedIntegralStrideElements, const unsigned int windowLeft, const unsigned int windowTop, const unsigned int windowWidth, const unsigned int windowHeight)
Determines the sum of elements within a window from an integral image.
static void createBorderedImageSquared(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int border, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates a bordered squared integral image from a given 1-plane image and adds an extra border to the ...
Definition IntegralImage.h:1333
static void createLinedImage(const T *source, TIntegral *integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
Creates an integral image from a given 1-plane image and adds an extra line (one column and one row) ...
Definition IntegralImage.h:707
This class implements Ocean's image class.
Definition Frame.h:1808
This class provides basic numeric functionalities.
Definition Numeric.h:57
static constexpr T sqr(const T value)
Returns the square of a given value.
Definition Numeric.h:1495
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition base/Utilities.h:1029
The namespace covering the entire Ocean framework.
Definition Accessor.h:15