Ocean
FrameFilterMean.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_FRAME_MEAN_FILTER_H
9 #define META_OCEAN_CV_FRAME_MEAN_FILTER_H
10 
11 #include "ocean/cv/CV.h"
12 #include "ocean/cv/IntegralImage.h"
13 
14 #include "ocean/base/Frame.h"
15 #include "ocean/base/Worker.h"
16 
17 namespace Ocean
18 {
19 
20 namespace CV
21 {
22 
23 /**
24  * This class implements a mean frame filter.
25  * @ingroup cv
26  */
27 class OCEAN_CV_EXPORT FrameFilterMean
28 {
29  public:
30 
31  /**
32  * Definition of different mean filter masks.
33  */
34  enum FilterMask : uint32_t
35  {
36  /// Invalid filter mask.
37  FM_INVALID = 0u,
38  /// One dimensional mean filter mask: 1/3 * [1 1 1].
39  FM_KERNEL_3 = 3u,
40  /// One dimensional mean filter mask: 1/5 * [1 1 1 1 1].
41  FM_KERNEL_5 = 5u
42  };
43 
44  public:
45 
46  /**
47  * Filters a given frame using a mean filter with arbitrary size by internally using a bordered integral image.
48  * @param source The source frame to be filtered
49  * @param target The target frame receiving the filtered frame
50  * @param window Size of the filter window in pixel, must be odd (actual size: window x window)
51  * @param worker Optional worker object to distribute the computation
52  * @return True, if succeeded
53  */
54  static bool filter(const Frame& source, Frame& target, const unsigned int window, Worker* worker = nullptr);
55 
56  /**
57  * Filters a given frame using a mean filter with arbitrary size by internally using a bordered integral image.
58  * @param frame The frame to be filtered
59  * @param window Size of the filter window in pixel, must be odd (actual size: window x window)
60  * @param worker Optional worker object to distribute the computation
61  * @return True, if succeeded
62  */
63  static bool filter(Frame& frame, const unsigned int window, Worker* worker = nullptr);
64 
65  /**
66  * Filters a given frame using a mean filter with arbitrary windows size by internally using a bordered integral image.
67  * @param source The source frame to be filtered, must be valid
68  * @param target The target frame receiving the filter result, must be valid
69  * @param width The width of source and target frame, in pixel, with range [1, infinity)
70  * @param height The height of source and target frame, in pixel, with range [1, infinity)
71  * @param window Size of the filter window in pixel, with range [1, infinity), must be odd (actual size: window x window)
72  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
73  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
74  * @param worker Optional worker object to distribute the computation
75  * @tparam tChannels The number of frame channels, with range [1, infinity)
76  */
77  template <unsigned int tChannels>
78  static void filter8BitPerChannel(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
79 
80  /**
81  * Filters a given frame using a mean filter with arbitrary windows size by internally using a bordered integral image.
82  * @param frame The frame to be filtered, must be valid
83  * @param width The width of source and target frame, in pixel, with range [1, infinity)
84  * @param height The height of source and target frame, in pixel, with range [1, infinity)
85  * @param window Size of the filter window in pixel, with range [1, infinity), must be odd (actual size: window x window)
86  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
87  * @param worker Optional worker object to distribute the computation
88  * @tparam tChannels The number of frame channels, with range [1, infinity)
89  */
90  template <unsigned int tChannels>
91  static void filter8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int framePaddingElements, Worker* worker = nullptr);
92 
93  /**
94  * Filters a frame using a mean filter with arbitrary size by using a bordered integral image.
95  * The size of the integral image's border must be `window / 2`.<br>
96  * @param borderedIntegral The bordered integral image of the original image, with border `window / 2`, must be valid
97  * @param target The target frame receiving the filter result, must be valid
98  * @param width The width of the original image in pixel, with range [1, infinity)
99  * @param height The height of the original image in pixel, with range [1, infinity)
100  * @param window Size of the filter window in pixel, with range [1, infinity), must be odd (actual size: window x window)
101  * @param borderedIntegralPaddingElements The number of padding elements at the end of each integral image row, in elements, with range [0, infinity)
102  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
103  * @param worker Optional worker object to distribute the computation
104  * @tparam tChannels The number of channels the original frame (and the bordered integral image) has, with range [1, infinity)
105  */
106  template <unsigned int tChannels>
107  static void filterWithIntegral8BitPerChannel(const uint32_t* borderedIntegral, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
108 
109  protected:
110 
111  /**
112  * Filters a subset of a frame using a mean filter with arbitrary size by using a bordered integral image.
113  * The size of the integral image's border must be `window / 2`.<br>
114  * @param borderedIntegral The bordered integral image of the original image, with border `window / 2`, must be valid
115  * @param target The target frame receiving the filter result, must be valid
116  * @param width The width of the original image in pixel, with range [1, infinity)
117  * @param height The height of the original image in pixel, with range [1, infinity)
118  * @param window Size of the filter window in pixel, with range [1, infinity), must be odd (actual size: window x window)
119  * @param borderedIntegralPaddingElements The number of padding elements at the end of each integral image row, in elements, with range [0, infinity)
120  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
121  * @param firstRow The first row to be handled, with range [0, height - 1]
122  * @param numberRows The number of rows to be handled, with range [1, height - firstRow]
123  * @tparam tChannels The number of channels the original frame (and the bordered integral image) has, with range [1, infinity)
124  */
125  template <unsigned int tChannels>
126  static void filterWithIntegral8BitPerChannelSubset(const uint32_t* borderedIntegral, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows);
127 };
128 
129 template <unsigned int tChannels>
130 void FrameFilterMean::filter8BitPerChannel(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
131 {
132  static_assert(tChannels >= 1u, "Invalid channel number!");
133 
134  ocean_assert(source != nullptr && target != nullptr);
135  ocean_assert(window % 2u == 1u);
136 
137  const unsigned int border = window / 2u;
138 
139  const unsigned int integralWidth = width + window;
140  const unsigned int integralHeight = height + window;
141 
142  Frame integralFrame(FrameType(integralWidth, integralHeight, FrameType::genericPixelFormat<uint32_t, tChannels>(), FrameType::ORIGIN_UPPER_LEFT));
143  CV::IntegralImage::createBorderedImageMirror<uint8_t, uint32_t, tChannels>(source, integralFrame.data<uint32_t>(), width, height, border, sourcePaddingElements, integralFrame.paddingElements());
144 
145  filterWithIntegral8BitPerChannel<tChannels>(integralFrame.constdata<uint32_t>(), target, width, height, window, integralFrame.paddingElements(), targetPaddingElements, worker);
146 }
147 
148 template <unsigned int tChannels>
149 void FrameFilterMean::filter8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int framePaddingElements, Worker* worker)
150 {
151  static_assert(tChannels >= 1u, "Invalid channel number!");
152 
153  ocean_assert(frame != nullptr);
154  ocean_assert(window % 2u == 1u);
155 
156  const unsigned int border = window / 2u;
157 
158  const unsigned int integralWidth = width + window;
159  const unsigned int integralHeight = height + window;
160 
161  Frame integralFrame(FrameType(integralWidth, integralHeight, FrameType::genericPixelFormat<uint32_t, tChannels>(), FrameType::ORIGIN_UPPER_LEFT));
162  CV::IntegralImage::createBorderedImageMirror<uint8_t, uint32_t, tChannels>(frame, integralFrame.data<uint32_t>(), width, height, border, framePaddingElements, integralFrame.paddingElements());
163 
164  filterWithIntegral8BitPerChannel<tChannels>(integralFrame.constdata<uint32_t>(), frame, width, height, window, integralFrame.paddingElements(), framePaddingElements, worker);
165 }
166 
167 template <unsigned int tChannels>
168 inline void FrameFilterMean::filterWithIntegral8BitPerChannel(const uint32_t* borderedIntegral, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, Worker* worker)
169 {
170  static_assert(tChannels >= 1u, "Invalid channel number!");
171 
172  ocean_assert(borderedIntegral != nullptr && target != nullptr);
173  ocean_assert(window % 2u == 1u);
174 
175  if (worker)
176  {
177  worker->executeFunction(Worker::Function::createStatic(&FrameFilterMean::filterWithIntegral8BitPerChannelSubset<tChannels>, borderedIntegral, target, width, height, window, borderedIntegralPaddingElements, targetPaddingElements, 0u, 0u), 0u, height);
178  }
179  else
180  {
181  filterWithIntegral8BitPerChannelSubset<tChannels>(borderedIntegral, target, width, height, window, borderedIntegralPaddingElements, targetPaddingElements, 0u, height);
182  }
183 }
184 
185 template <unsigned int tChannels>
186 void FrameFilterMean::filterWithIntegral8BitPerChannelSubset(const uint32_t* borderedIntegral, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
187 {
188  ocean_assert(borderedIntegral != nullptr && target != nullptr);
189  ocean_assert(window % 2u == 1u);
190 
191  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
192 
193  const unsigned int borderedIntegralStrideElements = (width + window) * tChannels + borderedIntegralPaddingElements; // window as the integral image has a border of size window/2, and one extra row/column
194  const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
195 
196  const unsigned int integralSkipElements = window * tChannels + borderedIntegralPaddingElements;
197 
198  const unsigned int area = window * window;
199  const unsigned int area_2 = (area + 1u) / 2u;
200 
201  const uint32_t* integralTopLeft = borderedIntegral + firstRow * borderedIntegralStrideElements;
202  const uint32_t* integralBottomLeft = borderedIntegral + (firstRow + window) * borderedIntegralStrideElements;
203 
204  const uint32_t* integralTopRight = integralTopLeft + window * tChannels;
205  const uint32_t* integralBottomRight = integralBottomLeft + window * tChannels;
206 
207  uint8_t* targetRow = target + firstRow * targetStrideElements;
208 
209  for (unsigned int y = 0u; y < numberRows; ++y)
210  {
211  ocean_assert((integralTopLeft - borderedIntegral) % borderedIntegralStrideElements == 0u);
212  ocean_assert((integralBottomLeft - borderedIntegral) % borderedIntegralStrideElements == 0u);
213 
214  for (unsigned int x = 0u; x < width; ++x)
215  {
216  for (unsigned int n = 0u; n < tChannels; ++n)
217  {
218  ocean_assert((*integralTopLeft - *integralTopRight - *integralBottomLeft + *integralBottomRight + area_2) / area <= 255u);
219 
220  *targetRow++ = uint8_t((*integralTopLeft++ - *integralTopRight++ - *integralBottomLeft++ + *integralBottomRight++ + area_2) / area);
221  }
222  }
223 
224  integralTopLeft += integralSkipElements;
225  integralBottomLeft += integralSkipElements;
226 
227  integralTopRight += integralSkipElements;
228  integralBottomRight += integralSkipElements;
229 
230  targetRow += targetPaddingElements;
231  }
232 }
233 
234 }
235 
236 }
237 
238 #endif // META_OCEAN_CV_FRAME_MEAN_FILTER_H
This class implements a mean frame filter.
Definition: FrameFilterMean.h:28
FilterMask
Definition of different mean filter masks.
Definition: FrameFilterMean.h:35
static void filter8BitPerChannel(const uint8_t *source, uint8_t *target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Filters a given frame using a mean filter with arbitrary windows size by internally using a bordered ...
Definition: FrameFilterMean.h:130
static bool filter(const Frame &source, Frame &target, const unsigned int window, Worker *worker=nullptr)
Filters a given frame using a mean filter with arbitrary size by internally using a bordered integral...
static void filterWithIntegral8BitPerChannel(const uint32_t *borderedIntegral, uint8_t *target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Filters a frame using a mean filter with arbitrary size by using a bordered integral image.
Definition: FrameFilterMean.h:168
static void filterWithIntegral8BitPerChannelSubset(const uint32_t *borderedIntegral, uint8_t *target, const unsigned int width, const unsigned int height, const unsigned int window, const unsigned int borderedIntegralPaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Filters a subset of a frame using a mean filter with arbitrary size by using a bordered integral imag...
Definition: FrameFilterMean.h:186
static bool filter(Frame &frame, const unsigned int window, Worker *worker=nullptr)
Filters a given frame using a mean filter with arbitrary size by internally using a bordered integral...
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
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
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
@ 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 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