Ocean
FrameFilter.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_FILTER_H
9 #define META_OCEAN_CV_FRAME_FILTER_H
10 
11 #include "ocean/cv/CV.h"
12 
13 #include "ocean/base/DataType.h"
14 #include "ocean/base/Worker.h"
15 
16 #include "ocean/math/Numeric.h"
17 
18 namespace Ocean
19 {
20 
21 namespace CV
22 {
23 
24 /**
25  * This class implements the base class for all filter.
26  * @ingroup cv
27  */
28 class OCEAN_CV_EXPORT FrameFilter
29 {
30  public:
31 
32  /**
33  * Determines the per-pixel magnitude of a frame.
34  * @param frame The input frame for which the magnitude will be determined, must be valid
35  * @param magnitude The resulting magnitude frame, must be valid
36  * @param width The width of the input (and magnitude) frame, in pixels, with range [1, infinity)
37  * @param height The height of the input (and magnitude) frame, in pixels, with range [1, infinity)
38  * @param channels The number of channels the frame has, with range [2, infinity)
39  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
40  * @param magnitudePaddingElements The number of padding elements at the end of each magnitude row, in elements, with range [0, infinity)
41  * @param worker The worker object to distribute the computation
42  * @tparam T The data type of the frame pixel channel
43  * @tparam TMagnitude The data type of the magnitude, ensure that the magnitude of 'T' (over all channels) fits into 'TMagnitude'
44  */
45  template <typename T, typename TMagnitude>
46  static void magnitude(const T* frame, TMagnitude* magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, Worker* worker = nullptr);
47 
48  /**
49  * Normalizes a given value with a template-based normalization factor.
50  * This function will create a wrong rounded normalization result for extremely large 32bit and 64bit integers if the value is within tNormalizationDenominator/2 to the value range.<br>
51  * Thus, for integers and if 'tRoundedNormalization == true', the value range for valid rounded normalization results is:
52  * <pre>
53  * int32_t: [-2147483648 + tNormalizationDenominator/2, 2147483647 - tNormalizationDenominator/2]
54  * uint32_t: [0, 4294967295 - tNormalizationDenominator/2]
55 
56  * int64_t: [-9223372036854775808 + tNormalizationDenominator/2, 9223372036854775807 - tNormalizationDenominator/2]
57  * uint64_t: [0, 18446744073709551615 - tNormalizationDenominator/2]
58  * </pre>
59  * @param value The value to be normalized
60  * @return The normalized value 'value / tNormalization'
61  * @tparam T The data type of the value to normalize, either an integer value or a floating point value
62  * @tparam tNormalizationDenominator The normalization factor to be applied, with range [1, infinity)
63  * @tparam tRoundedNormalization True, to apply a rounded normalization; False, to apply a normalization without rounding (ignored for floating point values)
64  * @see normalizeValueSlow().
65  */
66  template <typename T, T tNormalizationDenominator, bool tRoundedNormalization>
67  static inline T normalizeValue(const T& value);
68 
69  /**
70  * Normalizes a given value with a template-based normalization factor.
71  * This function does not provide wrong normalization results for extremely large 32bit and 64bit integers if 'tRoundedNormalization == true', but is also slower.
72  * @param value The value to be normalized
73  * @return The normalized value 'value / tNormalization'
74  * @tparam T The data type of the value to normalize, either an integer value or a floating point value
75  * @tparam tNormalizationDenominator The normalization factor to be applied, with range [1, infinity)
76  * @tparam tRoundedNormalization True, to apply a rounded normalization; False, to apply a normalization without rounding (ignored for floating point values)
77  * @see normalizeValue().
78  */
79  template <typename T, T tNormalizationDenominator, bool tRoundedNormalization>
80  static inline T normalizeValueSlow(const T& value);
81 
82  protected:
83 
84  /**
85  * Determines the per-pixel magnitude for a subset of a frame.
86  * @param frame The input frame for which the magnitude will be determined, must be valid
87  * @param magnitude The resulting magnitude frame, must be valid
88  * @param width The width of the input (and magnitude) frame, in pixels, with range [1, infinity)
89  * @param height The height of the input (and magnitude) frame, in pixels, with range [1, infinity)
90  * @param channels The number of channels the frame has, with range [2, infinity)
91  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
92  * @param magnitudePaddingElements The number of padding elements at the end of each magnitude row, in elements, with range [0, infinity)
93  * @param firstRow The first row to be handled, with range [0, height - 1]
94  * @param numberRows The number of rows to be handled, with range [1, height - firstRow]
95  * @tparam T The data type of the frame pixel channel
96  * @tparam TMagnitude The data type of the magnitude, ensure that the magnitude of 'T' (over all channels) fits into 'TMagnitude'
97  */
98  template <typename T, typename TMagnitude>
99  static void magnitudeSubset(const T* frame, TMagnitude* magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, const unsigned int firstRow, const unsigned int numberRows);
100 
101  /**
102  * Determines the per-pixel magnitude for a subset of a frame.
103  * This function applies a lookup-based sqrt calculation.
104  * @param frame The input frame for which the magnitude will be determined, must be valid
105  * @param magnitude The resulting magnitude frame, must be valid
106  * @param width The width of the input (and magnitude) frame, in pixels, with range [1, infinity)
107  * @param height The height of the input (and magnitude) frame, in pixels, with range [1, infinity)
108  * @param channels The number of channels the frame has, with range [2, infinity)
109  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
110  * @param magnitudePaddingElements The number of padding elements at the end of each magnitude row, in elements, with range [0, infinity)
111  * @param firstRow The first row to be handled, with range [0, height - 1]
112  * @param numberRows The number of rows to be handled, with range [1, height - firstRow]
113  */
114  static void magnitude2Channels8BitPerChannelSubset(const uint8_t* frame, uint16_t* magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, const unsigned int firstRow, const unsigned int numberRows);
115 };
116 
117 template <typename T, typename TMagnitude>
118 void FrameFilter::magnitude(const T* frame, TMagnitude* magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, Worker* worker)
119 {
120  static_assert(sizeof(T) <= sizeof(TMagnitude), "Invalid data type!");
121 
122  ocean_assert(frame != nullptr);
123  ocean_assert(magnitude != nullptr);
124  ocean_assert(channels >= 2u);
125  ocean_assert(width >= 1u && height >= 1u);
126 
127  if (worker != nullptr)
128  {
129  worker->executeFunction(Worker::Function::createStatic(&magnitudeSubset<T, TMagnitude>, frame, magnitude, channels, width, height, framePaddingElements, magnitudePaddingElements, 0u, 0u), 0u, height);
130  }
131  else
132  {
133  magnitudeSubset<T, TMagnitude>(frame, magnitude, channels, width, height, framePaddingElements, magnitudePaddingElements, 0u, height);
134  }
135 }
136 
137 template <typename T, T tNormalizationDenominator, bool tRoundedNormalization>
138 inline T FrameFilter::normalizeValue(const T& value)
139 {
140  static_assert(tNormalizationDenominator > T(0), "Invalid normalization!");
141 
142  if constexpr (tNormalizationDenominator == T(1))
143  {
144  return value;
145  }
146 
147  if constexpr (std::is_floating_point<T>::value)
148  {
149  return value / tNormalizationDenominator;
150  }
151  else
152  {
153  constexpr T tNormalizationDenominator_2 = tNormalizationDenominator / T(2);
154 
155 #ifdef OCEAN_DEBUG
156  ocean_assert((std::is_integral<T>::value));
157 
158  if constexpr (tRoundedNormalization)
159  {
160  if constexpr (std::is_same<T, int32_t>::value)
161  {
162  ocean_assert(value >= NumericT<int32_t>::minValue() + tNormalizationDenominator_2);
163  ocean_assert(value <= NumericT<int32_t>::maxValue() - tNormalizationDenominator_2);
164  }
165 
166  if constexpr (std::is_same<T, uint32_t>::value)
167  {
168  ocean_assert(value <= NumericT<uint32_t>::maxValue() - tNormalizationDenominator_2);
169  }
170 
171  if constexpr (std::is_same<T, int64_t>::value)
172  {
173  ocean_assert(value >= NumericT<int64_t>::minValue() + tNormalizationDenominator_2);
174  ocean_assert(value <= NumericT<int64_t>::maxValue() - tNormalizationDenominator_2);
175  }
176 
177  if constexpr (std::is_same<T, uint64_t>::value)
178  {
179  ocean_assert(value <= NumericT<uint64_t>::maxValue() - tNormalizationDenominator_2);
180  }
181  }
182 #endif // OCEAN_DEBUG
183 
184  if constexpr (tRoundedNormalization && std::is_signed<T>::value)
185  {
186  if (value >= T(0))
187  {
188  return (value + tNormalizationDenominator_2) / tNormalizationDenominator;
189  }
190  else
191  {
192  return (value - tNormalizationDenominator_2) / tNormalizationDenominator;
193  }
194  }
195  else
196  {
197  if constexpr (tRoundedNormalization)
198  {
199  return (value + tNormalizationDenominator_2) / tNormalizationDenominator;
200  }
201  else
202  {
203  return value / tNormalizationDenominator;
204  }
205  }
206  }
207 }
208 
209 template <typename T, T tNormalizationDenominator, bool tRoundedNormalization>
210 inline T FrameFilter::normalizeValueSlow(const T& value)
211 {
212  if constexpr (std::is_integral<T>::value && tNormalizationDenominator != T(1) && tRoundedNormalization && sizeof(T) >= 4)
213  {
214  constexpr T tNormalizationDenominator_2 = (tNormalizationDenominator + 1) / T(2);
215 
216  if constexpr (std::is_signed<T>::value)
217  {
218  if (value < T(0))
219  {
220  const T remainder = value % tNormalizationDenominator;
221 
222  if (remainder <= -tNormalizationDenominator_2)
223  {
224  return value / tNormalizationDenominator - T(1);
225  }
226  else
227  {
228  return value / tNormalizationDenominator;
229  }
230  }
231 
232  }
233 
234  const T remainder = value % tNormalizationDenominator;
235 
236  if (remainder >= tNormalizationDenominator_2)
237  {
238  return value / tNormalizationDenominator + T(1);
239  }
240  else
241  {
242  return value / tNormalizationDenominator;
243  }
244  }
245  else
246  {
247  return normalizeValue<T, tNormalizationDenominator, tRoundedNormalization>(value);
248  }
249 }
250 
251 template <typename T, typename TMagnitude>
252 void FrameFilter::magnitudeSubset(const T* frame, TMagnitude* magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
253 {
254  static_assert(sizeof(T) <= sizeof(TMagnitude), "Invalid data type!");
255 
256  ocean_assert(frame != nullptr);
257  ocean_assert(magnitude != nullptr);
258  ocean_assert(channels >= 2u);
259  ocean_assert(width >= 1u && height >= 1u);
260 
261  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
262 
263  if constexpr (std::is_same<T, uint8_t>::value && std::is_same<TMagnitude, uint16_t>::value)
264  {
265  if (channels == 2u)
266  {
267  magnitude2Channels8BitPerChannelSubset(frame, magnitude, channels, width, height, framePaddingElements, magnitudePaddingElements, firstRow, numberRows);
268  return;
269  }
270  }
271 
272  using TSqrMagnitude = typename SquareValueTyper<TMagnitude>::Type;
273  using TIntermediateFloat = typename FloatTyper<TMagnitude>::Type;
274 
275  const unsigned int frameStrideElements = width * channels + framePaddingElements;
276  const unsigned int magnitudeStrideElements = width + magnitudePaddingElements;
277 
278  frame += firstRow * frameStrideElements;
279  magnitude += firstRow * magnitudeStrideElements;
280 
281  for (unsigned int y = 0u; y < numberRows; ++y)
282  {
283  for (unsigned int x = 0u; x < width; ++x)
284  {
285  TSqrMagnitude sqrMagnitude = TSqrMagnitude(0);
286 
287  for (unsigned int n = 0u; n < channels; ++n)
288  {
289  sqrMagnitude += TSqrMagnitude(frame[n]) * TSqrMagnitude(frame[n]);
290  }
291 
292  const TIntermediateFloat floatMagnitude = NumericT<TIntermediateFloat>::sqrt(TIntermediateFloat(sqrMagnitude));
293 
294  if constexpr (std::is_floating_point<TMagnitude>::value)
295  {
296  ocean_assert(NumericT<TMagnitude>::isInsideValueRange(floatMagnitude));
297  }
298  else
299  {
300  ocean_assert(TIntermediateFloat(NumericT<TMagnitude>::minValue()) <= floatMagnitude);
301  ocean_assert(floatMagnitude < TIntermediateFloat(NumericT<TMagnitude>::maxValue()));
302  }
303 
304  *magnitude = TMagnitude(floatMagnitude);
305 
306  frame += channels;
307  ++magnitude;
308  }
309 
310  frame += framePaddingElements;
311  magnitude += magnitudePaddingElements;
312  }
313 }
314 
315 }
316 
317 }
318 
319 #endif // META_OCEAN_CV_FRAME_FILTER_H
This class implements the base class for all filter.
Definition: FrameFilter.h:29
static T normalizeValueSlow(const T &value)
Normalizes a given value with a template-based normalization factor.
Definition: FrameFilter.h:210
static T normalizeValue(const T &value)
Normalizes a given value with a template-based normalization factor.
Definition: FrameFilter.h:138
static void magnitude(const T *frame, TMagnitude *magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, Worker *worker=nullptr)
Determines the per-pixel magnitude of a frame.
Definition: FrameFilter.h:118
static void magnitudeSubset(const T *frame, TMagnitude *magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Determines the per-pixel magnitude for a subset of a frame.
Definition: FrameFilter.h:252
static void magnitude2Channels8BitPerChannelSubset(const uint8_t *frame, uint16_t *magnitude, const unsigned int channels, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int magnitudePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Determines the per-pixel magnitude for a subset of a frame.
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 provides basic numeric functionalities.
Definition: Numeric.h:57
static T sqrt(const T value)
Returns the square root of a given value.
Definition: Numeric.h:1533
T Type
Definition of the data type for the square value.
Definition: DataType.h:132
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
float Type
The 32 bit floating point data type for any data type T but 'double'.
Definition: DataType.h:373