Ocean
Loading...
Searching...
No Matches
FrameFilterBlur.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_SEGMENTATION_FRAME_FILTER_BLUR_H
9#define META_OCEAN_CV_SEGMENTATION_FRAME_FILTER_BLUR_H
10
13
14#include "ocean/base/Frame.h"
15#include "ocean/base/RandomI.h"
16
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26namespace Segmentation
27{
28
29/**
30 * This class implements functions allowing to blur image content.
31 * @ingroup cvsegmentation
32 */
33class OCEAN_CV_SEGMENTATION_EXPORT FrameFilterBlur
34{
35 public:
36
37 /**
38 * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
39 * Best practice is to avoid using these functions if binary size matters,<br>
40 * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.
41 */
42 class OCEAN_CV_SEGMENTATION_EXPORT Comfort
43 {
44 public:
45
46 /**
47 * Blurs several masked regions in an image.
48 * The resulting image will be a blurred version of the original image, with the masked regions blurred and the remaining regions untouched.
49 * The image color of blurred regions is defined by the average color of the mask region.
50 * @param image The image to be blurred, must be valid
51 * @param mask The mask defining the regions to be blurred, with pixel format FORMAT_Y8, mask values 0x00 define regions to be blurred, 0xFF define regions to remain untouched, must be valid
52 * @param blurBorder Optional border in pixel defining a smooth transition between blurred and non-blurred regions (outside of the masked region), with range [0, infinity), must be odd, 0 to avoid a smooth transition
53 * @param randomGenerator Optional random generator object to add tiny random nose to each blurred region, nullptr to avoid random noise
54 * @return True, if succeeded
55 */
56 static bool blurMaskRegions(Frame& image, const Frame& mask, const unsigned int blurBorder = 5u, RandomGenerator* randomGenerator = nullptr);
57 };
58
59 public:
60
61 /**
62 * Blurs several masked regions in an image.
63 * The resulting image will be a blurred version of the original image, with the masked regions blurred and the remaining regions untouched.
64 * The image color of blurred regions is defined by the average color of the mask region.
65 * @param image The image to be blurred, must be valid
66 * @param mask The mask defining the regions to be blurred, mask values 0x00 define regions to be blurred, 0xFF define regions to remain untouched, must be valid
67 * @param width The width of the image and mask frame in pixel, with range [1, infinity)
68 * @param height The height of the image and mask frame in pixel, with range [1, infinity)
69 * @param imagePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
70 * @param maskPaddingElements The number of padding elements at the end of each mask row, in elements, with range [0, infinity)
71 * @param blurBorder Optional border in pixel defining a smooth transition between blurred and non-blurred regions (outside of the masked region), with range [0, infinity), must be odd, 0 to avoid a smooth transition
72 * @param randomGenerator Optional random generator object to add tiny random nose to each blurred region, nullptr to avoid random noise
73 * @return True, if succeeded
74 * @tparam tChannels The number of channels the image has, with range [1, infinity)
75 */
76 template <unsigned int tChannels>
77 static bool blurMaskRegions8BitPerChannel(uint8_t* image, const uint8_t* mask, const unsigned int width, const unsigned int height, const unsigned int imagePaddingElements, const unsigned int maskPaddingElements, const unsigned int blurBorder = 5u, RandomGenerator* randomGenerator = nullptr);
78};
79
80template <unsigned int tChannels>
81bool FrameFilterBlur::blurMaskRegions8BitPerChannel(uint8_t* image, const uint8_t* mask, const unsigned int width, const unsigned int height, const unsigned int imagePaddingElements, const unsigned int maskPaddingElements, const unsigned int blurBorder, RandomGenerator* randomGenerator)
82{
83 static_assert(tChannels >= 1u, "Invalid channel number!");
84
85 ocean_assert(image != nullptr);
86 ocean_assert(mask != nullptr);
87 ocean_assert(width >= 1u && height >= 1u);
88 ocean_assert(blurBorder == 0u || blurBorder % 2u == 1u);
89
90 Frame imageFrame(FrameType(width, height, FrameType::genericPixelFormat<uint8_t, tChannels>(), FrameType::ORIGIN_UPPER_LEFT), image, Frame::CM_USE_KEEP_LAYOUT, imagePaddingElements);
91
92 const Frame imageMask(FrameType(width, height, FrameType::FORMAT_Y8, FrameType::ORIGIN_UPPER_LEFT), mask, Frame::CM_USE_KEEP_LAYOUT, maskPaddingElements);
93
94 // first, we determine the individual joined masks
95
97
99 CV::Segmentation::MaskAnalyzer::analyzeMaskSeparation8Bit(mask, width, height, maskPaddingElements, separation.data<uint32_t>(), separation.paddingElements(), maskBlocks);
100
101 // now, we determine the average color value of each individual block and update the image content
102
103 CV::PixelBoundingBoxes pixelBoundingBoxes;
104
105 for (const CV::Segmentation::MaskAnalyzer::MaskBlock& maskBlock : maskBlocks)
106 {
107 ocean_assert(maskBlock.size() > 0 && maskBlock.size() <= width * height);
108
109 CV::PixelBoundingBox pixelBoundingBox;
110
111 uint64_t sumColors[tChannels] = {};
112
113 size_t pixels = 0;
114
115 for (unsigned int y = 0u; pixels != maskBlock.size() && y < separation.height(); ++y)
116 {
117 const uint32_t* const rowSepartion = separation.constrow<uint32_t>(y);
118 const uint8_t* const rowImage = imageFrame.constrow<uint8_t>(y);
119
120 for (unsigned int x = 0u; pixels != maskBlock.size() && x < separation.width(); ++x)
121 {
122 if (rowSepartion[x] == maskBlock.id())
123 {
124 for (unsigned int n = 0u; n < tChannels; ++n)
125 {
126 sumColors[n] += rowImage[x * tChannels + n];
127 }
128
129 ++pixels;
130
131 pixelBoundingBox += CV::PixelPosition(x, y);
132 }
133 }
134 }
135
136 ocean_assert(pixels != 0);
137 ocean_assert(pixelBoundingBox.isValid());
138
139 if (pixels == 0)
140 {
141 return false;
142 }
143
144 uint8_t averageColors[tChannels];
145
146 for (unsigned int n = 0u; n < tChannels; ++n)
147 {
148 averageColors[n] = uint8_t((sumColors[n] + (pixels / 2)) / pixels);
149
150 if (randomGenerator != nullptr)
151 {
152 averageColors[n] = uint8_t(minmax(0, int(averageColors[n]) + RandomI::random(*randomGenerator, -10, 10), 255));
153 }
154 }
155
156 for (unsigned int y = pixelBoundingBox.top(); y < pixelBoundingBox.bottomEnd(); ++y)
157 {
158 const uint32_t* const rowSepartion = separation.constrow<uint32_t>(y);
159 uint8_t* const rowImage = imageFrame.row<uint8_t>(y);
160
161 for (unsigned int x = pixelBoundingBox.left(); x < pixelBoundingBox.rightEnd(); ++x)
162 {
163 if (rowSepartion[x] == maskBlock.id())
164 {
165 for (unsigned int n = 0u; n < tChannels; ++n)
166 {
167 rowImage[x * tChannels + n] = averageColors[n];
168 }
169 }
170 }
171 }
172
173 pixelBoundingBoxes.push_back(pixelBoundingBox);
174 }
175
176 if (blurBorder != 0u && blurBorder % 2u != 0u)
177 {
178 // in case the user wants to apply a smooth border between the mask content and the surrounding (remaining image content)
179 // we blend the results with a Gaussian blur
180
181 ocean_assert(maskBlocks.size() == pixelBoundingBoxes.size());
182
183 CV::PixelPositions borderPixels;
184
185 for (size_t n = 0; n < maskBlocks.size(); ++n)
186 {
187 const CV::PixelBoundingBox& pixelBoundingBox = pixelBoundingBoxes[n];
188
189 const CV::PixelBoundingBox extendedBoundingBox = pixelBoundingBox.extended(blurBorder, 0u, 0u, width - 1u, height - 1u);
190
191 Frame sourceSubFrame = imageFrame.subFrame(extendedBoundingBox.left(), extendedBoundingBox.top(), extendedBoundingBox.width(), extendedBoundingBox.height(), Frame::CM_USE_KEEP_LAYOUT);
192
193 Frame blurredSubFrame;
194 if (!CV::FrameFilterGaussian::filter(sourceSubFrame, blurredSubFrame, blurBorder))
195 {
196 ocean_assert(false && "This should never happen!");
197 return false;
198 }
199
200 Frame blendMask = imageMask.subFrame(extendedBoundingBox.left(), extendedBoundingBox.top(), extendedBoundingBox.width(), extendedBoundingBox.height(), Frame::CM_COPY_REMOVE_PADDING_LAYOUT);
201
202 for (unsigned int iteration = 1u; iteration < blurBorder; ++iteration)
203 {
204 borderPixels.clear();
205
206 for (unsigned int y = 0u; y < blendMask.height(); ++y)
207 {
208 const uint8_t* row = blendMask.constrow<uint8_t>(y);
209
210 for (unsigned int x = 0u; x < blendMask.width(); ++x)
211 {
212 if (*row == 0xFFu)
213 {
214 if ((x > 0u && *(row - 1) != 0xFFu) || (x < blendMask.width() - 1u && *(row + 1) != 0xFFu) || (y > 0u && *(row - blendMask.width()) != 0xFFu) || (y < blendMask.height() - 1u && *(row + blendMask.width()) != 0xFFu))
215 {
216 borderPixels.emplace_back(x, y);
217 }
218 }
219
220 ++row;
221 }
222 }
223
224 const uint8_t targetColor = uint8_t((iteration * 255u) / blurBorder);
225
226 uint8_t* blendMaskData = blendMask.data<uint8_t>();
227
228 for (const CV::PixelPosition& borderPixel : borderPixels)
229 {
230 blendMaskData[borderPixel.index(blendMask.width())] = targetColor;
231 }
232 }
233
234 CV::FrameBlender::blend8BitPerChannel<tChannels, true>(blurredSubFrame.constdata<uint8_t>(), blendMask.constdata<uint8_t>(), sourceSubFrame.data<uint8_t>(), sourceSubFrame.width(), sourceSubFrame.height(), blurredSubFrame.paddingElements(), blendMask.paddingElements(), sourceSubFrame.paddingElements());
235 }
236 }
237
238 return true;
239}
240
241}
242
243}
244
245}
246
247#endif // META_OCEAN_CV_SEGMENTATION_FRAME_FILTER_BLUR_H
static bool filter(const Frame &source, Frame &target, const unsigned int filterSize, Worker *worker=nullptr, ReusableMemory *reusableMemory=nullptr)
Applies a Gaussian blur filter to a given source image and copies the resulting filter results to a g...
T left() const
Returns the left (including) pixel position of this bounding box.
Definition PixelBoundingBox.h:416
unsigned int width() const
Returns the width (the number of horizontal including pixels) of this bounding box.
Definition PixelBoundingBox.h:482
T rightEnd() const
Returns the right (excluding) pixel position of this bounding box.
Definition PixelBoundingBox.h:437
bool isValid() const
Returns whether this bounding box covers a valid pixel area.
Definition PixelBoundingBox.h:577
T bottomEnd() const
Returns the bottom (excluding) pixel position of this bounding box.
Definition PixelBoundingBox.h:451
PixelBoundingBoxT< T > extended(const unsigned int pixels, const T minLeft, const T minTop, const T maxRight, const T maxBottom) const
Returns a new bounding box by extending this bounding box with a given number of pixel in each direct...
Definition PixelBoundingBox.h:558
T top() const
Returns the top (including) pixel position of this bounding box.
Definition PixelBoundingBox.h:423
unsigned int height() const
Returns the height (the number of vertical including pixels) of this bounding box.
Definition PixelBoundingBox.h:489
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition FrameFilterBlur.h:43
static bool blurMaskRegions(Frame &image, const Frame &mask, const unsigned int blurBorder=5u, RandomGenerator *randomGenerator=nullptr)
Blurs several masked regions in an image.
This class implements functions allowing to blur image content.
Definition FrameFilterBlur.h:34
static bool blurMaskRegions8BitPerChannel(uint8_t *image, const uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int imagePaddingElements, const unsigned int maskPaddingElements, const unsigned int blurBorder=5u, RandomGenerator *randomGenerator=nullptr)
Blurs several masked regions in an image.
Definition FrameFilterBlur.h:81
This class implements a simple information for a block/area of mask pixels.
Definition segmentation/MaskAnalyzer.h:46
static void analyzeMaskSeparation8Bit(const uint8_t *mask, const unsigned int width, const unsigned int height, const unsigned int maskPaddingElements, uint32_t *separation, const unsigned int separationPaddingElements, MaskBlocks &blocks)
Analyzes an 8 bit binary mask frame and separates the pixels into individual blocks of joined sub-mas...
std::vector< MaskBlock > MaskBlocks
Definition of a vector holding mask block objects.
Definition segmentation/MaskAnalyzer.h:112
This class implements Ocean's image class.
Definition Frame.h:1808
T * row(const unsigned int y, const unsigned int planeIndex=0u)
Returns the pointer to the pixel data of a specific row.
Definition Frame.h:4257
Frame subFrame(const unsigned int subFrameLeft, const unsigned int subFrameTop, const unsigned int subFrameWidth, const unsigned int subFrameHeight, const CopyMode copyMode=CM_USE_KEEP_LAYOUT) const
Returns a sub-frame of this frame.
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:4248
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition Frame.h:4239
@ CM_USE_KEEP_LAYOUT
The source memory is used only, no copy is created, the padding layout is preserved.
Definition Frame.h:1817
@ CM_COPY_REMOVE_PADDING_LAYOUT
Makes a copy of the source memory, but the new plane will not contain padding elements.
Definition Frame.h:1819
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:4273
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:4122
Definition of a frame type composed by the frame dimension, pixel format and pixel origin.
Definition Frame.h:30
@ FORMAT_Y32
Pixel format with 32 bits Y frame.
Definition Frame.h:639
@ FORMAT_Y8
Pixel format for grayscale images with byte order Y and 8 bits per pixel.
Definition Frame.h:594
unsigned int width() const
Returns the width of the frame format in pixel.
Definition Frame.h:3170
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition Frame.h:1050
unsigned int height() const
Returns the height of the frame in pixel.
Definition Frame.h:3175
This class implements a generator for random numbers.
Definition RandomGenerator.h:42
static unsigned int random(const unsigned int maxValue)
Returns one random integer value with specified maximum value.
T minmax(const T &lowerBoundary, const T &value, const T &upperBoundary)
This function fits a given parameter into a specified value range.
Definition base/Utilities.h:903
std::vector< PixelPosition > PixelPositions
Definition of a vector holding pixel positions (with positive coordinate values).
Definition PixelPosition.h:48
PixelPositionT< unsigned int > PixelPosition
Definition of the default PixelPosition object with a data type allowing only positive coordinate val...
Definition PixelPosition.h:34
std::vector< PixelBoundingBox > PixelBoundingBoxes
Definition of a vector holding bounding box objects with only positive coordinate values.
Definition PixelBoundingBox.h:42
The namespace covering the entire Ocean framework.
Definition Accessor.h:15