362 static_assert(tChannels >= 1u,
"Invalid number of frame channels!");
377 for (
unsigned int y = 0; y < height; ++y)
379 for (
unsigned int x = 0; x < width; ++x)
383 ocean_assert(!position.
isValid() || (position.
x() < width && position.
y() < height));
390 uint8_t*
const frameData = frame.
data<uint8_t>();
394 const uint8_t*
const staticMaskData = staticMask.
constdata<uint8_t>();
395 const unsigned int staticMaskStrideElements = staticMask.
strideElements();
397 uint8_t*
const dynamicMaskData = dynamicMask.
data<uint8_t>();
398 const unsigned int dynamicMaskPaddingElements = dynamicMask.
paddingElements();
399 const unsigned int dynamicMaskStrideElements = dynamicMask.
strideElements();
401 int16_t*
const sobelResponseData = sobelResponse.
data<int16_t>();
402 const unsigned int sobelResponseStrideElements = sobelResponse.
strideElements();
405 borderPixels.reserve(1024);
415 inpaintingPixels.emplace_back(borderPixel, borderDirection, imageOrientation);
418 inpaintingPixels.sort();
420 while (!inpaintingPixels.empty())
423 ocean_assert(dynamicMask.
constpixel<uint8_t>(position.
x(), position.
y())[0] != 0xFF);
425 inpaintingPixels.pop_back();
427 unsigned int ssdBest = (
unsigned int)(-1);
429 unsigned int xBest = (
unsigned int)(-1);
430 unsigned int yBest = (
unsigned int)(-1);
439 for (
unsigned int y = max(0,
int(center.
y()) - 3); y < min(center.
y() + 4u, height); ++y)
441 for (
unsigned int x = max(0,
int(center.
x()) - 3); x < min(center.
x() + 4u, width); ++x)
443 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
445 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
463 for (
unsigned int y = max(0,
int(east.
y()) - 3); y < min(east.
y() + 4u, height); ++y)
465 for (
unsigned int x = max(0,
int(east.
x()) - 3); x < min(east.
x() + 4u, width); ++x)
467 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
469 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
487 for (
unsigned int y = max(0,
int(southEast.
y()) - 3); y < min(southEast.
y() + 4u, height); ++y)
489 for (
unsigned int x = max(0,
int(southEast.
x()) - 3); x < min(southEast.
x() + 4u, width); ++x)
491 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
493 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
511 for (
unsigned int y = max(0,
int(south.
y()) - 3); y < min(south.
y() + 4u, height); ++y)
513 for (
unsigned int x = max(0,
int(south.
x()) - 3); x < min(south.
x() + 4u, width); ++x)
515 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
517 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
535 for (
unsigned int y = max(0,
int(southWest.
y()) - 3); y < min(southWest.
y() + 4u, height); ++y)
537 for (
unsigned int x = max(0,
int(southWest.
x()) - 3); x < min(southWest.
x() + 4u, width); ++x)
539 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
541 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
559 for (
unsigned int y = max(0,
int(west.
y()) - 3); y < min(west.
y() + 4u, height); ++y)
561 for (
unsigned int x = max(0,
int(west.
x()) - 3); x < min(west.
x() + 4u, width); ++x)
563 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
565 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
583 for (
unsigned int y = max(0,
int(northWest.
y()) - 3); y < min(northWest.
y() + 4u, height); ++y)
585 for (
unsigned int x = max(0,
int(northWest.
x()) - 3); x < min(northWest.
x() + 4u, width); ++x)
587 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
589 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
607 for (
unsigned int y = max(0,
int(north.
y()) - 3); y < min(north.
y() + 4u, height); ++y)
609 for (
unsigned int x = max(0,
int(north.
x()) - 3); x < min(north.
x() + 4u, width); ++x)
611 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
613 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
631 for (
unsigned int y = max(0,
int(northEast.
y()) - 3); y < min(northEast.
y() + 4u, height); ++y)
633 for (
unsigned int x = max(0,
int(northEast.
x()) - 3); x < min(northEast.
x() + 4u, width); ++x)
635 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
637 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
PixelPosition(x, y));
655 for (
unsigned int n = 0u; n < 100u; ++n)
659 const Vector3 offset = rotation * normal * length;
662 if (first.
x() < width && first.
y() < height && staticMaskData[first.
y() * staticMaskStrideElements + first.
x()] == 0xFF)
664 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position, first);
676 if (second.
x() < width && second.
y() < height && staticMaskData[second.
y() * staticMaskStrideElements + second.
x()] == 0xFF)
678 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position, second);
691 if (ssdBest != (
unsigned int)(-1))
693 const unsigned int iterations = 200u;
694 for (
unsigned int n = 0u; n < iterations; ++n)
696 const int xRadius = max(1,
int(width - (width - 1u) * n / iterations) >> 1);
697 const int yRadius = max(1,
int(height - (height - 1u) * n / iterations) >> 1);
699 const int offsetX =
RandomI::random(randomGenerator, -xRadius, xRadius);
700 const int offsetY =
RandomI::random(randomGenerator, -yRadius, yRadius);
702 const unsigned int randomX = xBest + offsetX;
703 const unsigned int randomY = yBest + offsetY;
705 if (randomX < width && randomY < height && (randomY != position.
y() || randomX != position.
x()) && staticMaskData[randomY * staticMaskStrideElements + randomX] == 0xFF)
707 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
CV::PixelPosition(randomX, randomY));
721 if (ssdBest == (
unsigned int)(-1))
726 for (
unsigned int y = 0u; y < height; ++y)
728 const uint8_t*
const staticMaskRow = staticMask.
constrow<uint8_t>(y);
730 for (
unsigned int x = 0u; x < width; ++x)
732 if ((y != position.
y() || x != position.
x()) && staticMaskRow[x] == 0xFF)
734 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
CV::PixelPosition(x, y));
756 for (
unsigned int y = top; y < bottomEnd; ++y)
758 for (
unsigned int x = left; x < rightEnd; ++x)
760 if ((y != position.
y() || x != position.
x()) && staticMaskData[y * staticMaskStrideElements + x] == 0xFF)
762 const unsigned int ssd = SSD::template determine5x5<tChannels>(frameData, dynamicMaskData, width, height, framePaddingElements, dynamicMaskPaddingElements, position,
CV::PixelPosition(x, y));
777 if (ssdBest == (
unsigned int)(-1))
779 for (
unsigned int y = 0u; ssdBest == (
unsigned int)(-1) && y < height; ++y)
781 const uint8_t* dynamicMaskRow = dynamicMask.
constrow<uint8_t>(y);
783 for (
unsigned int x = 0u; x < width; ++x)
785 if (dynamicMaskRow[x] == 0xFFu)
787 ssdBest = (
unsigned int)(-2);
798 if (ssdBest == (
unsigned int)(-1))
803 ocean_assert(xBest < width && yBest < height);
806 CVUtilities::copyPixel<tChannels>(frameData + position.
y() * frameStrideElements + position.
x() * tChannels, frameData + yBest * frameStrideElements + xBest * tChannels);
808 for (
unsigned int y = max(0,
int(position.
y()) - 1); y < min(position.
y() + 2u, height); ++y)
810 for (
unsigned int x = max(0,
int(position.
x()) - 1); x < min(position.
x() + 2u, width); ++x)
812 CV::FrameFilterSobel::filterPixelHorizontalVertical8BitPerChannel<int16_t, tChannels>(frameData, width, height, x, y, sobelResponseData + y * sobelResponseStrideElements + x * tChannels * 2u, framePaddingElements);
818 newBorderPixels.reserve(4u);
820 constexpr uint8_t nonMaskPixelValue = 0xFF;
823 if (position.
x() - 1u < width - 2u)
826 if (position.
y() > 1u && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
north(), nonMaskPixelValue))
828 newBorderPixels.emplace_back(position.
north());
832 if (position.
y() + 2u < height && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
south(), nonMaskPixelValue))
834 newBorderPixels.emplace_back(position.
south());
838 if (position.
y() - 1u < height - 2u)
841 if (position.
x() > 1u && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
west(), nonMaskPixelValue))
843 newBorderPixels.emplace_back(position.
west());
847 if (position.
x() + 2u < width && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
east(), nonMaskPixelValue))
849 newBorderPixels.emplace_back(position.
east());
859 ocean_assert(newBorerPixel != inpaintingPixel);
866 ocean_assert(dynamicMask.
constpixel<uint8_t>(position.
x(), position.
y())[0] != 0xFFu);
867 ocean_assert(staticMask.
constpixel<uint8_t>(xBest, yBest)[0] == 0xFFu);
869 dynamicMaskData[position.
y() * dynamicMaskStrideElements + position.
x()] = 0xFFu;
876 for (InpaintingPixelList::iterator i = inpaintingPixels.begin(); i != inpaintingPixels.end(); )
878 ocean_assert(*i != position);
881 const int dx = abs(
int(i->x()) -
int(position.
x()));
882 const int dy = abs(
int(i->y()) -
int(position.
y()));
884 if (dx <= 3 && dy <= 3)
887 changedInpaintingPixels.emplace_back(*i,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, *i),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, *i));
889 i = inpaintingPixels.erase(i);
900 changedInpaintingPixels.emplace_back(newBorderPixel,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, newBorderPixel),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, newBorderPixel));
903 changedInpaintingPixels.sort();
904 inpaintingPixels.merge(changedInpaintingPixels);
909 ocean_assert(inpaintingPixel ==
InpaintingPixel(inpaintingPixel,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, inpaintingPixel),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, inpaintingPixel)));
915 for (
unsigned int y = 0; y < height; ++y)
917 for (
unsigned int x = 0; x < width; ++x)
919 ocean_assert(dynamicMask.
constpixel<uint8_t>(x, y)[0] == 0xFFu);
922 if (staticMask.
constpixel<uint8_t>(x, y)[0] != 0xFFu)
924 ocean_assert(position.
isValid() && position.
x() < width && position.
y() < height);
928 ocean_assert(!position.
isValid());