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_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
605
606 /**
607 * 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 SSE instructions.
608 * @param source The image for which the integral image will be determined, with size width x height, must be valid
609 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
610 * @param width The width of the given image in pixel, with range [8, 4096^2]
611 * @param height The height of the given image in pixel, with range [1, 4096^2 / width]
612 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
613 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
614 * @see createLinedImage8BitPerChannel<tChannels>().
615 */
616 static void createLinedImage1Channel8BitSSE(const uint8_t* source, uint32_t* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements);
617
618#endif // OCEAN_HARDWARE_SSE_VERSION >= 41
619
620#if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
621
622#if defined(__aarch64__)
623
624 /**
625 * 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.
626 * @param source The image for which the integral image will be determined, with size width x height, must be valid
627 * @param integral The resulting integral image, with size (width + 1)x(height + 1), must be valid
628 * @param width The width of the given image in pixel, with range [8, 4096^2]
629 * @param height The height of the given image in pixel, with range [1, 4096^2 / width]
630 * @param sourcePaddingElements The number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
631 * @param integralPaddingElements The number of padding elements at the end of each row of the integral frame, in elements, with range [0, infinity)
632 * @see createLinedImage8BitPerChannel<tChannels>().
633 */
634 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);
635
636#endif // defined(__aarch64__)
637
638#endif // OCEAN_HARDWARE_NEON_VERSION >= 10
639
640 /**
641 * Returns the square value of the given parameter.
642 * @param value The value to be squared
643 * @return Square value
644 * @tparam T The data type of the value to be squared
645 * @tparam TSquared The data type of the squared value
646 */
647 template <typename T, typename TSquared>
648 static inline TSquared sqr(const T& value);
649};
650
651template <typename T, typename TIntegral, unsigned int tChannels>
652void IntegralImage::createImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
653{
654 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!");
655 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
656 static_assert(tChannels >= 1u, "Invalid channel number!");
657
658 ocean_assert(source != nullptr && integral != nullptr);
659 ocean_assert(width >= 1u && height >= 1u);
660
661 ocean_assert(sizeof(T) >=4 || double(NumericT<T>::maxValue()) * double(width * height) <= double(NumericT<TIntegral>::maxValue()));
662
663 const T* const sourceFirstRowEnd = source + width * tChannels;
664 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
665 const TIntegral* integralPreviousRow = integral;
666
667 TIntegral previousIntegral[tChannels];
668 for (unsigned int n = 0u; n < tChannels; ++n)
669 {
670 previousIntegral[n] = TIntegral(0);
671 }
672
673 // the first row
674
675 while (source != sourceFirstRowEnd)
676 {
677 for (unsigned int n = 0u; n < tChannels; ++n)
678 {
679 previousIntegral[n] += TIntegral(*source++);
680 }
681
682 for (unsigned int n = 0u; n < tChannels; ++n)
683 {
684 *integral++ = previousIntegral[n];
685 }
686 }
687
688 source += sourcePaddingElements;
689 integral += integralPaddingElements;
690
691
692 // the remaining rows
693
694 while (source != sourceEnd)
695 {
696 const T* const sourceRowEnd = source + width * tChannels;
697
698 for (unsigned int n = 0u; n < tChannels; ++n)
699 {
700 previousIntegral[n] = TIntegral(0);
701 }
702
703 while (source != sourceRowEnd)
704 {
705 for (unsigned int n = 0u; n < tChannels; ++n)
706 {
707 previousIntegral[n] += TIntegral(*source++);
708 }
709
710 for (unsigned int n = 0u; n < tChannels; ++n)
711 {
712 *integral++ = previousIntegral[n] + *integralPreviousRow++;
713 }
714 }
715
716 source += sourcePaddingElements;
717 integral += integralPaddingElements;
718 integralPreviousRow += integralPaddingElements;
719 }
720}
721
722template <typename T, typename TIntegral, unsigned int tChannels>
723void IntegralImage::createLinedImage(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
724{
725 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!");
726 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
727 static_assert(tChannels >= 1u, "Invalid channel number!");
728
729 ocean_assert(source != nullptr && integral != nullptr);
730 ocean_assert(width >= 1u && height >= 1u);
731
732 ocean_assert((std::is_floating_point<T>::value) || (double(NumericT<T>::maxValue()) * double(width * height) <= double(NumericT<TIntegral>::maxValue())));
733
734#if defined(OCEAN_HARDWARE_SSE_VERSION) && OCEAN_HARDWARE_SSE_VERSION >= 41
735
736 if (std::is_same<T, uint8_t>::value && std::is_same<TIntegral, uint32_t>::value && tChannels == 1u && width >= 8u)
737 {
738 createLinedImage1Channel8BitSSE((const uint8_t*)source, (uint32_t*)integral, width, height, sourcePaddingElements, integralPaddingElements);
739 return;
740 }
741
742#endif // OCEAN_HARDWARE_SSE_VERSION >= 41
743
744#if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10 && defined(__aarch64__)
745
746 if (std::is_same<T, uint8_t>::value && std::is_same<TIntegral, uint32_t>::value && tChannels == 1u && width >= 8u)
747 {
748 createLinedImage1Channel8BitNEON((const uint8_t*)source, (uint32_t*)integral, width, height, sourcePaddingElements, integralPaddingElements);
749 return;
750 }
751
752#endif // OCEAN_HARDWARE_NEON_VERSION >= 10 && defined(__aarch64__)
753
754 /*
755 * This is the resulting lined integral image.
756 * ------------
757 * |000000000000|
758 * |0|----------|
759 * |0| |
760 * |0| Integral |
761 * |0| |
762 * |------------
763 */
764
765 // entire top line will be set to zero
766 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
767
768#ifdef OCEAN_DEBUG
769 for (unsigned int n = 0u; n < width + 1u; ++n)
770 {
771 ocean_assert(integral[n] == TIntegral(0));
772 }
773#endif
774
775 // we calculate the first row of the integral image
776
777 const T* const sourceFirstRowEnd = source + width * tChannels;
778 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
779
780 integral += (width + 1u) * tChannels + integralPaddingElements;
781 const TIntegral* integralPreviousRow = integral;
782
783 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
784
785 // left pixel
786 for (unsigned int n = 0u; n < tChannels; ++n)
787 {
788 *integral++ = TIntegral(0);
789 }
790
791 // the remaining pixels of the first row
792
793 while (source != sourceFirstRowEnd)
794 {
795 for (unsigned int n = 0u; n < tChannels; ++n)
796 {
797 previousIntegral[n] += *source++;
798 }
799
800 for (unsigned int n = 0u; n < tChannels; ++n)
801 {
802 *integral++ = previousIntegral[n];
803 }
804 }
805
806 source += sourcePaddingElements;
807 integral += integralPaddingElements;
808
809
810 // we calculate the remaining rows
811
812 while (source != sourceEnd)
813 {
814 const T* const sourceRowEnd = source + width * tChannels;
815
816 for (unsigned int n = 0u; n < tChannels; ++n)
817 {
818 previousIntegral[n] = TIntegral(0);
819 }
820
821 // left pixel
822 for (unsigned int n = 0u; n < tChannels; ++n)
823 {
824 *integral++ = TIntegral(0);
825 }
826
827 integralPreviousRow += tChannels;
828
829 while (source != sourceRowEnd)
830 {
831 for (unsigned int n = 0u; n < tChannels; ++n)
832 {
833 previousIntegral[n] += *source++;
834 }
835
836 for (unsigned int n = 0u; n < tChannels; ++n)
837 {
838 *integral++ = previousIntegral[n] + *integralPreviousRow++;
839 }
840 }
841
842 source += sourcePaddingElements;
843 integral += integralPaddingElements;
844 integralPreviousRow += integralPaddingElements;
845 }
846}
847
848template <typename T, typename TIntegral, unsigned int tChannels>
849void IntegralImage::createLinedImageSquared(const T* source, TIntegral* integral, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralPaddingElements)
850{
851 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
852 static_assert(tChannels >= 1u, "Invalid channel number!");
853
854 ocean_assert(source != nullptr && integral != nullptr);
855 ocean_assert(width >= 1u && height >= 1u);
856
857 ocean_assert((std::is_floating_point<T>::value) || (NumericD::sqr(double(NumericT<T>::maxValue())) * double(width * height) <= double(NumericT<TIntegral>::maxValue())));
858
859 // entire top line will be set to zero
860 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
861
862#ifdef OCEAN_DEBUG
863 for (unsigned int n = 0u; n < width + 1u; ++n)
864 {
865 ocean_assert(integral[n] == TIntegral(0));
866 }
867#endif
868
869 // we calculate the first row of the integral image
870
871 const T* const sourceFirstRowEnd = source + width * tChannels;
872 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
873
874 integral += (width + 1u) * tChannels + integralPaddingElements;
875 const TIntegral* integralPreviousRow = integral;
876
877 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
878
879 // left pixel
880 for (unsigned int n = 0u; n < tChannels; ++n)
881 {
882 *integral++ = TIntegral(0);
883 }
884
885 // the remaining pixels of the first row
886
887 while (source != sourceFirstRowEnd)
888 {
889 for (unsigned int n = 0u; n < tChannels; ++n)
890 {
891 previousIntegral[n] += *source * *source;
892 ++source;
893 }
894
895 for (unsigned int n = 0u; n < tChannels; ++n)
896 {
897 *integral++ = previousIntegral[n];
898 }
899 }
900
901 source += sourcePaddingElements;
902 integral += integralPaddingElements;
903
904
905 // we calculate the remaining rows
906
907 while (source != sourceEnd)
908 {
909 const T* const sourceRowEnd = source + width * tChannels;
910
911 for (unsigned int n = 0u; n < tChannels; ++n)
912 {
913 previousIntegral[n] = TIntegral(0);
914 }
915
916 // left pixel
917 for (unsigned int n = 0u; n < tChannels; ++n)
918 {
919 *integral++ = TIntegral(0);
920 }
921
922 integralPreviousRow += tChannels;
923
924 while (source != sourceRowEnd)
925 {
926 for (unsigned int n = 0u; n < tChannels; ++n)
927 {
928 previousIntegral[n] += *source * *source;
929 ++source;
930 }
931
932 for (unsigned int n = 0u; n < tChannels; ++n)
933 {
934 *integral++ = previousIntegral[n] + *integralPreviousRow++;
935 }
936 }
937
938 source += sourcePaddingElements;
939 integral += integralPaddingElements;
940 integralPreviousRow += integralPaddingElements;
941 }
942}
943
944template <typename T, typename TIntegralAndSquared, unsigned int tChannels>
945void IntegralImage::createLinedImageAndSquared(const T* source, TIntegralAndSquared* integralAndSquared, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int integralAndSquaredPaddingElements)
946{
947 static_assert(sizeof(T) <= sizeof(TIntegralAndSquared), "Invalid integral elements!");
948 static_assert(tChannels >= 1u, "Invalid channel number!");
949
950 ocean_assert(source != nullptr && integralAndSquared != nullptr);
951 ocean_assert(width >= 1u && height >= 1u);
952
953 ocean_assert((std::is_floating_point<T>::value) || (NumericD::sqr(double(NumericT<T>::maxValue())) * double(width * height) <= double(NumericT<TIntegralAndSquared>::maxValue())));
954
955 // entire top line will be set to zero
956 memset(integralAndSquared, 0x00, (width + 1u) * tChannels * sizeof(TIntegralAndSquared) * 2u);
957
958#ifdef OCEAN_DEBUG
959 for (unsigned int n = 0u; n < (width + 1u) * 2u; ++n)
960 {
961 ocean_assert(integralAndSquared[n] == TIntegralAndSquared(0));
962 }
963#endif
964
965 // we calculate the first row of the integral image
966
967 const T* const sourceFirstRowEnd = source + width * tChannels;
968 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
969
970 integralAndSquared += (width + 1u) * tChannels * 2u + integralAndSquaredPaddingElements;
971 const TIntegralAndSquared* integralAndSquaredPreviousRow = integralAndSquared;
972
973 TIntegralAndSquared previousIntegral[tChannels] = {TIntegralAndSquared(0)};
974 TIntegralAndSquared previousIntegralSquared[tChannels] = {TIntegralAndSquared(0)};
975
976 // left pixel integral and squared integral
977 for (unsigned int n = 0u; n < tChannels * 2u; ++n)
978 {
979 *integralAndSquared++ = TIntegralAndSquared(0);
980 }
981
982 // the remaining pixels of the first row
983
984 while (source != sourceFirstRowEnd)
985 {
986 for (unsigned int n = 0u; n < tChannels; ++n)
987 {
988 previousIntegral[n] += *source;
989 previousIntegralSquared[n] += *source * *source;
990 ++source;
991 }
992
993 for (unsigned int n = 0u; n < tChannels; ++n)
994 {
995 *integralAndSquared++ = previousIntegral[n];
996 }
997
998 for (unsigned int n = 0u; n < tChannels; ++n)
999 {
1000 *integralAndSquared++ = previousIntegralSquared[n];
1001 }
1002 }
1003
1004 source += sourcePaddingElements;
1005 integralAndSquared += integralAndSquaredPaddingElements;
1006
1007 // we calculate the remaining rows
1008
1009 while (source != sourceEnd)
1010 {
1011 const T* const sourceRowEnd = source + width * tChannels;
1012
1013 for (unsigned int n = 0u; n < tChannels; ++n)
1014 {
1015 previousIntegral[n] = TIntegralAndSquared(0);
1016 }
1017 for (unsigned int n = 0u; n < tChannels; ++n)
1018 {
1019 previousIntegralSquared[n] = TIntegralAndSquared(0);
1020 }
1021
1022 // left pixel integral and squared integral
1023 for (unsigned int n = 0u; n < tChannels * 2u; ++n)
1024 {
1025 *integralAndSquared++ = TIntegralAndSquared(0);
1026 }
1027
1028 integralAndSquaredPreviousRow += tChannels * 2u;
1029
1030 while (source != sourceRowEnd)
1031 {
1032 for (unsigned int n = 0u; n < tChannels; ++n)
1033 {
1034 previousIntegral[n] += *source;
1035 previousIntegralSquared[n] += *source * *source;
1036 ++source;
1037 }
1038
1039 for (unsigned int n = 0u; n < tChannels; ++n)
1040 {
1041 *integralAndSquared++ = previousIntegral[n] + *integralAndSquaredPreviousRow++;
1042 }
1043 for (unsigned int n = 0u; n < tChannels; ++n)
1044 {
1045 *integralAndSquared++ = previousIntegralSquared[n] + *integralAndSquaredPreviousRow++;
1046 }
1047 }
1048
1049 source += sourcePaddingElements;
1050 integralAndSquared += integralAndSquaredPaddingElements;
1051 integralAndSquaredPreviousRow += integralAndSquaredPaddingElements;
1052 }
1053}
1054
1055template <typename T, typename TIntegral, typename TIntegralSquared, unsigned int tChannels>
1056void 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)
1057{
1058 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1059 static_assert(sizeof(TIntegral) <= sizeof(TIntegralSquared), "Invalid integral elements!");
1060 static_assert(tChannels >= 1u, "Invalid channel number!");
1061
1062 ocean_assert(source != nullptr && integral != nullptr && integralSquared != nullptr);
1063 ocean_assert(width >= 1u && height >= 1u);
1064
1065 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())));
1066
1067 // entire top line will be set to zero
1068 memset(integral, 0x00, (width + 1u) * tChannels * sizeof(TIntegral));
1069 memset(integralSquared, 0x00, (width + 1u) * tChannels * sizeof(TIntegralSquared));
1070
1071#ifdef OCEAN_DEBUG
1072 for (unsigned int n = 0u; n < width + 1u; ++n)
1073 {
1074 ocean_assert(integral[n] == TIntegral(0));
1075 ocean_assert(integralSquared[n] == TIntegralSquared(0));
1076 }
1077#endif
1078
1079 // we calculate the first row of the integral image
1080
1081 const T* const sourceFirstRowEnd = source + width * tChannels;
1082 const T* const sourceEnd = source + (width * tChannels + sourcePaddingElements) * height;
1083
1084 integral += (width + 1u) * tChannels + integralPaddingElements;
1085 integralSquared += (width + 1u) * tChannels + integralSquaredPaddingElements;
1086 const TIntegral* integralPreviousRow = integral;
1087 const TIntegralSquared* integralSquaredPreviousRow = integralSquared;
1088
1089 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1090 TIntegralSquared previousIntegralSquared[tChannels] = {TIntegralSquared(0)};
1091
1092 // left pixel integral
1093 for (unsigned int n = 0u; n < tChannels; ++n)
1094 {
1095 *integral++ = TIntegral(0);
1096 }
1097 // left pixel squared integral
1098 for (unsigned int n = 0u; n < tChannels; ++n)
1099 {
1100 *integralSquared++ = TIntegralSquared(0);
1101 }
1102
1103 // the remaining pixels of the first row
1104
1105 while (source != sourceFirstRowEnd)
1106 {
1107 for (unsigned int n = 0u; n < tChannels; ++n)
1108 {
1109 previousIntegral[n] += *source;
1110 previousIntegralSquared[n] += *source * *source;
1111 ++source;
1112 }
1113
1114 for (unsigned int n = 0u; n < tChannels; ++n)
1115 {
1116 *integral++ = previousIntegral[n];
1117 }
1118
1119 for (unsigned int n = 0u; n < tChannels; ++n)
1120 {
1121 *integralSquared++ = previousIntegralSquared[n];
1122 }
1123 }
1124
1125 source += sourcePaddingElements;
1126 integral += integralPaddingElements;
1127 integralSquared += integralSquaredPaddingElements;
1128
1129 // we calculate the remaining rows
1130
1131 while (source != sourceEnd)
1132 {
1133 const T* const sourceRowEnd = source + width * tChannels;
1134
1135 for (unsigned int n = 0u; n < tChannels; ++n)
1136 {
1137 previousIntegral[n] = TIntegral(0);
1138 }
1139 for (unsigned int n = 0u; n < tChannels; ++n)
1140 {
1141 previousIntegralSquared[n] = TIntegralSquared(0);
1142 }
1143
1144 // left pixel integral
1145 for (unsigned int n = 0u; n < tChannels; ++n)
1146 {
1147 *integral++ = TIntegral(0);
1148 }
1149 // left pixel squared integral
1150 for (unsigned int n = 0u; n < tChannels; ++n)
1151 {
1152 *integralSquared++ = TIntegralSquared(0);
1153 }
1154
1155 integralPreviousRow += tChannels;
1156 integralSquaredPreviousRow += tChannels;
1157
1158 while (source != sourceRowEnd)
1159 {
1160 for (unsigned int n = 0u; n < tChannels; ++n)
1161 {
1162 previousIntegral[n] += *source;
1163 previousIntegralSquared[n] += *source * *source;
1164 ++source;
1165 }
1166
1167 for (unsigned int n = 0u; n < tChannels; ++n)
1168 {
1169 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1170 }
1171 for (unsigned int n = 0u; n < tChannels; ++n)
1172 {
1173 *integralSquared++ = previousIntegralSquared[n] + *integralSquaredPreviousRow++;
1174 }
1175 }
1176
1177 source += sourcePaddingElements;
1178
1179 integral += integralPaddingElements;
1180 integralSquared += integralSquaredPaddingElements;
1181
1182 integralPreviousRow += integralPaddingElements;
1183 integralSquaredPreviousRow += integralSquaredPaddingElements;
1184 }
1185}
1186
1187template <typename T, typename TIntegral, unsigned int tChannels>
1188void 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)
1189{
1190 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!");
1191 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1192 static_assert(tChannels >= 1u, "Invalid channel number!");
1193
1194 ocean_assert(source != nullptr && integral != nullptr);
1195 ocean_assert(width >= 1u && height >= 1u);
1196 ocean_assert(border >= 1u);
1197
1198 /**
1199 * This is the resulting bordered integral image.
1200 * Columns or rows with '0' receive a null value.
1201 * Rows with '>' receive the last valid integral value from the left
1202 * Rows with 'v' receive the last valid integral value from the top
1203 * -------------------------
1204 * |0000000000000000000000000|
1205 * |0|-----------------------|
1206 * |0| | | |
1207 * |0| 0 | 0 | 0 |
1208 * |0| | | |
1209 * |0|-----|-----------|-----|
1210 * |0| | | > |
1211 * |0| | | > |
1212 * |0| 0 | Integral | > |
1213 * |0| | | > |
1214 * |0| | | > |
1215 * |0|-----|-----------|-----|
1216 * |0| | | |
1217 * |0| 0 | V | V |
1218 * |0| | | |
1219 * -------------------------
1220 */
1221
1222 const unsigned int integralWidth = width + (border * 2u) + 1u;
1223
1224 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1225 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1226
1227 // entire top border (plus the extra zero-row) will be set to zero
1228
1229 if (integralPaddingElements == 0u)
1230 {
1231 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral) * (border + 1u));
1232
1233#ifdef OCEAN_DEBUG
1234 for (unsigned int n = 0u; n < integralWidth; ++n)
1235 {
1236 ocean_assert(integral[n] == TIntegral(0));
1237 }
1238#endif
1239
1240 integral += integralStrideElements * (border + 1u);
1241 }
1242 else
1243 {
1244 for (unsigned int y = 0u; y < border + 1u; ++y)
1245 {
1246 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral));
1247
1248#ifdef OCEAN_DEBUG
1249 for (unsigned int n = 0u; n < integralWidth; ++n)
1250 {
1251 ocean_assert(integral[n] == TIntegral(0));
1252 }
1253#endif
1254
1255 integral += integralStrideElements;
1256 }
1257 }
1258
1259 // computing the first row of the integral image
1260
1261 // setting left border (plus the extra zero-column) to zero
1262 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1263 integral += (border + 1u) * tChannels;
1264
1265 const T* const sourceFirstRowEnd = source + tChannels * width;
1266 const T* const sourceEnd = source + sourceStrideElements * height;
1267 const TIntegral* integralPreviousRow = integral;
1268
1269 TIntegral previousIntegral[tChannels] = {0u};
1270
1271 while (source != sourceFirstRowEnd)
1272 {
1273 for (unsigned int n = 0u; n < tChannels; ++n)
1274 {
1275 previousIntegral[n] += *source++;
1276 }
1277
1278 for (unsigned int n = 0u; n < tChannels; ++n)
1279 {
1280 *integral++ = previousIntegral[n];
1281 }
1282 }
1283
1284 // setting right border to last value
1285
1286 for (unsigned int n = 0u; n < border; ++n)
1287 {
1288 for (unsigned int c = 0u; c < tChannels; ++c)
1289 {
1290 *integral++ = previousIntegral[c];
1291 }
1292 }
1293
1294 integral += integralPaddingElements;
1295 source += sourcePaddingElements;
1296
1297 // computing the following rows of the integral image
1298
1299 while (source != sourceEnd)
1300 {
1301 ocean_assert(source < sourceEnd);
1302
1303 // setting left border (plus the extra zero-column) to zero
1304 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1305 integral += (border + 1u) * tChannels;
1306
1307 const T* const sourceRowEnd = source + tChannels * width;
1308
1309 for (unsigned int n = 0u; n < tChannels; ++n)
1310 {
1311 previousIntegral[n] = TIntegral(0);
1312 }
1313
1314 while (source != sourceRowEnd)
1315 {
1316 for (unsigned int n = 0u; n < tChannels; ++n)
1317 {
1318 previousIntegral[n] += *source++;
1319 }
1320
1321 for (unsigned int n = 0u; n < tChannels; ++n)
1322 {
1323 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1324 }
1325 }
1326
1327 // setting right border to last value
1328
1329 for (unsigned int n = 0u; n < tChannels; ++n)
1330 {
1331 previousIntegral[n] = *(integral - tChannels + n);
1332 }
1333
1334 for (unsigned int n = 0u; n < border; ++n)
1335 {
1336 for (unsigned int c = 0u; c < tChannels; ++c)
1337 {
1338 *integral++ = previousIntegral[c];
1339 }
1340 }
1341
1342 source += sourcePaddingElements;
1343 integral += integralPaddingElements;
1344 integralPreviousRow += (border * 2u + 1u) * tChannels + integralPaddingElements;
1345 }
1346
1347 // bottom border will be set to the last column of the integral image
1348
1349 integralPreviousRow -= (border + 1u) * tChannels;
1350
1351 for (unsigned int n = 0u; n < border; ++n)
1352 {
1353 memcpy(integral, integralPreviousRow, integralWidth * tChannels * sizeof(TIntegral));
1354 integral += integralStrideElements;
1355 }
1356}
1357
1358template <typename T, typename TIntegral, unsigned int tChannels>
1359void 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)
1360{
1361 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1362 static_assert(tChannels >= 1u, "Invalid channel number!");
1363
1364 ocean_assert(source != nullptr && integral != nullptr);
1365 ocean_assert(width >= 1u && height >= 1u);
1366 ocean_assert(border >= 1u);
1367
1368 /**
1369 * This is the resulting bordered integral image.
1370 * Columns or rows with '0' receive a null value.
1371 * Rows with '>' receive the last valid integral value from the left
1372 * Rows with 'v' receive the last valid integral value from the top
1373 * --------------------------
1374 * |00000000000000000000000000|
1375 * |0|------------------------|
1376 * |0| | | |
1377 * |0| 0 | 0 | 0 |
1378 * |0| | | |
1379 * |0|-----|------------|-----|
1380 * |0| | | > |
1381 * |0| | | > |
1382 * |0| 0 | Integral^2 | > |
1383 * |0| | | > |
1384 * |0| | | > |
1385 * |0|-----|------------|-----|
1386 * |0| | | |
1387 * |0| 0 | V | V |
1388 * |0| | | |
1389 * --------------------------
1390 */
1391
1392 const unsigned int integralWidth = width + (border * 2u) + 1u;
1393
1394 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1395 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1396
1397 // entire top border (plus the extra zero-row) will be set to zero
1398
1399 if (integralPaddingElements == 0u)
1400 {
1401 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral) * (border + 1u));
1402
1403#ifdef OCEAN_DEBUG
1404 for (unsigned int n = 0u; n < integralWidth; ++n)
1405 {
1406 ocean_assert(integral[n] == TIntegral(0));
1407 }
1408#endif
1409
1410 integral += integralStrideElements * (border + 1u);
1411 }
1412 else
1413 {
1414 for (unsigned int y = 0u; y < border + 1u; ++y)
1415 {
1416 memset(integral, 0x00, integralWidth * tChannels * sizeof(TIntegral));
1417
1418#ifdef OCEAN_DEBUG
1419 for (unsigned int n = 0u; n < integralWidth; ++n)
1420 {
1421 ocean_assert(integral[n] == TIntegral(0));
1422 }
1423#endif
1424
1425 integral += integralStrideElements;
1426 }
1427 }
1428
1429 // computing the first row of the integral image
1430
1431 // setting left border (plus the extra zero-column) to zero
1432 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1433 integral += (border + 1u) * tChannels;
1434
1435 const T * const sourceFirstRowEnd = source + tChannels * width;
1436 const T * const sourceEnd = source + sourceStrideElements * height;
1437 const TIntegral * integralPreviousRow = integral;
1438
1439 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1440
1441 while (source != sourceFirstRowEnd)
1442 {
1443 for (unsigned int n = 0u; n < tChannels; ++n)
1444 {
1445 previousIntegral[n] += *source * *source;
1446 source++;
1447 }
1448
1449 for (unsigned int n = 0u; n < tChannels; ++n)
1450 {
1451 *integral++ = previousIntegral[n];
1452 }
1453 }
1454
1455 // setting right border to last value
1456
1457 for (unsigned int n = 0u; n < border; ++n)
1458 {
1459 for (unsigned int c = 0u; c < tChannels; ++c)
1460 {
1461 *integral++ = previousIntegral[c];
1462 }
1463 }
1464
1465 integral += integralPaddingElements;
1466 source += sourcePaddingElements;
1467
1468 // computing the following rows of the integral image
1469
1470 while (source != sourceEnd)
1471 {
1472 ocean_assert(source < sourceEnd);
1473
1474 // setting left border (plus the extra zero-column) to zero
1475 memset(integral, 0x00, (border + 1u) * tChannels * sizeof(TIntegral));
1476 integral += (border + 1u) * tChannels;
1477
1478 const T * const sourceRowEnd = source + tChannels * width;
1479
1480 for (unsigned int n = 0u; n < tChannels; ++n)
1481 {
1482 previousIntegral[n] = TIntegral(0);
1483 }
1484
1485 while (source != sourceRowEnd)
1486 {
1487 for (unsigned int n = 0u; n < tChannels; ++n)
1488 {
1489 previousIntegral[n] += *source * *source;
1490 source++;
1491 }
1492
1493 for (unsigned int n = 0u; n < tChannels; ++n)
1494 {
1495 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1496 }
1497 }
1498
1499 // setting right border to last value
1500
1501 for (unsigned int n = 0u; n < tChannels; ++n)
1502 {
1503 previousIntegral[n] = *(integral - tChannels + n);
1504 }
1505
1506 for (unsigned int n = 0u; n < border; ++n)
1507 {
1508 for (unsigned int c = 0u; c < tChannels; ++c)
1509 {
1510 *integral++ = previousIntegral[c];
1511 }
1512 }
1513
1514 source += sourcePaddingElements;
1515 integral += integralPaddingElements;
1516 integralPreviousRow += (border * 2u + 1u) * tChannels + integralPaddingElements;
1517 }
1518
1519 // bottom border will be set to the last column of the integral image
1520
1521 integralPreviousRow -= (border + 1u) * tChannels;
1522
1523 for (unsigned int n = 0u; n < border; ++n)
1524 {
1525 memcpy(integral, integralPreviousRow, integralWidth * tChannels * sizeof(TIntegral));
1526 integral += integralStrideElements;
1527 }
1528}
1529
1530template <typename T, typename TIntegral, unsigned int tChannels>
1531void 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)
1532{
1533 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1534 static_assert(tChannels >= 1u, "Invalid channel number!");
1535
1536 ocean_assert(source != nullptr && integral != nullptr);
1537 ocean_assert(width >= 1u && height >= 1u);
1538 ocean_assert(border >= 1u && border <= min(width, height));
1539
1540 /**
1541 * This is the resulting bordered integral image.
1542 * Columns or rows with '0' receive a null value.
1543 * -------------------------
1544 * |0000000000000000000000000|
1545 * |0|-----------------------|
1546 * |0| | | |
1547 * |0| m | mirrored | m |
1548 * |0| | | |
1549 * |0|-----|-----------|-----|
1550 * |0| | | |
1551 * |0| | | |
1552 * |0| m | Integral | m |
1553 * |0| | | |
1554 * |0| | | |
1555 * |0|-----|-----------|-----|
1556 * |0| | | |
1557 * |0| m | mirrored | m |
1558 * |0| | | |
1559 * -------------------------
1560 */
1561
1562 const unsigned int integralWidth = width + border * 2u + 1u;
1563
1564 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1565 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1566
1567 // entire first row (plus the extra zero-column) will be set to zero
1568 memset(integral, 0, integralWidth * sizeof(TIntegral) * tChannels);
1569 integral += integralStrideElements;
1570
1571 const TIntegral* integralPreviousRow = integral + tChannels;
1572 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1573
1574 const T* sourcePtr = source + sourceStrideElements * (border - 1u);
1575
1576 // setting first column to zero
1577
1578 for (unsigned int n = 0u; n < tChannels; ++n)
1579 {
1580 integral[n] = TIntegral(0);
1581 }
1582 integral += tChannels;
1583
1584 // first row left border
1585
1586 for (unsigned int x = (border - 1u); x != (unsigned int)(-1); --x)
1587 {
1588 for (unsigned int n = 0u; n < tChannels; ++n)
1589 {
1590 previousIntegral[n] += TIntegral(sourcePtr[x * tChannels + n]);
1591 }
1592
1593 for (unsigned int n = 0u; n < tChannels; ++n)
1594 {
1595 *integral++ = previousIntegral[n];
1596 }
1597 }
1598
1599 // first row center pixels
1600
1601 const T* const sourceRowEnd0 = sourcePtr + width * tChannels;
1602 while (sourcePtr != sourceRowEnd0)
1603 {
1604 for (unsigned int n = 0u; n < tChannels; ++n)
1605 {
1606 previousIntegral[n] += TIntegral(*sourcePtr++);
1607 }
1608
1609 for (unsigned int n = 0u; n < tChannels; ++n)
1610 {
1611 *integral++ = previousIntegral[n];
1612 }
1613 }
1614
1615 // first row right border
1616
1617 for (unsigned int x = 0u; x < border; ++x)
1618 {
1619 for (unsigned int n = 0u; n < tChannels; ++n)
1620 {
1621 previousIntegral[n] += TIntegral(*(sourcePtr - int((x + 1u) * tChannels) + int(n)));
1622 }
1623
1624 for (unsigned int n = 0u; n < tChannels; ++n)
1625 {
1626 *integral++ = previousIntegral[n];
1627 }
1628 }
1629
1630 integral += integralPaddingElements;
1631
1632 // following rows
1633
1634 int y = -int(border) + 1;
1635
1636 while (y != int(height + border))
1637 {
1638 if (y < 0)
1639 {
1640 ocean_assert(-y - 1 >= 0 && -y - 1 < int(border));
1641 sourcePtr = source + int(sourceStrideElements) * (-y - 1);
1642 }
1643 else if (y < int(height))
1644 {
1645 sourcePtr = source + int(sourceStrideElements) * y;
1646 }
1647 else
1648 {
1649 sourcePtr = source + int(sourceStrideElements) * (2 * int(height) - y - 1);
1650 }
1651
1652 // left column
1653
1654 for (unsigned int n = 0u; n < tChannels; ++n)
1655 {
1656 previousIntegral[n] = TIntegral(0);
1657 }
1658
1659 for (unsigned int n = 0u; n < tChannels; ++n)
1660 {
1661 *integral++ = TIntegral(0);
1662 }
1663
1664 // left border
1665
1666 for (unsigned int x = border - 1u; x != (unsigned int)(-1); --x)
1667 {
1668 for (unsigned int n = 0u; n < tChannels; ++n)
1669 {
1670 previousIntegral[n] += TIntegral(sourcePtr[x * tChannels + n]);
1671 }
1672
1673 for (unsigned int n = 0u; n < tChannels; ++n)
1674 {
1675 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1676 }
1677 }
1678
1679 // center
1680
1681 const T* const followingSourceRowEnd0 = sourcePtr + width * tChannels;
1682 while (sourcePtr != followingSourceRowEnd0)
1683 {
1684 ocean_assert(sourcePtr < followingSourceRowEnd0);
1685
1686 for (unsigned int n = 0u; n < tChannels; ++n)
1687 {
1688 previousIntegral[n] += TIntegral(*sourcePtr++);
1689 }
1690
1691 for (unsigned int n = 0u; n < tChannels; ++n)
1692 {
1693 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1694 }
1695 }
1696
1697 // right border
1698
1699 for (unsigned int x = 0u; x < border; ++x)
1700 {
1701 for (unsigned int n = 0u; n < tChannels; ++n)
1702 {
1703 previousIntegral[n] += TIntegral(*(sourcePtr - int((x + 1u) * tChannels) + int(n)));
1704 }
1705
1706 for (unsigned int n = 0u; n < tChannels; ++n)
1707 {
1708 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1709 }
1710 }
1711
1712 integral += integralPaddingElements;
1713 integralPreviousRow += tChannels + integralPaddingElements;
1714
1715 ++y;
1716 }
1717}
1718
1719template <typename T, typename TIntegral, unsigned int tChannels>
1720void 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)
1721{
1722 static_assert(sizeof(T) <= sizeof(TIntegral), "Invalid integral elements!");
1723 static_assert(tChannels >= 1u, "Invalid channel number!");
1724
1725 ocean_assert(source != nullptr && integral != nullptr);
1726 ocean_assert(width >= 1u && height >= 1u);
1727 ocean_assert(border >= 1u && border <= min(width, height));
1728
1729 /**
1730 * This is the resulting bordered integral image.
1731 * Columns or rows with '0' receive a null value.
1732 * -------------------------------
1733 * |0000000000000000000000000000000|
1734 * |0|-----------------------------|
1735 * |0| | | |
1736 * |0| m^2 | mirrored^2 | m^2 |
1737 * |0| | | |
1738 * |0|-------|-------------|-------|
1739 * |0| | | |
1740 * |0| | | |
1741 * |0| m^2 | Integral^2 | m^2 |
1742 * |0| | | |
1743 * |0| | | |
1744 * |0|-------|-------------|-------|
1745 * |0| | | |
1746 * |0| m^2 | mirrored^2 | m^2 |
1747 * |0| | | |
1748 * -------------------------------
1749 */
1750
1751 const unsigned int integralWidth = width + border * 2u + 1u;
1752
1753 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1754 const unsigned int integralStrideElements = integralWidth * tChannels + integralPaddingElements;
1755
1756 // entire first row (plus the extra zero-column) will be set to zero
1757 memset(integral, 0, integralWidth * sizeof(TIntegral) * tChannels);
1758 integral += integralStrideElements;
1759
1760 const TIntegral* integralPreviousRow = integral + tChannels;
1761 TIntegral previousIntegral[tChannels] = {TIntegral(0)};
1762
1763 const T* sourcePtr = source + sourceStrideElements * (border - 1u);
1764
1765 // setting first column to zero
1766
1767 for (unsigned int n = 0u; n < tChannels; ++n)
1768 {
1769 integral[n] = TIntegral(0);
1770 }
1771 integral += tChannels;
1772
1773 // first row left border
1774
1775 for (unsigned int x = (border - 1u); x != (unsigned int)(-1); --x)
1776 {
1777 for (unsigned int n = 0u; n < tChannels; ++n)
1778 {
1779 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(sourcePtr[x * tChannels + n]));
1780 }
1781
1782 for (unsigned int n = 0u; n < tChannels; ++n)
1783 {
1784 *integral++ = previousIntegral[n];
1785 }
1786 }
1787
1788 // first row center pixels
1789
1790 const T* const sourceRowEnd0 = sourcePtr + width * tChannels;
1791 while (sourcePtr != sourceRowEnd0)
1792 {
1793 for (unsigned int n = 0u; n < tChannels; ++n)
1794 {
1795 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*sourcePtr++));
1796 }
1797
1798 for (unsigned int n = 0u; n < tChannels; ++n)
1799 {
1800 *integral++ = previousIntegral[n];
1801 }
1802 }
1803
1804 // first row right border
1805
1806 for (unsigned int x = 0u; x < border; ++x)
1807 {
1808 for (unsigned int n = 0u; n < tChannels; ++n)
1809 {
1810 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*(sourcePtr - int((x + 1u) * tChannels) + int(n))));
1811 }
1812
1813 for (unsigned int n = 0u; n < tChannels; ++n)
1814 {
1815 *integral++ = previousIntegral[n];
1816 }
1817 }
1818
1819 integral += integralPaddingElements;
1820
1821 // following rows
1822
1823 int y = -int(border) + 1;
1824
1825 while (y != int(height + border))
1826 {
1827 if (y < 0)
1828 {
1829 ocean_assert(-y - 1 >= 0 && -y - 1 < int(border));
1830 sourcePtr = source + int(sourceStrideElements) * (-y - 1);
1831 }
1832 else if (y < int(height))
1833 {
1834 sourcePtr = source + int(sourceStrideElements) * y;
1835 }
1836 else
1837 {
1838 sourcePtr = source + int(sourceStrideElements) * (2 * int(height) - y - 1);
1839 }
1840
1841 // left column
1842
1843 for (unsigned int n = 0u; n < tChannels; ++n)
1844 {
1845 previousIntegral[n] = TIntegral(0);
1846 }
1847
1848 for (unsigned int n = 0u; n < tChannels; ++n)
1849 {
1850 *integral++ = TIntegral(0);
1851 }
1852
1853 // left border
1854
1855 for (unsigned int x = border - 1u; x != (unsigned int)(-1); --x)
1856 {
1857 for (unsigned int n = 0u; n < tChannels; ++n)
1858 {
1859 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(sourcePtr[x * tChannels + n]));
1860 }
1861
1862 for (unsigned int n = 0u; n < tChannels; ++n)
1863 {
1864 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1865 }
1866 }
1867
1868 // center
1869
1870 const T* const followingSourceRowEnd0 = sourcePtr + width * tChannels;
1871 while (sourcePtr != followingSourceRowEnd0)
1872 {
1873 ocean_assert(sourcePtr < followingSourceRowEnd0);
1874
1875 for (unsigned int n = 0u; n < tChannels; ++n)
1876 {
1877 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*sourcePtr++));
1878 }
1879
1880 for (unsigned int n = 0u; n < tChannels; ++n)
1881 {
1882 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1883 }
1884 }
1885
1886 // right border
1887
1888 for (unsigned int x = 0u; x < border; ++x)
1889 {
1890 for (unsigned int n = 0u; n < tChannels; ++n)
1891 {
1892 previousIntegral[n] += TIntegral(sqr<T, TIntegral>(*(sourcePtr - int((x + 1u) * tChannels) + int(n))));
1893 }
1894
1895 for (unsigned int n = 0u; n < tChannels; ++n)
1896 {
1897 *integral++ = previousIntegral[n] + *integralPreviousRow++;
1898 }
1899 }
1900
1901 integral += integralPaddingElements;
1902 integralPreviousRow += tChannels + integralPaddingElements;
1903
1904 ++y;
1905 }
1906}
1907
1908template <typename TIntegral>
1909inline 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)
1910{
1911 ocean_assert(linedIntegral != nullptr);
1912 ocean_assert(windowLeft + windowWidth < linedIntegralStrideElements);
1913 ocean_assert(windowWidth != 0u);
1914 ocean_assert(windowHeight != 0u);
1915
1916 const unsigned int windowRight = windowLeft + windowWidth;
1917 const unsigned int windowBottom = windowTop + windowHeight;
1918
1919 return linedIntegral[windowTop * linedIntegralStrideElements + windowLeft] - linedIntegral[windowTop * linedIntegralStrideElements + windowRight]
1920 - linedIntegral[windowBottom * linedIntegralStrideElements + windowLeft] + linedIntegral[windowBottom * linedIntegralStrideElements + windowRight];
1921}
1922
1923template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
1924inline 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)
1925{
1926 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
1927
1928 ocean_assert(linedIntegral != nullptr);
1929 ocean_assert(windowLeft + windowWidth < integralStrideElements);
1930
1931 ocean_assert(linedIntegralSquared != nullptr);
1932 ocean_assert(windowLeft + windowWidth < integralStrideSquaredElements);
1933
1934 ocean_assert(windowWidth != 0u);
1935 ocean_assert(windowHeight != 0u);
1936
1937 if (windowWidth == 1u && windowHeight == 1u)
1938 {
1939 return TVariance(0);
1940 }
1941
1942 const TIntegral sum = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowLeft, windowTop, windowWidth, windowHeight);
1943 const TIntegralSquared squaredSum = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowLeft, windowTop, windowWidth, windowHeight);
1944
1945 const TVariance size = TVariance(windowWidth * windowHeight);
1946
1947 if constexpr (tReturnMean)
1948 {
1949 ocean_assert(mean != nullptr);
1950 *mean = TVariance(sum) / size;
1951 }
1952 else
1953 {
1954 ocean_assert(mean == nullptr);
1955 }
1956
1957 const TVariance variance = (TVariance(squaredSum) - TVariance(TIntegralSquared(sum) * TIntegralSquared(sum)) / size) / size;
1958
1959 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
1960}
1961
1962template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
1963inline 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)
1964{
1965 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
1966
1967 ocean_assert(linedIntegral != nullptr);
1968 ocean_assert(windowALeft + windowAWidth < integralStrideElements);
1969 ocean_assert(windowBLeft + windowBWidth < integralStrideElements);
1970
1971 ocean_assert(linedIntegralSquared != nullptr);
1972 ocean_assert(windowALeft + windowAWidth < integralStrideSquaredElements);
1973 ocean_assert(windowBLeft + windowBWidth < integralStrideSquaredElements);
1974
1975 ocean_assert(windowAWidth != 0u && windowAHeight != 0u);
1976 ocean_assert(windowBWidth != 0u && windowBHeight != 0u);
1977
1978 const TIntegral sumA = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowALeft, windowATop, windowAWidth, windowAHeight);
1979 const TIntegral sumB = linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
1980
1981 const TIntegralSquared squaredSumA = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowALeft, windowATop, windowAWidth, windowAHeight);
1982 const TIntegralSquared squaredSumB = linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
1983
1984 const unsigned int sizeA = windowAWidth * windowAHeight;
1985 const unsigned int sizeB = windowBWidth * windowBHeight;
1986 const TVariance size = TVariance(sizeA + sizeB);
1987
1988 const TVariance squaredSum = TVariance(squaredSumA + squaredSumB);
1989 const TIntegralSquared sum = TIntegralSquared(sumA + sumB);
1990
1991 if constexpr (tReturnMean)
1992 {
1993 ocean_assert(mean != nullptr);
1994 *mean = TVariance(sum) / size;
1995 }
1996 else
1997 {
1998 ocean_assert(mean == nullptr);
1999 }
2000
2001 const TVariance variance = (squaredSum - TVariance(sum * sum) / size) / size;
2002
2003 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
2004}
2005
2006template <typename TIntegral, typename TIntegralSquared, typename TVariance, bool tReturnMean>
2007inline 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)
2008{
2009 static_assert(std::is_floating_point<TVariance>::value, "Invalid TVariance must be a floating point data type!");
2010
2011 ocean_assert(linedIntegral != nullptr);
2012 ocean_assert(windowALeft + windowAWidth < integralStrideElements);
2013 ocean_assert(windowBLeft + windowBWidth < integralStrideElements);
2014 ocean_assert(windowCLeft + windowCWidth < integralStrideElements);
2015
2016 ocean_assert(linedIntegralSquared != nullptr);
2017 ocean_assert(windowALeft + windowAWidth < integralStrideSquaredElements);
2018 ocean_assert(windowBLeft + windowBWidth < integralStrideSquaredElements);
2019 ocean_assert(windowCLeft + windowCWidth < integralStrideSquaredElements);
2020
2021 ocean_assert(windowAWidth != 0u && windowAHeight != 0u);
2022 ocean_assert(windowBWidth != 0u && windowBHeight != 0u);
2023 ocean_assert(windowCWidth != 0u && windowCHeight != 0u);
2024
2025 const TIntegral sumA = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowALeft, windowATop, windowAWidth, windowAHeight);
2026 const TIntegral sumB = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
2027 const TIntegral sumC = CV::IntegralImage::linedIntegralSum<TIntegral>(linedIntegral, integralStrideElements, windowCLeft, windowCTop, windowCWidth, windowCHeight);
2028
2029 const TIntegralSquared squaredSumA = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowALeft, windowATop, windowAWidth, windowAHeight);
2030 const TIntegralSquared squaredSumB = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowBLeft, windowBTop, windowBWidth, windowBHeight);
2031 const TIntegralSquared squaredSumC = CV::IntegralImage::linedIntegralSum<TIntegralSquared>(linedIntegralSquared, integralStrideSquaredElements, windowCLeft, windowCTop, windowCWidth, windowCHeight);
2032
2033 const unsigned int sizeA = windowAWidth * windowAHeight;
2034 const unsigned int sizeB = windowBWidth * windowBHeight;
2035 const unsigned int sizeC = windowCWidth * windowCHeight;
2036 const TVariance size = TVariance(sizeA + sizeB + sizeC);
2037
2038 const TVariance squaredSum = TVariance(squaredSumA + squaredSumB + squaredSumC);
2039 const TIntegralSquared sum = TIntegralSquared(sumA + sumB + sumC);
2040
2041 if constexpr (tReturnMean)
2042 {
2043 ocean_assert(mean != nullptr);
2044 *mean = TVariance(sum) / size;
2045 }
2046 else
2047 {
2048 ocean_assert(mean == nullptr);
2049 }
2050
2051 const TVariance variance = (squaredSum - TVariance(sum * sum) / size) / size;
2052
2053 return std::max(TVariance(0), variance); // due to floating point precision, always ensure that the variance is non-negative
2054}
2055
2056template <typename T, typename TSquared>
2057inline TSquared IntegralImage::sqr(const T& value)
2058{
2059 return TSquared(value * value);
2060}
2061
2062}
2063
2064}
2065
2066#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:1531
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 createLinedImage1Channel8BitSSE(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:849
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:1924
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:652
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:1720
static TSquared sqr(const T &value)
Returns the square value of the given parameter.
Definition IntegralImage.h:2057
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:1188
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:945
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:1359
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:723
This class implements Ocean's image class.
Definition Frame.h:1879
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:1499
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition base/Utilities.h:1099
The namespace covering the entire Ocean framework.
Definition Accessor.h:15