Ocean
Loading...
Searching...
No Matches
FrameFilterMin.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_FRAME_FILTER_MIN_H
9#define META_OCEAN_CV_FRAME_FILTER_MIN_H
10
11#include "ocean/cv/CV.h"
13
14#include "ocean/base/Frame.h"
15#include "ocean/base/Worker.h"
16
17#include "ocean/math/Numeric.h"
18
19namespace Ocean
20{
21
22namespace CV
23{
24
25/**
26 * This class implements filters based on the min function.
27 * @ingroup cv
28 */
29class OCEAN_CV_EXPORT FrameFilterMin : protected FrameFilterSorted
30{
31 public:
32
33 /**
34 * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
35 * Best practice is to avoid using these functions if binary size matters,<br>
36 * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.<br>
37 */
38 class OCEAN_CV_EXPORT Comfort
39 {
40 public:
41
42 /**
43 * Filters a frame with a min filter with arbitrary size (a square patch).
44 * @param source The source image to be filtered, must be valid
45 * @param target The target frame with same size and pixel format receiving the filtered result, must be valid
46 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
47 * @param worker Optional worker object to distribute the computation
48 * @return True, if succeeded
49 */
50 static bool filter(const Frame& source, Frame& target, const unsigned int filterSize, Worker* worker);
51
52 /**
53 * Filters a frame with a min filter with arbitrary size (a square patch).
54 * @param frame The image to be filtered, must be valid
55 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
56 * @param worker Optional worker object to distribute the computation
57 * @return True, if succeeded
58 */
59 static bool filter(Frame& frame, const unsigned int filterSize, Worker* worker);
60 };
61
62 public:
63
64 /**
65 * Filters a frame with a min filter with arbitrary size (a square patch).
66 * @param source The source image to be filtered, must be valid
67 * @param target The target frame with same size and pixel format receiving the filtered result, must be valid
68 * @param width The width of the input frame in pixel, with range [filterSize / 2, infinity)
69 * @param height The height of the input frame in pixel, with range [filterSize / 2, infinity)
70 * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
71 * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
72 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
73 * @param worker Optional worker object to distribute the computation
74 * @tparam T Data type of the data elements
75 * @tparam tChannels Number of data channels, with range [1, infinity)
76 */
77 template <typename T, unsigned int tChannels>
78 static void filter(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, Worker* worker = nullptr);
79
80 /**
81 * Filters a frame with a min filter with arbitrary size (a square patch).
82 * @param frame The image to be filtered, must be valid
83 * @param width The width of the input frame in pixel, with range [filterSize / 2, infinity)
84 * @param height The height of the input frame in pixel, with range [filterSize / 2, infinity)
85 * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
86 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
87 * @param worker Optional worker object to distribute the computation
88 * @tparam T Data type of the data elements
89 * @tparam tChannels Number of data channels, with range [1, infinity)
90 */
91 template <typename T, unsigned int tChannels>
92 static void filter(T* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int filterSize, Worker* worker = nullptr);
93
94 protected:
95
96 /**
97 * Filters a subset of an integer frame with a min filter with arbitrary size.
98 * @param source The source image to be filtered, must be valid
99 * @param target The target frame with same size and pixel format receiving the filtered result, must be valid
100 * @param width The width of the input frame in pixel, with range [filterSize / 2, infinity)
101 * @param height The height of the input frame in pixel, with range [filterSize / 2, infinity)
102 * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
103 * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
104 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
105 * @param firstRow First row to be handled, with range [0, height - 1]
106 * @param numberRows Number of rows to be handled, with range [1, height - firstRow]
107 * @tparam T Data type of the data elements, must be an integer data type
108 * @tparam tChannels Number of data channels, with range [1, infinity)
109 */
110 template <typename T, unsigned int tChannels, typename THistogram>
111 static void filterHistogramSubset(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows);
112
113 /**
114 * Filters a subset of a floating point frame with a min filter with arbitrary size.
115 * @param source The source image to be filtered, must be valid
116 * @param target The target frame with same size and pixel format receiving the filtered result, must be valid
117 * @param width The width of the input frame in pixel, with range [filterSize / 2, infinity)
118 * @param height The height of the input frame in pixel, with range [filterSize / 2, infinity)
119 * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
120 * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
121 * @param filterSize Size of the filter edge in pixel, must be odd with range [1, infinity)
122 * @param firstRow First row to be handled, with range [0, height - 1]
123 * @param numberRows Number of rows to be handled, with range [1, height - firstRow]
124 * @tparam T Data type of the data elements, must be a valid data type
125 * @tparam tChannels Number of data channels, with range [1, infinity)
126 */
127 template <typename T, unsigned int tChannels>
128 static void filterSequentialSubset(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows);
129};
130
131template <typename T, unsigned int tChannels>
132void FrameFilterMin::filter(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, Worker* worker)
133{
134 static_assert(tChannels != 0u, "Invalid channel number!");
135
136 ocean_assert(source != nullptr && target != nullptr && source != target);
137 ocean_assert(filterSize / 2u <= width && filterSize / 2u <= height);
138
139 if constexpr (std::is_floating_point<T>::value || sizeof(T) > sizeof(uint16_t))
140 {
141 if (worker)
142 {
143 worker->executeFunction(Worker::Function::createStatic(&filterSequentialSubset<T, tChannels>, source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, 0u), 0u, height, 7u, 8u, 20u);
144 }
145 else
146 {
147 filterSequentialSubset<T, tChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, height);
148 }
149 }
150 else if (filterSize < 5u)
151 {
152 if (worker)
153 {
154 worker->executeFunction(Worker::Function::createStatic(&filterSequentialSubset<T, tChannels>, source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, 0u), 0u, height, 7u, 8u, 20u);
155 }
156 else
157 {
158 filterSequentialSubset<T, tChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, height);
159 }
160 }
161 else
162 {
163 ocean_assert(!std::is_floating_point<T>::value);
164
165 ocean_assert(uint64_t(filterSize * filterSize) < uint64_t(NumericT<uint16_t>::maxValue()));
166
167 constexpr size_t histogramElements = 1 << sizeof(T) * 8;
168
169 ocean_assert(sizeof(T) != sizeof(uint8_t) || histogramElements == 256);
170 ocean_assert(sizeof(T) != sizeof(uint16_t) || histogramElements == 65536);
171
173
174 if (worker)
175 {
176 worker->executeFunction(Worker::Function::createStatic(&filterHistogramSubset<T, tChannels, Histogram>, source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, 0u), 0u, height, 7u, 8u, 20u);
177 }
178 else
179 {
180 filterHistogramSubset<T, tChannels, Histogram>(source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, height);
181 }
182 }
183}
184
185template <typename T, unsigned int tChannels>
186void FrameFilterMin::filter(T* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int filterSize, Worker* worker)
187{
188 static_assert(tChannels != 0u, "Invalid channel number!");
189
190 ocean_assert(frame != nullptr);
191 ocean_assert(filterSize / 2u <= width && filterSize / 2u <= height);
192
193 Memory memory(width * height * sizeof(T) * tChannels);
194
195 constexpr unsigned int memoryPaddingElements = 0u;
196 filter<T, tChannels>(frame, memory.data<T>(), width, height, framePaddingElements, memoryPaddingElements, filterSize, worker);
197
198 if (framePaddingElements == 0u)
199 {
200 memcpy(frame, memory.data(), memory.size());
201 }
202 else
203 {
204 const T* memoryData = memory.data<T>();
205
206 for (unsigned int y = 0u; y < height; ++y)
207 {
208 memcpy(frame, memoryData, width * tChannels * sizeof(T));
209
210 frame += width * tChannels + framePaddingElements;
211 memoryData += width * tChannels + memoryPaddingElements;
212 }
213 }
214}
215
216template <typename T, unsigned int tChannels, typename THistogram>
217void FrameFilterMin::filterHistogramSubset(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows)
218{
219 static_assert(!std::is_floating_point<T>::value, "Invalid data type!");
220 static_assert(tChannels != 0u, "Invalid channel number");
221
222 ocean_assert(source != nullptr && target != nullptr);
223
224 ocean_assert(filterSize >= 3u && filterSize % 2u == 1u);
225
226 const unsigned int filterSize_2 = filterSize / 2u;
227 ocean_assert(filterSize_2 <= width && filterSize_2 <= height);
228
229 const unsigned int endRow = firstRow + numberRows;
230
231 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
232 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
233
234 THistogram histogram[tChannels];
235
236 // fill initial histogram
237
238 for (unsigned int y = clampLower(firstRow, filterSize_2); y <= clampUpper(firstRow, filterSize_2, height); ++y)
239 {
240 const T* sourceRow = source + y * sourceStrideElements;
241
242 for (unsigned int x = 0u; x <= filterSize_2; ++x)
243 {
244 for (unsigned int n = 0u; n < tChannels; ++n)
245 {
246 histogram[n].pushValue(*sourceRow++);
247 }
248 }
249 }
250
251 ocean_assert(histogram[0].values() >= (filterSize_2 + 1u) * (filterSize_2 + 1u));
252 ocean_assert(histogram[0].values() <= (filterSize_2 + 1u) * filterSize);
253
254 THistogram previousHistograms[tChannels];
255
256 for (unsigned int y = firstRow; y < endRow; ++y)
257 {
258 T* targetRow = target + y * targetStrideElements;
259
260 // making a copy which we can use when we start with the next row
261 for (unsigned int n = 0u; n < tChannels; ++n)
262 {
263 previousHistograms[n] = histogram[n];
264 }
265
266 for (unsigned int x = 0u; x < width; ++x)
267 {
268 for (unsigned int n = 0u; n < tChannels; ++n)
269 {
270 ocean_assert(histogram[n]);
271 *targetRow++ = histogram[n].minValue();
272 }
273
274 if (x != width - 1u)
275 {
276 ocean_assert(x + 1u < width);
277
278 // horizontal histogram update
279
280 for (unsigned int yy = clampLower(y, filterSize_2); yy <= clampUpper(y, filterSize_2, height); ++yy)
281 {
282 const T* sourceRow = source + yy * sourceStrideElements;
283
284 const unsigned int xxLeft = x - filterSize_2;
285 const unsigned int xxRight = x + filterSize_2 + 1u;
286
287 if (xxLeft < width) // handling negative cases: int(xxLeft) < 0
288 {
289 for (unsigned int n = 0u; n < tChannels; ++n)
290 {
291 const T popValue = sourceRow[xxLeft * tChannels + n];
292
293 ocean_assert(histogram[n].hasValue(popValue));
294 histogram[n].popValue(popValue);
295 }
296 }
297
298 if (xxRight < width)
299 {
300 for (unsigned int n = 0u; n < tChannels; ++n)
301 {
302 const T pushValue = sourceRow[xxRight * tChannels + n];
303
304 histogram[n].pushValue(pushValue);
305 }
306 }
307 }
308 }
309
310 ocean_assert(histogram[0].values() <= filterSize * filterSize);
311 }
312
313 if (y != endRow - 1u)
314 {
315 ocean_assert(y + 1u < endRow);
316
317 // vertical histogram update at the beginning of the row
318
319 for (unsigned int n = 0u; n < tChannels; ++n)
320 {
321 histogram[n] = previousHistograms[n];
322 }
323
324 const unsigned int yyTop = y - filterSize_2;
325 const unsigned int yyBottom = y + filterSize_2 + 1u;
326
327 if (yyTop < height) // handling negative cases: int(yyTop) < 0
328 {
329 const T* sourceRow = source + yyTop * sourceStrideElements;
330
331 for (unsigned int x = 0u; x <= filterSize_2; ++x)
332 {
333 for (unsigned int n = 0u; n < tChannels; ++n)
334 {
335 const T popValue = sourceRow[x * tChannels + n];
336
337 ocean_assert(histogram[n].hasValue(popValue));
338 histogram[n].popValue(popValue);
339 }
340 }
341 }
342
343 if (yyBottom < height)
344 {
345 const T* sourceRow = source + yyBottom * sourceStrideElements;
346
347 for (unsigned int x = 0u; x <= filterSize_2; ++x)
348 {
349 for (unsigned int n = 0u; n < tChannels; ++n)
350 {
351 const T pushValue = sourceRow[x * tChannels + n];
352
353 histogram[n].pushValue(pushValue);
354 }
355 }
356 }
357 }
358 }
359}
360
361template <typename T, unsigned int tChannels>
362void FrameFilterMin::filterSequentialSubset(const T* source, T* target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows)
363{
364 static_assert(tChannels != 0u, "Invalid channel number");
365
366 ocean_assert(source != nullptr && target != nullptr);
367 ocean_assert(firstRow + numberRows <= height);
368
369 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
370 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
371
372 const unsigned int filterSize_2 = filterSize / 2u;
373
374 T minValues[tChannels];
375
376 for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
377 {
378 T* targetRow = target + y * targetStrideElements;
379
380 for (unsigned int x = 0u; x < width; ++x)
381 {
382 for (unsigned int n = 0u; n < tChannels; ++n)
383 {
384 minValues[n] = NumericT<T>::maxValue();
385 }
386
387 for (unsigned int xx = max(0, int(x) - int(filterSize_2)); xx < min(x + filterSize_2 + 1u, width); ++xx)
388 {
389 for (unsigned int yy = max(0, int(y) - int(filterSize_2)); yy < min(y + filterSize_2 + 1u, height); ++yy)
390 {
391 ocean_assert(xx < width && yy < height);
392
393 const T* const sourcePixel = source + yy * sourceStrideElements + xx * tChannels;
394
395 for (unsigned int n = 0u; n < tChannels; ++n)
396 {
397 if (sourcePixel[n] < minValues[n])
398 {
399 minValues[n] = sourcePixel[n];
400 }
401 }
402 }
403 }
404
405 for (unsigned int n = 0u; n < tChannels; ++n)
406 {
407 targetRow[n] = minValues[n];
408 }
409
410 targetRow += tChannels;
411 }
412 }
413}
414
415}
416
417}
418
419#endif // META_OCEAN_CV_FRAME_FILTER_MIN_H
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition FrameFilterMin.h:39
static bool filter(Frame &frame, const unsigned int filterSize, Worker *worker)
Filters a frame with a min filter with arbitrary size (a square patch).
static bool filter(const Frame &source, Frame &target, const unsigned int filterSize, Worker *worker)
Filters a frame with a min filter with arbitrary size (a square patch).
This class implements filters based on the min function.
Definition FrameFilterMin.h:30
static void filterSequentialSubset(const T *source, T *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows)
Filters a subset of a floating point frame with a min filter with arbitrary size.
Definition FrameFilterMin.h:362
static void filterHistogramSubset(const T *source, T *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, const unsigned int firstRow, const unsigned int numberRows)
Filters a subset of an integer frame with a min filter with arbitrary size.
Definition FrameFilterMin.h:217
static void filter(const T *source, T *target, const unsigned int width, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int filterSize, Worker *worker=nullptr)
Filters a frame with a min filter with arbitrary size (a square patch).
Definition FrameFilterMin.h:132
This class implements a histogram for integer values.
Definition FrameFilterSorted.h:42
This class implements the base class for all filters relying on sorted filter values.
Definition FrameFilterSorted.h:31
static unsigned int clampLower(const unsigned int index, const unsigned int lowerOffset)
Returns the lower clamped offset to an index.
Definition FrameFilterSorted.h:428
static unsigned int clampUpper(const unsigned int index, const unsigned int upperOffset, const unsigned int size)
Returns the upper clamped offset to an index.
Definition FrameFilterSorted.h:433
This class implements an image histogram.
Definition Histogram.h:32
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition Caller.h:2876
This class implements Ocean's image class.
Definition Frame.h:1808
This class implements an object able to allocate memory.
Definition base/Memory.h:22
size_t size() const
Returns the size of the memory in bytes.
Definition base/Memory.h:386
void * data()
Returns the pointer to the writable memory which is allocated by this object.
Definition base/Memory.h:303
This class provides basic numeric functionalities.
Definition Numeric.h:57
static constexpr T maxValue()
Returns the max scalar value.
Definition Numeric.h:3244
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
The namespace covering the entire Ocean framework.
Definition Accessor.h:15