8 #ifndef META_OCEAN_CV_FRAME_FILTER_MEDIAN_H
9 #define META_OCEAN_CV_FRAME_FILTER_MEDIAN_H
79 template <
typename T,
unsigned int tChannels>
80 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);
93 template <
typename T,
unsigned int tChannels>
94 static void filter(T* frame,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int filterSize,
Worker* worker =
nullptr);
112 template <
typename T,
unsigned int tChannels,
typename THistogram>
113 static void filterIntegerSubset(
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 template <
typename T,
unsigned int tChannels>
130 static void filterFloatSubset(
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);
133 template <
typename T,
unsigned int tChannels>
134 void FrameFilterMedian::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)
136 static_assert(tChannels != 0u,
"Invalid channel number!");
138 ocean_assert(source !=
nullptr && target !=
nullptr && source != target);
139 ocean_assert(filterSize / 2u <= width && filterSize / 2u <= height);
141 if constexpr (std::is_floating_point<T>::value ||
sizeof(T) >
sizeof(uint16_t))
145 worker->
executeFunction(
Worker::Function::createStatic(&filterFloatSubset<T, tChannels>, source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, 0u), 0u, height, 7u, 8u, 20u);
149 filterFloatSubset<T, tChannels>(source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, height);
156 constexpr
size_t histogramElements = 1 <<
sizeof(T) * 8;
158 ocean_assert(
sizeof(T) !=
sizeof(uint8_t) || histogramElements == 256);
159 ocean_assert(
sizeof(T) !=
sizeof(uint16_t) || histogramElements == 65536);
165 worker->
executeFunction(
Worker::Function::createStatic(&filterIntegerSubset<T, tChannels, Histogram>, source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, 0u), 0u, height, 7u, 8u, 20u);
169 filterIntegerSubset<T, tChannels, Histogram>(source, target, width, height, sourcePaddingElements, targetPaddingElements, filterSize, 0u, height);
174 template <
typename T,
unsigned int tChannels>
175 void FrameFilterMedian::filter(T* frame,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int filterSize,
Worker* worker)
177 static_assert(tChannels != 0u,
"Invalid channel number!");
179 ocean_assert(frame !=
nullptr);
180 ocean_assert(filterSize / 2u <= width && filterSize / 2u <= height);
182 Memory memory(width * height *
sizeof(T) * tChannels);
184 constexpr
unsigned int memoryPaddingElements = 0u;
185 filter<T, tChannels>(frame, memory.
data<T>(), width, height, framePaddingElements, memoryPaddingElements, filterSize, worker);
187 if (framePaddingElements == 0u)
189 memcpy(frame, memory.
data(), memory.
size());
193 const T* memoryData = memory.
data<T>();
195 for (
unsigned int y = 0u; y < height; ++y)
197 memcpy(frame, memoryData, width * tChannels *
sizeof(T));
199 frame += width * tChannels + framePaddingElements;
200 memoryData += width * tChannels + memoryPaddingElements;
205 template <
typename T,
unsigned int tChannels,
typename THistogram>
206 void FrameFilterMedian::filterIntegerSubset(
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)
208 static_assert(!std::is_floating_point<T>::value,
"Invalid data type!");
209 static_assert(tChannels != 0u,
"Invalid channel number");
211 ocean_assert(source !=
nullptr && target !=
nullptr);
213 ocean_assert(filterSize >= 3u && filterSize % 2u == 1u);
215 const unsigned int filterSize_2 = filterSize / 2u;
216 ocean_assert(filterSize_2 <= width && filterSize_2 <= height);
218 const unsigned int endRow = firstRow + numberRows;
220 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
221 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
223 THistogram medianHistograms[tChannels];
227 for (
unsigned int y =
clampLower(firstRow, filterSize_2); y <=
clampUpper(firstRow, filterSize_2, height); ++y)
229 const T* sourceRow = source + y * sourceStrideElements;
231 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
233 for (
unsigned int n = 0u; n < tChannels; ++n)
235 medianHistograms[n].pushValue(*sourceRow++);
240 ocean_assert(medianHistograms[0].values() >= (filterSize_2 + 1u) * (filterSize_2 + 1u));
241 ocean_assert(medianHistograms[0].values() <= (filterSize_2 + 1u) * filterSize);
243 THistogram previousMedianHistograms[tChannels];
245 for (
unsigned int y = firstRow; y < endRow; ++y)
247 T* targetRow = target + y * targetStrideElements;
250 for (
unsigned int n = 0u; n < tChannels; ++n)
252 previousMedianHistograms[n] = medianHistograms[n];
255 for (
unsigned int x = 0u; x < width; ++x)
257 for (
unsigned int n = 0u; n < tChannels; ++n)
259 ocean_assert(medianHistograms[n]);
260 *targetRow++ = medianHistograms[n].medianValue();
265 ocean_assert(x + 1u < width);
269 for (
unsigned int yy =
clampLower(y, filterSize_2); yy <=
clampUpper(y, filterSize_2, height); ++yy)
271 const T* sourceRow = source + yy * sourceStrideElements;
273 const unsigned int xxLeft = x - filterSize_2;
274 const unsigned int xxRight = x + filterSize_2 + 1u;
278 for (
unsigned int n = 0u; n < tChannels; ++n)
280 const T popValue = sourceRow[xxLeft * tChannels + n];
282 ocean_assert(medianHistograms[n].hasValue(popValue));
283 medianHistograms[n].popValue(popValue);
289 for (
unsigned int n = 0u; n < tChannels; ++n)
291 const T pushValue = sourceRow[xxRight * tChannels + n];
293 medianHistograms[n].pushValue(pushValue);
299 ocean_assert(medianHistograms[0].values() <= filterSize * filterSize);
302 if (y != endRow - 1u)
304 ocean_assert(y + 1u < endRow);
308 for (
unsigned int n = 0u; n < tChannels; ++n)
310 medianHistograms[n] = previousMedianHistograms[n];
313 const unsigned int yyTop = y - filterSize_2;
314 const unsigned int yyBottom = y + filterSize_2 + 1u;
318 const T* sourceRow = source + yyTop * sourceStrideElements;
320 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
322 for (
unsigned int n = 0u; n < tChannels; ++n)
324 const T popValue = sourceRow[x * tChannels + n];
326 ocean_assert(medianHistograms[n].hasValue(popValue));
327 medianHistograms[n].popValue(popValue);
332 if (yyBottom < height)
334 const T* sourceRow = source + yyBottom * sourceStrideElements;
336 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
338 for (
unsigned int n = 0u; n < tChannels; ++n)
340 const T pushValue = sourceRow[x * tChannels + n];
342 medianHistograms[n].pushValue(pushValue);
352 template <
typename T,
unsigned int tChannels>
353 void FrameFilterMedian::filterFloatSubset(
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)
355 static_assert(tChannels != 0u,
"Invalid channel number");
357 ocean_assert(source !=
nullptr && target !=
nullptr);
359 ocean_assert(filterSize >= 3u && filterSize % 2u == 1u);
361 const unsigned int filterSize_2 = filterSize / 2u;
362 ocean_assert(filterSize_2 <= width && filterSize_2 <= height);
364 const unsigned int endRow = firstRow + numberRows;
366 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
367 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
373 for (
unsigned int y =
clampLower(firstRow, filterSize_2); y <=
clampUpper(firstRow, filterSize_2, height); ++y)
375 const T* sourceRow = source + y * sourceStrideElements;
377 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
379 for (
unsigned int n = 0u; n < tChannels; ++n)
381 sortedElements[n].
pushValue(*sourceRow++);
386 ocean_assert(sortedElements[0].size() >= (filterSize_2 + 1u) * (filterSize_2 + 1u));
387 ocean_assert(sortedElements[0].size() <= (filterSize_2 + 1u) * filterSize);
391 for (
unsigned int y = firstRow; y < endRow; ++y)
393 T* targetRow = target + y * targetStrideElements;
396 for (
unsigned int n = 0u; n < tChannels; ++n)
398 previousSortedElements[n] = sortedElements[n];
401 for (
unsigned int x = 0u; x < width; ++x)
403 for (
unsigned int n = 0u; n < tChannels; ++n)
405 ocean_assert(sortedElements[n].size() != 0);
411 ocean_assert(x + 1u < width);
415 for (
unsigned int yy =
clampLower(y, filterSize_2); yy <=
clampUpper(y, filterSize_2, height); ++yy)
417 const T* sourceRow = source + yy * sourceStrideElements;
419 const unsigned int xxLeft = x - filterSize_2;
420 const unsigned int xxRight = x + filterSize_2 + 1u;
422 if (xxLeft < width && xxRight < width)
424 for (
unsigned int n = 0u; n < tChannels; ++n)
426 const T pushValue = sourceRow[xxRight * tChannels + n];
427 const T popValue = sourceRow[xxLeft * tChannels + n];
429 sortedElements[n].
exchange(pushValue, popValue);
436 for (
unsigned int n = 0u; n < tChannels; ++n)
438 const T popValue = sourceRow[xxLeft * tChannels + n];
440 sortedElements[n].
popValue(popValue);
446 for (
unsigned int n = 0u; n < tChannels; ++n)
448 const T pushValue = sourceRow[xxRight * tChannels + n];
457 ocean_assert(sortedElements[0].size() <= filterSize * filterSize);
460 if (y != endRow - 1u)
462 ocean_assert(y + 1u < endRow);
466 for (
unsigned int n = 0u; n < tChannels; ++n)
468 sortedElements[n] = previousSortedElements[n];
471 const unsigned int yyTop = y - filterSize_2;
472 const unsigned int yyBottom = y + filterSize_2 + 1u;
474 if (yyTop < height && yyBottom < height)
476 const T* sourceRowTop = source + yyTop * sourceStrideElements;
477 const T* sourceRowBottom = source + yyBottom * sourceStrideElements;
479 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
481 for (
unsigned int n = 0u; n < tChannels; ++n)
483 const T pushValue = sourceRowBottom[x * tChannels + n];
484 const T popValue = sourceRowTop[x * tChannels + n];
486 sortedElements[n].
exchange(pushValue, popValue);
494 const T* sourceRow = source + yyTop * sourceStrideElements;
496 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
498 for (
unsigned int n = 0u; n < tChannels; ++n)
500 const T popValue = sourceRow[x * tChannels + n];
502 sortedElements[n].
popValue(popValue);
507 if (yyBottom < height)
509 const T* sourceRow = source + yyBottom * sourceStrideElements;
511 for (
unsigned int x = 0u; x <= filterSize_2; ++x)
513 for (
unsigned int n = 0u; n < tChannels; ++n)
515 const T pushValue = sourceRow[x * tChannels + n];
528 template <
typename T,
unsigned int tChannels>
529 void FrameFilterMedian::filterFloatSubset(
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)
531 static_assert(std::is_floating_point<T>::value,
"Invalid data type!");
532 static_assert(tChannels != 0u,
"Invalid channel number");
534 ocean_assert(source !=
nullptr && target !=
nullptr);
535 ocean_assert(firstRow + numberRows <= height);
537 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
538 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
540 const unsigned int filterSize_2 = filterSize / 2u;
542 std::vector<T> elements;
543 elements.reserve(filterSize * filterSize);
545 for (
unsigned int y = firstRow; y < firstRow + numberRows; ++y)
547 T* targetRow = target + y * targetStrideElements;
549 for (
unsigned int x = 0u; x < width; ++x)
551 for (
unsigned int n = 0u; n < tChannels; ++n)
555 for (
unsigned int xx = max(0,
int(x) -
int(filterSize_2)); xx < min(x + filterSize_2 + 1u, width); ++xx)
557 for (
unsigned int yy = max(0,
int(y) -
int(filterSize_2)); yy < min(y + filterSize_2 + 1u, height); ++yy)
559 ocean_assert(xx < width && yy < height);
561 elements.emplace_back(source[yy * sourceStrideElements + xx * tChannels + n]);
565 *targetRow++ = Median::median<T>(elements.data(), elements.size());
This class implements a histogram for integer values.
Definition: FrameFilterSorted.h:42
This class implements a container holding sorted elements.
Definition: FrameFilterSorted.h:115
void pushValue(const T &value)
Pushes a new value into the container.
Definition: FrameFilterSorted.h:327
void exchange(const T &pushValue, const T &popValue)
Exchanges a value with another value.
Definition: FrameFilterSorted.h:345
void popValue(const T &value)
Pops a value from the container.
Definition: FrameFilterSorted.h:336
T medianValue() const
Returns the median value of this histogram.
Definition: FrameFilterSorted.h:406
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:1792
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
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