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))
782 for (
unsigned int y = 0u; ssdBest == (
unsigned int)(-1) && y < height; ++y)
784 const uint8_t* staticMaskRow = staticMask.
constrow<uint8_t>(y);
786 for (
unsigned int x = 0u; x < width; ++x)
788 if (staticMaskRow[x] == 0xFFu)
790 ssdBest = (
unsigned int)(-2);
801 if (ssdBest == (
unsigned int)(-1))
806 ocean_assert(xBest < width && yBest < height);
809 CVUtilities::copyPixel<tChannels>(frameData + position.
y() * frameStrideElements + position.
x() * tChannels, frameData + yBest * frameStrideElements + xBest * tChannels);
811 for (
unsigned int y = max(0,
int(position.
y()) - 1); y < min(position.
y() + 2u, height); ++y)
813 for (
unsigned int x = max(0,
int(position.
x()) - 1); x < min(position.
x() + 2u, width); ++x)
815 CV::FrameFilterSobel::filterPixelHorizontalVertical8BitPerChannel<int16_t, tChannels>(frameData, width, height, x, y, sobelResponseData + y * sobelResponseStrideElements + x * tChannels * 2u, framePaddingElements);
821 newBorderPixels.reserve(4u);
823 constexpr uint8_t nonMaskPixelValue = 0xFF;
826 if (position.
x() - 1u < width - 2u)
829 if (position.
y() > 1u && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
north(), nonMaskPixelValue))
831 newBorderPixels.emplace_back(position.
north());
835 if (position.
y() + 2u < height && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
south(), nonMaskPixelValue))
837 newBorderPixels.emplace_back(position.
south());
841 if (position.
y() - 1u < height - 2u)
844 if (position.
x() > 1u && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
west(), nonMaskPixelValue))
846 newBorderPixels.emplace_back(position.
west());
850 if (position.
x() + 2u < width && !Segmentation::MaskAnalyzer::hasMaskNeighbor5<true>(dynamicMaskData, width, height, dynamicMaskPaddingElements, position.
east(), nonMaskPixelValue))
852 newBorderPixels.emplace_back(position.
east());
862 ocean_assert(newBorerPixel != inpaintingPixel);
869 ocean_assert(dynamicMask.
constpixel<uint8_t>(position.
x(), position.
y())[0] != 0xFFu);
870 ocean_assert(staticMask.
constpixel<uint8_t>(xBest, yBest)[0] == 0xFFu);
872 dynamicMaskData[position.
y() * dynamicMaskStrideElements + position.
x()] = 0xFFu;
879 for (InpaintingPixelList::iterator i = inpaintingPixels.begin(); i != inpaintingPixels.end(); )
881 ocean_assert(*i != position);
884 const int dx = abs(
int(i->x()) -
int(position.
x()));
885 const int dy = abs(
int(i->y()) -
int(position.
y()));
887 if (dx <= 3 && dy <= 3)
890 changedInpaintingPixels.emplace_back(*i,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, *i),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, *i));
892 i = inpaintingPixels.erase(i);
903 changedInpaintingPixels.emplace_back(newBorderPixel,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, newBorderPixel),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, newBorderPixel));
906 changedInpaintingPixels.sort();
907 inpaintingPixels.merge(changedInpaintingPixels);
912 ocean_assert(inpaintingPixel ==
InpaintingPixel(inpaintingPixel,
InpaintingPixel::determineBorderDirection5x5(dynamicMaskData, width, height, dynamicMaskPaddingElements, inpaintingPixel),
InpaintingPixel::determineImageOrientation5x5<tChannels>(sobelResponseData, dynamicMaskData, width, height, sobelResponseStrideElements, dynamicMaskPaddingElements, inpaintingPixel)));
918 for (
unsigned int y = 0; y < height; ++y)
920 for (
unsigned int x = 0; x < width; ++x)
922 ocean_assert(dynamicMask.
constpixel<uint8_t>(x, y)[0] == 0xFFu);
925 if (staticMask.
constpixel<uint8_t>(x, y)[0] != 0xFFu)
927 ocean_assert(position.
isValid() && position.
x() < width && position.
y() < height);
931 ocean_assert(!position.
isValid());