8 #ifndef META_OCEAN_CV_FRAME_FILTER_EROSION_H
9 #define META_OCEAN_CV_FRAME_FILTER_EROSION_H
96 template <
unsigned int tChannels,
bool tUseRandomNoise>
97 static bool shrinkMask8BitPerChannel4Neighbor(uint8_t* frame, uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int maskPaddingElements,
const unsigned int randomNoise = 0u,
const unsigned int randomSeed =
RandomI::random32());
116 template <
unsigned int tChannels,
bool tUseRandomNoise>
117 static bool shrinkMask8BitPerChannel8Neighbor(uint8_t* frame, uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int maskPaddingElements,
const unsigned int randomNoise = 0u,
const unsigned int randomSeed =
RandomI::random32());
133 template <
unsigned int tChannels>
134 static void shrinkMaskRandom8BitPerChannel8Neighbor(uint8_t* frame, uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int maskPaddingElements,
const unsigned int randomNoise = 0u,
const unsigned int randomSeed =
RandomI::random32());
149 template <MorphologyFilter tErosionFilter>
150 static void filter1Channel8Bit(uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int iterations,
const uint8_t maskValue = 0x00,
const unsigned int maskPaddingElements = 0u,
Worker* worker =
nullptr);
164 static inline void filter1Channel8Bit4Neighbor(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue = 0x00,
const unsigned int maskPaddingElements = 0u,
const unsigned int targetPaddingElements = 0u,
Worker* worker =
nullptr);
178 static inline void filter1Channel8Bit8Neighbor(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue = 0x00,
const unsigned int maskPaddingElements = 0u,
const unsigned int targetPaddingElements = 0u,
Worker* worker =
nullptr);
192 static inline void filter1Channel8Bit24Neighbor(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue = 0x00,
const unsigned int maskPaddingElements = 0u,
const unsigned int targetPaddingElements = 0u,
Worker* worker =
nullptr);
208 static void filter1Channel8Bit4NeighborSubset(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue,
const unsigned int maskPaddingElements,
const unsigned int targetPaddingElements,
const unsigned int firstRow,
const unsigned int numberRows);
222 static void filter1Channel8Bit8NeighborSubset(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue,
const unsigned int maskPaddingElements,
const unsigned int targetPaddingElements,
const unsigned int firstRow,
const unsigned int numberRows);
236 static void filter1Channel8Bit24NeighborSubset(
const uint8_t* mask, uint8_t* target,
const unsigned int width,
const unsigned int height,
const uint8_t maskValue,
const unsigned int maskPaddingElements,
const unsigned int targetPaddingElements,
const unsigned int firstRow,
const unsigned int numberRows);
245 template <
unsigned int tSize>
246 static OCEAN_FORCE_INLINE
bool onePixelNotEqual(
const uint8_t*
const maskPixels,
const uint8_t maskValue);
249 template <
unsigned int tChannels,
bool tUseRandomNoise>
250 bool FrameFilterErosion::shrinkMask8BitPerChannel4Neighbor(uint8_t* frame, uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int maskPaddingElements,
const unsigned int randomNoise,
const unsigned int randomSeed)
252 static_assert(tChannels >= 1u,
"Invalid channel number!");
254 ocean_assert(frame !=
nullptr && mask !=
nullptr);
255 ocean_assert(width >= 2u && height >= 2u);
256 ocean_assert(randomNoise <= 255u);
258 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
259 const unsigned int maskStrideElements = width + maskPaddingElements;
262 for (
unsigned int y = 0u; y < height; ++y)
264 const uint8_t* maskRow = mask + y * maskStrideElements;
266 for (
unsigned int x = 0u; x < width; ++x)
268 ocean_assert(maskRow[x] == 0x00u || maskRow[x] == 0xFFu);
284 bool atLeastOnePixel =
true;
286 while (atLeastOnePixel)
288 atLeastOnePixel =
false;
290 const uint8_t* maskMiddle = mask;
291 const uint8_t* maskLower = mask + maskStrideElements;
293 uint8_t* frameMiddle = frame;
294 const uint8_t* frameLower = frame + frameStrideElements;
296 uint8_t* intermediateMaskMiddle = intermediateMask.
data<uint8_t>();
299 if (*maskMiddle == 0x00u && (*(maskMiddle + 1) != 0x00u || *maskLower != 0x00u))
301 const unsigned int weight = *(maskMiddle + 1) + *maskLower;
302 ocean_assert(weight > 0u && weight <= 0xFFu * 2u);
304 for (
unsigned int n = 0u; n < tChannels; ++n)
306 if constexpr (tUseRandomNoise)
308 ocean_assert(randomNoise != 0u);
309 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
313 *(frameMiddle + n) = uint8_t((*(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight);
317 *intermediateMaskMiddle = 0xFFu;
318 atLeastOnePixel =
true;
321 frameMiddle += tChannels;
322 frameLower += tChannels;
325 ++intermediateMaskMiddle;
329 for (
unsigned int i = 1u; i < width - 1u; ++i)
332 if (*maskMiddle == 0x00u && (*(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u || *maskLower != 0x00u))
334 const unsigned int weight = *(maskMiddle - 1) + *(maskMiddle + 1) + *maskLower;
335 ocean_assert(weight > 0u && weight <= 0xFFu * 3u);
337 for (
unsigned int n = 0u; n < tChannels; ++n)
339 if constexpr (tUseRandomNoise)
341 ocean_assert(randomNoise != 0u);
342 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
346 *(frameMiddle + n) = uint8_t((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight);
350 *intermediateMaskMiddle = 0xFFu;
351 atLeastOnePixel =
true;
354 frameMiddle += tChannels;
355 frameLower += tChannels;
358 ++intermediateMaskMiddle;
363 if (*maskMiddle == 0 && (*(maskMiddle - 1) != 0u || *maskLower != 0u))
365 const unsigned int weight = *(maskMiddle - 1) + *maskLower;
366 ocean_assert(weight > 0u && weight <= 0xFFu * 2u);
368 for (
unsigned int n = 0u; n < tChannels; ++n)
370 if constexpr (tUseRandomNoise)
372 ocean_assert(randomNoise != 0u);
373 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
377 *(frameMiddle + n) = uint8_t((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *maskLower * *(frameLower + n)) / weight);
381 *intermediateMaskMiddle = 0xFFu;
382 atLeastOnePixel =
true;
385 frameMiddle += tChannels + framePaddingElements;
386 frameLower += tChannels + framePaddingElements;
387 maskMiddle += 1u + maskPaddingElements;
388 maskLower += 1u + maskPaddingElements;
389 ++intermediateMaskMiddle;
391 ocean_assert(frameMiddle == frame + frameStrideElements);
392 ocean_assert(frameLower == frame + frameStrideElements * 2u);
393 ocean_assert(maskMiddle == mask + maskStrideElements);
394 ocean_assert(maskLower == mask + maskStrideElements * 2u);
395 ocean_assert(intermediateMaskMiddle == intermediateMask.
data<uint8_t>() + width);
400 const uint8_t* maskUpper = maskMiddle - maskStrideElements;
401 const uint8_t* frameUpper = frameMiddle - frameStrideElements;
403 const uint8_t*
const maskUpperEnd = mask + maskStrideElements * (height - 2u);
405 while (maskUpper != maskUpperEnd)
408 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle + 1) != 0x00u || *maskLower != 0x00u))
410 const unsigned int weight = *maskUpper + *(maskMiddle + 1) + *maskLower;
411 ocean_assert(weight > 0u && weight <= 0xFFu * 3u);
413 for (
unsigned int n = 0u; n < tChannels; ++n)
415 if constexpr (tUseRandomNoise)
417 ocean_assert(randomNoise != 0u);
418 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
422 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight);
426 *intermediateMaskMiddle = 0xFFu;
427 atLeastOnePixel =
true;
430 frameUpper += tChannels;
431 frameMiddle += tChannels;
432 frameLower += tChannels;
436 ++intermediateMaskMiddle;
440 for (
unsigned int i = 1u; i < width - 1u; ++i)
442 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u || *maskLower != 0x00u))
444 const unsigned int weight = *maskUpper + *(maskMiddle - 1) + *(maskMiddle + 1) + *maskLower;
445 ocean_assert(weight > 0u && weight <= 0xFFu * 4u);
447 for (
unsigned int n = 0u; n < tChannels; ++n)
449 if constexpr (tUseRandomNoise)
451 ocean_assert(randomNoise != 0u);
452 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
456 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) + *maskLower * *(frameLower + n)) / weight);
460 *intermediateMaskMiddle = 0xFFu;
461 atLeastOnePixel =
true;
464 frameUpper += tChannels;
465 frameMiddle += tChannels;
466 frameLower += tChannels;
470 ++intermediateMaskMiddle;
475 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle - 1) != 0x00u || *maskLower != 0x00u))
477 const unsigned int weight = *maskUpper + *(maskMiddle - 1) + *maskLower;
478 ocean_assert(weight > 0u && weight <= 0xFFu * 3u);
480 for (
unsigned int n = 0u; n < tChannels; ++n)
482 if constexpr (tUseRandomNoise)
484 ocean_assert(randomNoise != 0u);
485 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *maskLower * *(frameLower + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
489 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *maskLower * *(frameLower + n)) / weight);
493 *intermediateMaskMiddle = 0xFFu;
494 atLeastOnePixel =
true;
497 frameUpper += tChannels + framePaddingElements;
498 frameMiddle += tChannels + framePaddingElements;
499 frameLower += tChannels + framePaddingElements;
500 maskUpper += 1u + maskPaddingElements;
501 maskMiddle += 1u + maskPaddingElements;
502 maskLower += 1u + maskPaddingElements;
503 ++intermediateMaskMiddle;
506 ocean_assert(frameUpper == frame + frameStrideElements * (height - 2u));
507 ocean_assert(frameMiddle == frame + frameStrideElements * (height - 1u));
508 ocean_assert(maskUpper == mask + maskStrideElements * (height - 2u));
509 ocean_assert(maskMiddle == mask + maskStrideElements * (height - 1u));
510 ocean_assert(intermediateMaskMiddle == intermediateMask.
data<uint8_t>() + width * (height - 1u));
513 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle + 1) != 0x00u))
515 const unsigned int weight = *maskUpper + *(maskMiddle + 1);
516 ocean_assert(weight > 0u && weight <= 0xFFu * 2u);
518 for (
unsigned int n = 0u; n < tChannels; ++n)
520 if constexpr (tUseRandomNoise)
522 ocean_assert(randomNoise != 0u);
523 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
527 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n)) / weight);
531 *intermediateMaskMiddle = 0xFFu;
532 atLeastOnePixel =
true;
535 frameUpper += tChannels;
536 frameMiddle += tChannels;
539 ++intermediateMaskMiddle;
543 for (
unsigned int i = 1u; i < width - 1u; ++i)
545 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u))
547 const unsigned int weight = *maskUpper + *(maskMiddle - 1) + *(maskMiddle + 1);
548 ocean_assert(weight > 0u && weight <= 0xFFu * 4u);
550 for (
unsigned int n = 0u; n < tChannels; ++n)
552 if constexpr (tUseRandomNoise)
554 ocean_assert(randomNoise != 0u);
555 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
559 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) + *(maskMiddle + 1) * *(frameMiddle + tChannels + n)) / weight);
563 *intermediateMaskMiddle = 0xFFu;
564 atLeastOnePixel =
true;
567 frameUpper += tChannels;
568 frameMiddle += tChannels;
571 ++intermediateMaskMiddle;
576 if (*maskMiddle == 0x00u && (*maskUpper != 0x00u || *(maskMiddle - 1) != 0x00u))
578 const unsigned int weight = *maskUpper + *(maskMiddle - 1);
579 ocean_assert(weight > 0u && weight <= 0xFFu * 3u);
581 for (
unsigned int n = 0u; n < tChannels; ++n)
583 if constexpr (tUseRandomNoise)
585 ocean_assert(randomNoise != 0u);
586 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
590 *(frameMiddle + n) = uint8_t((*maskUpper * *(frameUpper + n) + *(maskMiddle - 1) * *(frameMiddle - tChannels + n)) / weight);
594 *intermediateMaskMiddle = 0xFFu;
595 atLeastOnePixel =
true;
600 if (maskPaddingElements == 0u)
602 memcpy(mask, intermediateMask.
constdata<uint8_t>(),
sizeof(uint8_t) * width * height);
606 for (
unsigned int y = 0u; y < height; ++y)
608 memcpy(mask + y * maskStrideElements, intermediateMask.
constrow<uint8_t>(y),
sizeof(uint8_t) * width);
617 template <
unsigned int tChannels,
bool tUseRandomNoise>
618 bool FrameFilterErosion::shrinkMask8BitPerChannel8Neighbor(uint8_t* frame, uint8_t* mask,
const unsigned int width,
const unsigned int height,
const unsigned int framePaddingElements,
const unsigned int maskPaddingElements,
const unsigned int randomNoise,
const unsigned int randomSeed)
620 static_assert(tChannels >= 1u,
"Invalid channel number!");
622 ocean_assert(frame !=
nullptr && mask !=
nullptr);
623 ocean_assert(width >= 2 && height >= 2u);
624 ocean_assert(randomNoise <= 255u);
626 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
627 const unsigned int maskStrideElements = width + maskPaddingElements;
630 for (
unsigned int y = 0u; y < height; ++y)
632 const uint8_t* maskRow = mask + y * maskStrideElements;
634 for (
unsigned int x = 0u; x < width; ++x)
636 ocean_assert(maskRow[x] == 0x00u || maskRow[x] == 0xFFu);
652 bool atLeastOnePixel =
true;
654 while (atLeastOnePixel)
656 atLeastOnePixel =
false;
658 const uint8_t* maskMiddle = mask;
659 const uint8_t* maskLower = mask + maskStrideElements;
661 uint8_t* frameMiddle = frame;
662 const uint8_t* frameLower = frame + frameStrideElements;
664 uint8_t* intermediateMaskMiddle = intermediateMask.
data<uint8_t>();
667 if (*maskMiddle == 0x00u && (*(maskMiddle + 1) != 0x00u || *(maskLower + 0) != 0x00u || *(maskLower + 1) != 0x00u))
669 const unsigned int weight = *(maskMiddle + 1) * 2u + *(maskLower + 0) * 2u + *(maskLower + 1);
670 ocean_assert(weight > 0u && weight <= 0xFF * 12u);
672 for (
unsigned int n = 0u; n < tChannels; ++n)
674 if constexpr (tUseRandomNoise)
676 ocean_assert(randomNoise != 0u);
678 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
679 + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
683 *(frameMiddle + n) = uint8_t((*(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
684 + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight);
688 *intermediateMaskMiddle = 0xFFu;
689 atLeastOnePixel =
true;
692 frameMiddle += tChannels;
693 frameLower += tChannels;
696 ++intermediateMaskMiddle;
700 for (
unsigned int i = 1u; i < width - 1u; ++i)
703 if (*maskMiddle == 0x00u && (*(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u || *(maskLower - 1) != 0x00u || *(maskLower + 0) != 0x00u || *(maskLower + 1) != 0x00u))
705 const unsigned int weight = *(maskMiddle - 1) * 2u + *(maskMiddle + 1) * 2u + *(maskLower - 1) + *(maskLower + 0) * 2u + *(maskLower + 1);
706 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
708 for (
unsigned int n = 0u; n < tChannels; ++n)
710 if constexpr (tUseRandomNoise)
712 ocean_assert(randomNoise != 0u);
714 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
715 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
719 *(frameMiddle + n) = uint8_t((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
720 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight);
724 *intermediateMaskMiddle = 0xFFu;
725 atLeastOnePixel =
true;
728 frameMiddle += tChannels;
729 frameLower += tChannels;
732 ++intermediateMaskMiddle;
737 if (*maskMiddle == 0x00u && (*(maskMiddle - 1) != 0x00u || *(maskLower - 1) != 0x00u || *(maskLower + 0) != 0x00u))
739 const unsigned int weight = *(maskMiddle - 1) * 2u + *(maskLower - 1) + *(maskLower + 0) * 2u;
740 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
742 for (
unsigned int n = 0u; n < tChannels; ++n)
744 if constexpr (tUseRandomNoise)
746 ocean_assert(randomNoise != 0u);
748 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u
749 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
753 *(frameMiddle + n) = uint8_t((*(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u
754 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u) / weight);
758 *intermediateMaskMiddle = 0xFF;
759 atLeastOnePixel =
true;
762 frameMiddle += tChannels + framePaddingElements;
763 frameLower += tChannels + framePaddingElements;
764 maskMiddle += 1u + maskPaddingElements;
765 maskLower += 1u + maskPaddingElements;
766 ++intermediateMaskMiddle;
768 ocean_assert(frameMiddle == frame + frameStrideElements);
769 ocean_assert(frameLower == frame + frameStrideElements * 2u);
770 ocean_assert(maskMiddle == mask + maskStrideElements);
771 ocean_assert(maskLower == mask + maskStrideElements * 2u);
772 ocean_assert(intermediateMaskMiddle == intermediateMask.
data<uint8_t>() + width);
777 const uint8_t* maskUpper = maskMiddle - maskStrideElements;
778 const uint8_t* frameUpper = frameMiddle - frameStrideElements;
780 const uint8_t*
const maskUpperEnd = mask + maskStrideElements * (height - 2u);
782 while (maskUpper != maskUpperEnd)
785 if (*maskMiddle == 0x00u && (*(maskUpper + 0) != 0x00u || *(maskUpper + 1) != 0x00u || *(maskMiddle + 1) != 0x00u || *(maskLower + 0) != 0x00u || *(maskLower + 1) != 0x00u))
787 const unsigned int weight = *(maskUpper + 0) * 2u + *(maskUpper + 1) + *(maskMiddle + 1) * 2u + *(maskLower + 0) * 2u + *(maskLower + 1);
788 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
790 for (
unsigned int n = 0u; n < tChannels; ++n)
792 if constexpr (tUseRandomNoise)
794 ocean_assert(randomNoise != 0u);
796 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
797 + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
798 + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
802 *(frameMiddle + n) = uint8_t((*(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
803 + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
804 + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight);
808 *intermediateMaskMiddle = 0xFFu;
809 atLeastOnePixel =
true;
812 frameUpper += tChannels;
813 frameMiddle += tChannels;
814 frameLower += tChannels;
818 ++intermediateMaskMiddle;
822 for (
unsigned int i = 1u; i < width - 1u; ++i)
824 if (*maskMiddle == 0x00u && (*(maskUpper - 1) != 0x00u || *(maskUpper + 0) != 0x00u || *(maskUpper + 1) != 0x00u || *(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u || *(maskLower - 1) != 0x00u || *(maskLower + 0) != 0x00u || *(maskLower + 1) != 0x00u))
826 const unsigned int weight = *(maskUpper - 1) + *(maskUpper + 0) * 2u + *(maskUpper + 1) + *(maskMiddle - 1) * 2u + *(maskMiddle + 1) * 2u + *(maskLower - 1) + *(maskLower + 0) * 2u + *(maskLower + 1);
827 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
829 for (
unsigned int n = 0u; n < tChannels; ++n)
831 if constexpr (tUseRandomNoise)
833 ocean_assert(randomNoise != 0u);
835 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
836 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
837 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
841 *(frameMiddle + n) = uint8_t((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
842 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u
843 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u + *(maskLower + 1) * *(frameLower + tChannels + n)) / weight);
847 *intermediateMaskMiddle = 0xFFu;
848 atLeastOnePixel =
true;
851 frameUpper += tChannels;
852 frameMiddle += tChannels;
853 frameLower += tChannels;
857 ++intermediateMaskMiddle;
862 if (*maskMiddle == 0x00u && (*(maskUpper - 1) != 0x00u || *(maskUpper + 0) != 0x00u || *(maskMiddle - 1) != 0x00u || *(maskLower - 1) != 0x00u || *(maskLower + 0) != 0x00u))
864 const unsigned int weight = *(maskUpper - 1) + *(maskUpper + 0) * 2u + *(maskMiddle - 1) * 2u + *(maskLower - 1) + *(maskLower + 0) * 2u;
865 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
867 for (
unsigned int n = 0u; n < tChannels; ++n)
869 if constexpr (tUseRandomNoise)
871 ocean_assert(randomNoise != 0u);
873 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u
874 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u
875 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
879 *(frameMiddle + n) = uint8_t((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u
880 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u
881 + *(maskLower - 1) * *(frameLower - tChannels + n) + *(maskLower + 0) * *(frameLower + n) * 2u) / weight);
885 *intermediateMaskMiddle = 0xFFu;
886 atLeastOnePixel =
true;
889 frameUpper += tChannels + framePaddingElements;
890 frameMiddle += tChannels + framePaddingElements;
891 frameLower += tChannels + framePaddingElements;
892 maskUpper += 1u + maskPaddingElements;
893 maskMiddle += 1u + maskPaddingElements;
894 maskLower += 1u + maskPaddingElements;
895 ++intermediateMaskMiddle;
898 ocean_assert(frameUpper == frame + frameStrideElements * (height - 2u));
899 ocean_assert(frameMiddle == frame + frameStrideElements * (height - 1u));
900 ocean_assert(maskUpper == mask + maskStrideElements * (height - 2u));
901 ocean_assert(maskMiddle == mask + maskStrideElements * (height - 1u));
902 ocean_assert(intermediateMaskMiddle == intermediateMask.
data<uint8_t>() + width * (height - 1u));
906 if (*maskMiddle == 0x00u && (*(maskUpper + 0) != 0x00u || *(maskUpper + 1) != 0x00u || *(maskMiddle + 1) != 0x00u))
908 const unsigned int weight = *(maskUpper + 0) * 2u + *(maskUpper + 1) + *(maskMiddle + 1) * 2u;
909 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
911 for (
unsigned int n = 0u; n < tChannels; ++n)
913 if constexpr (tUseRandomNoise)
915 ocean_assert(randomNoise != 0u);
917 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
918 + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
922 *(frameMiddle + n) = uint8_t((*(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
923 + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u) / weight);
927 *intermediateMaskMiddle = 0xFFu;
928 atLeastOnePixel =
true;
931 frameUpper += tChannels;
932 frameMiddle += tChannels;
935 ++intermediateMaskMiddle;
939 for (
unsigned int i = 1u; i < width - 1u; ++i)
941 if (*maskMiddle == 0x00u && (*(maskUpper - 1) != 0x00u || *(maskUpper + 0) != 0x00u || *(maskUpper + 1) != 0x00u || *(maskMiddle - 1) != 0x00u || *(maskMiddle + 1) != 0x00u))
943 const unsigned int weight = *(maskUpper - 1) + *(maskUpper + 0) * 2u + *(maskUpper + 1) + *(maskMiddle - 1) * 2u + *(maskMiddle + 1) * 2u;
944 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
946 for (
unsigned int n = 0u; n < tChannels; ++n)
948 if constexpr (tUseRandomNoise)
950 ocean_assert(randomNoise != 0u);
952 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
953 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
957 *(frameMiddle + n) = uint8_t((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u + *(maskUpper + 1) * *(frameUpper + tChannels + n)
958 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u + *(maskMiddle + 1) * *(frameMiddle + tChannels + n) * 2u) / weight);
962 *intermediateMaskMiddle = 0xFFu;
963 atLeastOnePixel =
true;
966 frameUpper += tChannels;
967 frameMiddle += tChannels;
970 ++intermediateMaskMiddle;
975 if (*maskMiddle == 0x00u && (*(maskUpper - 1) != 0x00u || *(maskUpper + 0) != 0x00u || *(maskMiddle - 1) != 0x00u))
977 const unsigned int weight = *(maskUpper - 1) + *(maskUpper + 0) * 2u + *(maskMiddle - 1) * 2u;
978 ocean_assert(weight > 0u && weight <= 0xFFu * 12u);
980 for (
unsigned int n = 0u; n < tChannels; ++n)
982 if constexpr (tUseRandomNoise)
984 ocean_assert(randomNoise != 0u);
986 *(frameMiddle + n) = uint8_t(minmax<int>(0,
int((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u
987 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u) / weight) +
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise)), 255));
991 *(frameMiddle + n) = uint8_t((*(maskUpper - 1) * *(frameUpper - tChannels + n) + *(maskUpper + 0) * *(frameUpper + n) * 2u
992 + *(maskMiddle - 1) * *(frameMiddle - tChannels + n) * 2u) / weight);
996 *intermediateMaskMiddle = 0xFFu;
997 atLeastOnePixel =
true;
1000 if (atLeastOnePixel)
1002 if (maskPaddingElements == 0u)
1004 memcpy(mask, intermediateMask.
constdata<uint8_t>(),
sizeof(uint8_t) * width * height);
1008 for (
unsigned int y = 0u; y < height; ++y)
1010 memcpy(mask + y * maskStrideElements, intermediateMask.
constrow<uint8_t>(y),
sizeof(uint8_t) * width);
1019 template <
unsigned int tChannels>
1022 static_assert(tChannels >= 1u,
"Invalid channel number!");
1024 ocean_assert(frame !=
nullptr && mask !=
nullptr);
1025 ocean_assert(width >= 2u && height >= 2u);
1027 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1028 const unsigned int maskStrideElements = width + maskPaddingElements;
1030 const unsigned int width_1 = width - 1u;
1031 const unsigned int height_1 = height - 1u;
1044 borderPixelSet.reserve(1024);
1045 borderPixels.reserve(1024);
1047 constexpr uint8_t nonMaskValue = 0xFFu;
1052 const uint8_t* maskUpper = mask - maskStrideElements;
1053 const uint8_t* maskMiddle = mask;
1054 const uint8_t* maskLower = mask + maskStrideElements;
1056 for (
unsigned int y = 0u; y < height; ++y)
1058 unsigned int x = 0u;
1063 if (maskMiddle[x] != nonMaskValue && (maskMiddle[x + 1u] == nonMaskValue || maskLower[x] == nonMaskValue || maskLower[x + 1u] == nonMaskValue))
1065 borderPixelSet.emplace(x, 0u);
1066 borderPixels.emplace_back(x, 0u);
1069 while (++x < width_1)
1071 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskMiddle + x + 1u) == nonMaskValue || *(maskLower + x - 1u) == nonMaskValue || *(maskLower + x) == nonMaskValue || *(maskLower + x + 1u) == nonMaskValue))
1073 borderPixelSet.emplace(x, 0u);
1074 borderPixels.emplace_back(x, 0u);
1078 ocean_assert(x == width_1);
1081 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskLower + x - 1u) == nonMaskValue || *(maskLower + x) == nonMaskValue))
1083 borderPixelSet.emplace(x, 0u);
1084 borderPixels.emplace_back(x, 0u);
1087 else if (y == height_1)
1090 if (maskMiddle[x] != nonMaskValue && (maskMiddle[x + 1u] == nonMaskValue || maskUpper[x] == nonMaskValue || maskUpper[x + 1u] == nonMaskValue))
1092 borderPixelSet.emplace(x, height_1);
1093 borderPixels.emplace_back(x, height_1);
1096 while (++x < width_1)
1098 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskMiddle + x + 1u) == nonMaskValue || *(maskUpper + x - 1u) == nonMaskValue || *(maskUpper + x) == nonMaskValue || *(maskUpper + x + 1u) == nonMaskValue))
1100 borderPixelSet.emplace(x, height_1);
1101 borderPixels.emplace_back(x, height_1);
1105 ocean_assert(x == width_1);
1108 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskUpper + x - 1u) == nonMaskValue || *(maskUpper + x) == nonMaskValue))
1110 borderPixelSet.emplace(x, height_1);
1111 borderPixels.emplace_back(x, height_1);
1116 ocean_assert(y >= 1u && y < height_1);
1119 if (maskMiddle[x] != nonMaskValue && (maskMiddle[x + 1u] == nonMaskValue || maskUpper[x] == nonMaskValue || maskUpper[x + 1u] == nonMaskValue || maskLower[x] == nonMaskValue || maskLower[x + 1u] == nonMaskValue))
1121 borderPixelSet.emplace(x, y);
1122 borderPixels.emplace_back(x, y);
1125 while (++x < width_1)
1127 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskMiddle + x + 1u) == nonMaskValue || *(maskUpper + x - 1u) == nonMaskValue || *(maskUpper + x) == nonMaskValue || *(maskUpper + x + 1u) == nonMaskValue || *(maskLower + x - 1u) == nonMaskValue || *(maskLower + x) == nonMaskValue || *(maskLower + x + 1u) == nonMaskValue))
1129 borderPixelSet.emplace(x, y);
1130 borderPixels.emplace_back(x, y);
1134 ocean_assert(x == width_1);
1137 if (*(maskMiddle + x) != nonMaskValue && (*(maskMiddle + x - 1u) == nonMaskValue || *(maskUpper + x - 1u) == nonMaskValue || *(maskUpper + x) == nonMaskValue || *(maskLower + x - 1u) == nonMaskValue || *(maskLower + x) == nonMaskValue))
1139 borderPixelSet.emplace(x, y);
1140 borderPixels.emplace_back(x, y);
1144 maskUpper += maskStrideElements;
1145 maskMiddle += maskStrideElements;
1146 maskLower += maskStrideElements;
1150 while (!borderPixels.empty())
1152 const unsigned int index =
Random::random(randomGenerator, (
unsigned int)(borderPixels.size()) - 1u);
1156 borderPixels[index] = borderPixels.back();
1157 borderPixels.pop_back();
1159 borderPixelSet.erase(pixelPosition);
1161 ocean_assert(pixelPosition.
x() < width && pixelPosition.
y() < height);
1163 uint8_t* maskMiddle = mask + pixelPosition.
y() * maskStrideElements + pixelPosition.
x();
1165 const uint8_t* maskUpper = maskMiddle - maskStrideElements;
1166 const uint8_t* maskLower = maskMiddle + maskStrideElements;
1168 uint8_t* frameMiddle = frame + pixelPosition.
y() * frameStrideElements + pixelPosition.
x() * tChannels;
1169 frameMiddle -= tChannels;
1170 const uint8_t*
const frameUpper = frameMiddle - frameStrideElements;
1171 const uint8_t*
const frameLower = frameMiddle + frameStrideElements;
1173 if (pixelPosition.
x() >= 1u && pixelPosition.
y() >= 1u && pixelPosition.
x() < width_1 && pixelPosition.
y() < height_1)
1177 const unsigned int weight = maskUpper[0] + maskUpper[1] * 2u + maskUpper[2] + maskMiddle[0] * 2u + maskMiddle[2] * 2u + maskLower[0] + maskLower[1] * 2u + maskLower[2];
1179 ocean_assert(weight > 0u && weight <= 0xFF * 12u);
1180 const unsigned int weight_2 = weight / 2u;
1182 for (
unsigned int n = 0u; n < tChannels; ++n)
1184 const unsigned int value = frameUpper[n] * maskUpper[0] + frameUpper[tChannels + n] * maskUpper[1] * 2u + frameUpper[tChannels * 2u + n] * maskUpper[2]
1185 + frameMiddle[n] * maskMiddle[0] * 2u + frameMiddle[tChannels * 2u + n] * maskMiddle[2] * 2u
1186 + frameLower[n] * maskLower[0] + frameLower[tChannels + n] * maskLower[1] * 2u + frameLower[tChannels * 2u + n] * maskLower[2];
1188 const int noise = randomNoise == 0u ? 0 :
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise));
1190 frameMiddle[tChannels + n] = uint8_t(minmax<int>(0,
int((value + weight_2) / weight) + noise, 255));
1193 maskMiddle[1] = nonMaskValue;
1199 unsigned int weight = 0u;
1200 unsigned int values[tChannels] = {0u};
1202 if (pixelPosition.
y() > 0u)
1204 if (pixelPosition.
x() > 0u)
1206 weight += maskUpper[0];
1208 for (
unsigned int n = 0u; n < tChannels; ++n)
1210 values[n] += frameUpper[n] * maskUpper[0];
1214 weight += maskUpper[1] * 2u;
1216 for (
unsigned int n = 0u; n < tChannels; ++n)
1218 values[n] += frameUpper[tChannels + n] * maskUpper[1] * 2u;
1221 if (pixelPosition.
x() < width_1)
1223 weight += maskUpper[2];
1225 for (
unsigned int n = 0u; n < tChannels; ++n)
1227 values[n] += frameUpper[tChannels * 2u + n] * maskUpper[2];
1232 if (pixelPosition.
x() > 0u)
1234 weight += maskMiddle[0] * 2u;
1236 for (
unsigned int n = 0u; n < tChannels; ++n)
1238 values[n] += frameMiddle[n] * maskMiddle[0] * 2u;
1242 if (pixelPosition.
x() < width_1)
1244 weight += maskMiddle[2] * 2u;
1246 for (
unsigned int n = 0u; n < tChannels; ++n)
1248 values[n] += frameMiddle[tChannels * 2u + n] * maskMiddle[2] * 2u;
1252 if (pixelPosition.
y() < height_1)
1254 if (pixelPosition.
x() > 0u)
1256 weight += maskLower[0];
1258 for (
unsigned int n = 0u; n < tChannels; ++n)
1260 values[n] += frameLower[n] * maskLower[0];
1264 weight += maskLower[1] * 2u;
1266 for (
unsigned int n = 0u; n < tChannels; ++n)
1268 values[n] += frameLower[tChannels + n] * maskLower[1] * 2u;
1271 if (pixelPosition.
x() < width_1)
1273 weight += maskLower[2];
1275 for (
unsigned int n = 0u; n < tChannels; ++n)
1277 values[n] += frameLower[tChannels * 2u + n] * maskLower[2];
1282 ocean_assert(weight > 0u && weight <= 0xFF * 12u);
1283 const unsigned int weight_2 = weight / 2u;
1285 for (
unsigned int n = 0u; n < tChannels; ++n)
1287 const int noise = randomNoise == 0u ? 0 :
RandomI::random(randomGenerator, -
int(randomNoise),
int(randomNoise));
1289 frameMiddle[tChannels + n] = uint8_t(minmax<int>(0,
int((values[n] + weight_2) / weight) + noise, 255));
1292 maskMiddle[1] = nonMaskValue;
1295 for (
int yy = -1; yy <= 1; ++yy)
1297 const unsigned int yCenter = (
unsigned int)(
int(pixelPosition.
y()) + yy);
1299 if (yCenter < height)
1301 for (
int xx = -1; xx <= 1; ++xx)
1303 if (yy != 0 || xx != 0)
1305 const unsigned int xCenter = (
unsigned int)(
int(pixelPosition.
x()) + xx);
1307 if (xCenter < width)
1309 maskMiddle = mask + yCenter * maskStrideElements + xCenter;
1312 if (maskMiddle[1] != nonMaskValue)
1314 if (borderPixelSet.find(
CV::PixelPosition(xCenter, yCenter)) == borderPixelSet.cend())
1316 maskUpper = maskMiddle - maskStrideElements;
1317 maskLower = maskMiddle + maskStrideElements;
1319 const bool newBorderPixel = (xCenter > 0u && yCenter > 0u && maskUpper[0] == nonMaskValue)
1320 || (yCenter > 0u && maskUpper[1] == nonMaskValue)
1321 || (xCenter < width_1 && yCenter > 0u && maskUpper[2] == nonMaskValue)
1322 || (xCenter > 0u && maskMiddle[0] == nonMaskValue)
1323 || (xCenter < width_1 && maskMiddle[2] == nonMaskValue)
1324 || (xCenter > 0u && yCenter < height_1 && maskLower[0] == nonMaskValue)
1325 || (yCenter < height_1 && maskLower[1] == nonMaskValue)
1326 || (xCenter < width_1 && yCenter < height_1 && maskLower[2] == nonMaskValue);
1330 borderPixelSet.emplace(xCenter, yCenter);
1331 borderPixels.emplace_back(xCenter, yCenter);
1343 template <FrameFilterErosion::MorphologyFilter tErosionFilter>
1346 ocean_assert(mask !=
nullptr);
1347 ocean_assert(width >= 4u && height >= 4u);
1348 ocean_assert(iterations >= 1u);
1352 switch (tErosionFilter)
1356 for (
unsigned int n = 0u; n < iterations / 2u; ++n)
1362 if (iterations % 2u == 1u)
1372 for (
unsigned int n = 0u; n < iterations / 2u; ++n)
1378 if (iterations % 2u == 1u)
1388 for (
unsigned int n = 0u; n < iterations / 2u; ++n)
1394 if (iterations % 2u == 1u)
1403 ocean_assert(
false &&
"Invalid erosion filter!");
1406 if (iterations % 2u == 1u)
1408 CV::FrameConverter::subFrame<uint8_t>(intermediateTarget.
constdata<uint8_t>(), mask, width, height, width, height, 1u, 0u, 0u, 0u, 0u, width, height, intermediateTarget.
paddingElements(), maskPaddingElements);
1414 ocean_assert(mask && target);
1415 ocean_assert(width >= 2u && height >= 2u);
1419 worker->
executeFunction(
Worker::Function::createStatic(&
FrameFilterErosion::filter1Channel8Bit4NeighborSubset, mask, target, width, height, maskValue, maskPaddingElements, targetPaddingElements, 0u, 0u), 0u, height, 7u, 8u, 20u);
1429 ocean_assert(mask && target);
1430 ocean_assert(width >= 2u && height >= 2u);
1434 worker->
executeFunction(
Worker::Function::createStatic(&
FrameFilterErosion::filter1Channel8Bit8NeighborSubset, mask, target, width, height, maskValue, maskPaddingElements, targetPaddingElements, 0u, 0u), 0u, height, 7u, 8u, 20u);
1444 ocean_assert(mask && target);
1445 ocean_assert(width >= 2u && height >= 2u);
1449 worker->
executeFunction(
Worker::Function::createStatic(&
FrameFilterErosion::filter1Channel8Bit24NeighborSubset, mask, target, width, height, maskValue, maskPaddingElements, targetPaddingElements, 0u, 0u), 0u, height, 7u, 8u, 20u);
1458 OCEAN_FORCE_INLINE
bool FrameFilterErosion::onePixelNotEqual<3u>(
const uint8_t*
const maskPixels,
const uint8_t maskValue)
1460 ocean_assert(maskPixels !=
nullptr);
1462 return maskPixels[0] != maskValue || maskPixels[1] != maskValue || maskPixels[2] != maskValue;
1466 OCEAN_FORCE_INLINE
bool FrameFilterErosion::onePixelNotEqual<4u>(
const uint8_t*
const maskPixels,
const uint8_t maskValue)
1468 ocean_assert(maskPixels !=
nullptr);
1470 return maskPixels[0] != maskValue || maskPixels[1] != maskValue || maskPixels[2] != maskValue || maskPixels[3] != maskValue;
1474 OCEAN_FORCE_INLINE
bool FrameFilterErosion::onePixelNotEqual<5u>(
const uint8_t*
const maskPixels,
const uint8_t maskValue)
1476 ocean_assert(maskPixels !=
nullptr);
1478 return maskPixels[0] != maskValue || maskPixels[1] != maskValue || maskPixels[2] != maskValue || maskPixels[3] != maskValue || maskPixels[4] != maskValue;
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition: FrameFilterErosion.h:48
static bool shrinkMaskRandom(Frame &frame, Frame &mask, const MorphologyFilter erosionFilter, const unsigned int randomNoise=3u, const unsigned int randomSeed=RandomI::random32())
Closes a hole inside an 8 bit grayscale frame using a randomized erosion filter.
static bool shrinkMask(Frame &frame, Frame &mask, const MorphologyFilter erosionFilter, const unsigned int randomNoise=3u, const unsigned int randomSeed=RandomI::random32())
Closes holes inside a frame using a shrinking/in-bleeding approach based on either a 4-neighborhood o...
This class implements an erosion filter.
Definition: FrameFilterErosion.h:32
static bool shrinkMask8BitPerChannel8Neighbor(uint8_t *frame, uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int maskPaddingElements, const unsigned int randomNoise=0u, const unsigned int randomSeed=RandomI::random32())
Closes a hole inside a frame by using a shrinking/in-bleeding approach based on an 8-neighborhood.
Definition: FrameFilterErosion.h:618
static void filter1Channel8Bit24Neighbor(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue=0x00, const unsigned int maskPaddingElements=0u, const unsigned int targetPaddingElements=0u, Worker *worker=nullptr)
Applies one erosion filter iteration for an 8 bit mask image using a 24-neighborhood,...
Definition: FrameFilterErosion.h:1442
static void filter1Channel8Bit24NeighborSubset(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue, const unsigned int maskPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Applies one erosion filter iteration for an 8 bit mask image using a 24-neighborhood.
static void filter1Channel8Bit8NeighborSubset(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue, const unsigned int maskPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Applies one erosion filter iteration for an 8 bit mask image using a 8-neighborhood.
static void filter1Channel8Bit8Neighbor(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue=0x00, const unsigned int maskPaddingElements=0u, const unsigned int targetPaddingElements=0u, Worker *worker=nullptr)
Applies one erosion filter iteration for an 8 bit mask image using a 8-neighborhood,...
Definition: FrameFilterErosion.h:1427
std::unordered_set< CV::PixelPosition, CV::PixelPosition > PixelPositionSet
Definition of an unordered set holding pixel positions.
Definition: FrameFilterErosion.h:38
static OCEAN_FORCE_INLINE bool onePixelNotEqual(const uint8_t *const maskPixels, const uint8_t maskValue)
Returns whether at least one of several pixels in a row is not equal to a specified value.
static void shrinkMaskRandom8BitPerChannel8Neighbor(uint8_t *frame, uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int maskPaddingElements, const unsigned int randomNoise=0u, const unsigned int randomSeed=RandomI::random32())
Closes a hole inside a frame by using a randomized shrinking/in-bleeding approach based on an 8-neigh...
Definition: FrameFilterErosion.h:1020
static void filter1Channel8Bit(uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int iterations, const uint8_t maskValue=0x00, const unsigned int maskPaddingElements=0u, Worker *worker=nullptr)
Applies several erosion filter iterations for an 8 bit mask image.
Definition: FrameFilterErosion.h:1344
static bool shrinkMask8BitPerChannel4Neighbor(uint8_t *frame, uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int maskPaddingElements, const unsigned int randomNoise=0u, const unsigned int randomSeed=RandomI::random32())
Closes a hole inside a frame by using a shrinking/in-bleeding approach based on a 4-neighborhood.
Definition: FrameFilterErosion.h:250
static void filter1Channel8Bit4NeighborSubset(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue, const unsigned int maskPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Applies one erosion filter iteration in a subset of an 8 bit mask image using a 4-neighborhood.
static void filter1Channel8Bit4Neighbor(const uint8_t *mask, uint8_t *target, const unsigned int width, const unsigned int height, const uint8_t maskValue=0x00, const unsigned int maskPaddingElements=0u, const unsigned int targetPaddingElements=0u, Worker *worker=nullptr)
Applies one erosion filter iteration in an 8 bit mask image using a 4-neighborhood.
Definition: FrameFilterErosion.h:1412
This class implements the base class for all morphology frame filter.
Definition: FrameFilterMorphology.h:26
MorphologyFilter
Definition of individual morphology masks.
Definition: FrameFilterMorphology.h:33
@ MF_SQUARE_3
Square mask filter defined by one center point and 8 surrounded filter pixels with an area of 3x3.
Definition: FrameFilterMorphology.h:37
@ MF_CROSS_3
Cross mask filter defined by one center point and 4 (north, south, west, east) filter pixels with an ...
Definition: FrameFilterMorphology.h:35
@ MF_SQUARE_5
Square mask filter defined by one center point and 24 surrounded filter pixels with an area of 5x5.
Definition: FrameFilterMorphology.h:39
T y() const
Returns the vertical coordinate position of this object.
Definition: PixelPosition.h:470
T x() const
Returns the horizontal coordinate position of this object.
Definition: PixelPosition.h:458
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
bool isContinuous() const
Returns whether all planes of this frame have continuous memory and thus do not contain any padding a...
Definition: Frame.h:4276
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition: Frame.h:4168
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition: Frame.h:4159
@ CM_COPY_REMOVE_PADDING_LAYOUT
Makes a copy of the source memory, but the new plane will not contain padding elements.
Definition: Frame.h:1803
const T * constrow(const unsigned int y, const unsigned int planeIndex=0u) const
Returns the pointer to the constant data of a specific row.
Definition: Frame.h:4193
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition: Frame.h:4042
Definition of a frame type composed by the frame dimension, pixel format and pixel origin.
Definition: Frame.h:30
@ FORMAT_Y8
Pixel format for grayscale images with byte order Y and 8 bits per pixel.
Definition: Frame.h:594
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition: Frame.h:1050
This class implements a generator for random numbers.
Definition: RandomGenerator.h:42
static uint32_t random32()
Returns one random integer number with range [0x00000000, 0xFFFFFFFF].
static unsigned int random(const unsigned int maxValue)
Returns one random integer value with specified maximum value.
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.
std::vector< PixelPosition > PixelPositions
Definition of a vector holding pixel positions (with positive coordinate values).
Definition: PixelPosition.h:48
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15