Ocean
FrameVariance.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_VARIANCE_H
9 #define META_OCEAN_CV_FRAME_VARIANCE_H
10 
11 #include "ocean/cv/CV.h"
12 
13 #include "ocean/math/Numeric.h"
14 
15 namespace Ocean
16 {
17 
18 namespace CV
19 {
20 
21 
22 /**
23  * This class implements functions to determine the frame variance.
24  * @ingroup cv
25  */
26 class OCEAN_CV_EXPORT FrameVariance
27 {
28  public:
29 
30  /**
31  * This functions determines the frame deviation of a 1 channel 8 bit frame.
32  * @param frame Original frame to determine the variance for
33  * @param integral Bordered integral frame of the original frame with border size equal have of the specified window size, the border must be mirrored
34  * @param deviation Resulting deviation frame
35  * @param width The width of the original frame
36  * @param height The height of the original frame
37  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
38  * @param deviationPaddingElements The number of padding elements at the end of each deviation row, in elements, with range [0, infinity)
39  * @param window Size of the window must be odd, with range [1, infinity)
40  * @return True, if succeeded
41  */
42  template <typename T, typename TIntegral>
43  static bool deviation1Channel8Bit(const T* frame, const TIntegral* integral, uint8_t* deviation, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int deviationPaddingElements, const unsigned int window);
44 
45  /**
46  * This functions determines the deviation within a 1-channel 8 bit frame.<br>
47  * The function uses an integral image for the calculation of the deviation.
48  * @param frame The frame for which the deviation will be determined, must be valid
49  * @param deviation Resulting deviation frame
50  * @param width The width of the given frame, in pixel, with range [1, infinity)
51  * @param height The height of the given frame, in pixel, with range [1, infinity)
52  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
53  * @param deviationPaddingElements The number of padding elements at the end of each deviation row, in elements, with range [0, infinity)
54  * @param window Size of the window must be odd, with range [1, min(width, height) * 2]
55  * @return True, if succeeded
56  * @tparam T The data type of the frame elements, either 'int8_t' or 'uint8_t'
57  */
58  template <typename T>
59  static bool deviation1Channel8Bit(const T* frame, uint8_t* deviation, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int deviationPaddingElements, const unsigned int window);
60 
61  /**
62  * Compute the per-channel mean, variance, and standard deviation over an image
63  *
64  * The basic outline of the computation is this (this example assumes no multi-channel and no stride but the actual implementation supports both, of course):
65  * @code
66  * T0 imagePixels[pixelCount] = { ... };
67  * T1 sum = 0;
68  * T1 squareSum = 0;
69  * for (i = 0; i < pixelCount; ++i)
70  * {
71  * sum[i] += T1(imagePixels[i]);
72  * squareSum[i] += T1(T2(imagePixel[i]) * T2(imagePixels[i]))
73  * }
74  * double mean = (double)sum / (double)pixelCount
75  * double variance = ((double)squareSum / pixelCount) - (mean * mean);
76  * double stddev = std::sqrt(variance)
77  *
78  * // Type `T0` is the type of the pixel elements, `T1` is used for the summations and type `T2` is used for multiplications.
79  * // This allows for a optimal control over how to compute and with what precision.
80  * // Example configurations are:
81  * // - `T0`=float, `T1`=float, `T2`=double
82  * // - `T0`=unsigned char, `T1`=unsigned long long, `T2`=unsigned short
83  * @endcode
84  * @note The most related OpenCV function is cv::meanStdDev()
85  * @param frame The input frame; mustn't be empty and must be a 1-channel image
86  * @param width The width of the input image, range: [1, infinity)
87  * @param height The height of the input image, range: [1, infinity)
88  * @param framePaddingElements Optional number of padding elements at the end of each source row, in elements, with range [0, infinity)
89  * @param mean Array for the resulting per-channel mean values, will be ignored if set to `nullptr` otherwise it must have `channels` elements
90  * @param variance Array for the resulting per-channel variance, will be ignored if set to `nullptr` otherwise it must have `channels` elements
91  * @param standardDeviation Array for the resulting per-channel standard deviations, will be ignored if set to `nullptr` otherwise it must have `channels` elements
92  * @tparam TElementType Type of the elements of the pixels of the input image
93  * @tparam TSummationType Type used for the internal computation of the pixel sums (should be at least as large as `TElementType`), cf. function description for details
94  * @tparam TMultiplicationType Type used to compute the square values of pixels (allows control over integer vs. floating point multiplication), cf. function description for details
95  * @tparam tChannels Number of channels of the input image, range: [1, infinity)
96  */
97  template <typename TElementType, typename TSummationType, typename TMultiplicationType, unsigned int tChannels>
98  static void imageStatistics(const TElementType* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, double* mean = nullptr, double* variance = nullptr, double* standardDeviation = nullptr);
99 };
100 
101 template <typename TElementType, typename TSummationType, typename TMultiplicationType, unsigned int tChannels>
102 void FrameVariance::imageStatistics(const TElementType* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, double* mean, double* variance, double* standardDeviation)
103 {
104  static_assert(tChannels != 0u, "Number of channels must be in the range [1, infinity)");
105  ocean_assert(frame != nullptr);
106  ocean_assert(width != 0u && height != 0u);
107 
108  const unsigned int pixelCount = width * height;
109  const unsigned int elementsCount = (width * tChannels + framePaddingElements) * height;
110 
111  const TElementType* const frameEnd = frame + elementsCount;
112 
113  TSummationType sum[tChannels];
114  TSummationType squareSum[tChannels];
115  memset(sum, 0, tChannels * sizeof(TSummationType));
116  memset(squareSum, 0, tChannels * sizeof(TSummationType));
117 
118  if (framePaddingElements == 0u)
119  {
120  for (unsigned int i = 0u; i < pixelCount; ++i)
121  {
122  for (unsigned int c = 0u; c < tChannels; ++c)
123  {
124  ocean_assert_and_suppress_unused(frame < frameEnd, frameEnd);
125 
126  sum[c] += TSummationType(*frame);
127 
128  ocean_assert(std::is_integral<TSummationType>::value == false || (squareSum[c] <= NumericT<TSummationType>::maxValue() - TSummationType(TMultiplicationType(*frame) * TMultiplicationType(*frame)) && "Integer overflow; TSummationType must be a wider type, cf. NextLargerTyper<TSummationType>::Type"));
129 
130  squareSum[c] += TSummationType(TMultiplicationType(*frame) * TMultiplicationType(*frame));
131 
132  frame++;
133  }
134  }
135  }
136  else
137  {
138  for (unsigned int y = 0u; y < height; ++y)
139  {
140  for (unsigned int x = 0u; x < width; ++x)
141  {
142  for (unsigned int c = 0u; c < tChannels; ++c)
143  {
144  ocean_assert(frame < frameEnd);
145 
146  sum[c] += TSummationType(*frame);
147 
148  ocean_assert(std::is_integral<TSummationType>::value == false || (squareSum[c] <= NumericT<TSummationType>::maxValue() - TSummationType(TMultiplicationType(*frame) * TMultiplicationType(*frame)) && "Integer overflow; TSummationType must be a wider type, cf. NextLargerTyper<TSummationType>::Type"));
149 
150  squareSum[c] += TSummationType(TMultiplicationType(*frame) * TMultiplicationType(*frame));
151 
152  frame++;
153  }
154  }
155 
156  frame += framePaddingElements;
157  }
158  }
159 
160  double localMean[tChannels];
161  double localVariance[tChannels];
162 
163  ocean_assert(pixelCount != 0u);
164  const double normalizer = 1.0 / double(pixelCount);
165 
166  for (unsigned int c = 0u; c < tChannels; ++c)
167  {
168  localMean[c] = double(sum[c]) * normalizer;
169 
170  // var = sum((I_i - mean)^2) / N, i = 1...N
171  // = (sum(I_i^2)) / N) - (2 * sum(I_i) * mean / N) + mean^2
172  // = (sum(I_i^2)) / N) - (2 * mean * mean) + mean^2
173  // = (sum(I_i^2)) / N) - mean^2
174  localVariance[c] = std::max(0.0, (double(squareSum[c]) * normalizer) - (localMean[c] * localMean[c]));
175  }
176 
177  if (mean)
178  {
179  for (unsigned int c = 0u; c < tChannels; ++c)
180  {
181  mean[c] = localMean[c];
182  }
183  }
184 
185  if (variance)
186  {
187  for (unsigned int c = 0u; c < tChannels; ++c)
188  {
189  variance[c] = localVariance[c];
190  }
191  }
192 
193  if (standardDeviation)
194  {
195  for (unsigned int c = 0u; c < tChannels; ++c)
196  {
197  ocean_assert(localVariance[c] >= 0.0);
198  standardDeviation[c] = NumericD::sqrt(localVariance[c]);
199  }
200  }
201 }
202 
203 } // namespace CV
204 
205 } // namespace Ocean
206 
207 #endif // META_OCEAN_CV_FRAME_VARIANCE_H
This class implements functions to determine the frame variance.
Definition: FrameVariance.h:27
static void imageStatistics(const TElementType *frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, double *mean=nullptr, double *variance=nullptr, double *standardDeviation=nullptr)
Compute the per-channel mean, variance, and standard deviation over an image.
Definition: FrameVariance.h:102
static bool deviation1Channel8Bit(const T *frame, uint8_t *deviation, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int deviationPaddingElements, const unsigned int window)
This functions determines the deviation within a 1-channel 8 bit frame.
static bool deviation1Channel8Bit(const T *frame, const TIntegral *integral, uint8_t *deviation, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int deviationPaddingElements, const unsigned int window)
This functions determines the frame deviation of a 1 channel 8 bit frame.
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
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15