Ocean
ZeroMeanSumSquareDifferencesBase.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_SUM_ZERO_MEAN_SQUARE_DIFFERENCES_BASE_H
9 #define META_OCEAN_CV_SUM_ZERO_MEAN_SQUARE_DIFFERENCES_BASE_H
10 
11 #include "ocean/cv/CV.h"
12 #include "ocean/cv/CVUtilities.h"
13 
14 namespace Ocean
15 {
16 
17 namespace CV
18 {
19 
20 /**
21  * This class implements several zero-mean sum square differences functions based e.g., on template parameters.
22  * @ingroup cv
23  */
25 {
26  public:
27 
28  /**
29  * Returns the zero-mean sum of square differences between two square patches.
30  * @param image0 The first image in which the first patch is located, must be valid
31  * @param image1 The second image in which the second patch is located, must be valid
32  * @param width0 Width of the first frame in pixels, with range [tPatchSize, infinity)
33  * @param width1 Width of the second frame in pixels, with range [tPatchSize, infinity)
34  * @param centerX0 Horizontal center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, width0 - tPatchSize / 2 - 1]
35  * @param centerY0 Vertical center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, height0 - tPatchSize / 2 - 1]
36  * @param centerX1 Horizontal center position of the (tPatchSize x tPatchSize) block in the second frame, with range [tPatchSize / 2, width1 - tPatchSize / 2 - 1]
37  * @param centerY1 Vertical center position of the (tPatchSize x tPatchSize) block in the second frame, with range [tPatchSize / 2, height1 - tPatchSize / 2 - 1]
38  * @param image0PaddingElements The number of padding elements at the end of each row of the first image, in elements, with range [0, infinity)
39  * @param image1PaddingElements The number of padding elements at the end of each row of the second image, in elements, with range [0, infinity
40  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements
41  * @tparam tChannels Specifies the number of channels for the given frames, with range [1, infinity)
42  * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
43  */
44  template <unsigned int tChannels, unsigned int tPatchSize>
45  static OCEAN_FORCE_INLINE uint32_t patch8BitPerChannelTemplate(const uint8_t* const image0, const uint8_t* const image1, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements);
46 
47  /**
48  * Returns the zero-mean sum of square differences between two square patches.
49  * @param patch0 The top-left corner of the first image patch, must be valid
50  * @param patch1 The top-left corner of the second image patch, must be valid
51  * @param patch0StrideElements The number of elements between two row starts in the first patch, in elements, with range [tPatchSize * tChannels, infinity)
52  * @param patch1StrideElements The number of elements between two row starts in the second patch, in elements, with range [tPatchSize * tChannels, infinity)
53  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements
54  * @tparam tChannels Specifies the number of channels for the given frames, with range [1, infinity)
55  * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
56  */
57  template <unsigned int tChannels, unsigned int tPatchSize>
58  static uint32_t patch8BitPerChannelTemplate(const uint8_t* patch0, const uint8_t* patch1, const unsigned int patch0StrideElements, const unsigned int patch1StrideElements);
59 
60  /**
61  * Returns the zero-mean sum of square differences between a square image patch and a buffer.
62  * @param image0 The image in which the image patch is located, must be valid
63  * @param width0 Width of the first frame in pixels, with range [tPatchSize, infinity)
64  * @param centerX0 Horizontal center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, width0 - tPatchSize / 2 - 1]
65  * @param centerY0 Vertical center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, height0 - tPatchSize / 2 - 1]
66  * @param image0PaddingElements The number of padding elements at the end of each row of the first image, in elements, with range [0, infinity)
67  * @param buffer1 The memory buffer with `tChannels * tPatchSize * tPatchSize` elements, must be valid
68  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements, with range [0, infinity)
69  * @tparam tChannels The number of channels for the given frames, with range [1, infinity)
70  * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
71  */
72  template <unsigned int tChannels, unsigned int tPatchSize>
73  static OCEAN_FORCE_INLINE uint32_t patchBuffer8BitPerChannelTemplate(const uint8_t* image0, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t* buffer1);
74 
75  /**
76  * Returns the zero-mean sum of square differences between a square image patch and a buffer.
77  * @param patch0 The top left start position of the image patch, must be valid
78  * @param buffer1 The memory buffer, must be valid
79  * @param patch0StrideElements The number of elements between two rows for the image patch, in elements, with range [tChannels, tPatchSize, infinity)
80  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements, with range [0, infinity)
81  * @tparam tChannels The number of channels for the given frames, with range [1, infinity)
82  * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
83  */
84  template <unsigned int tChannels, unsigned int tPatchSize>
85  static uint32_t patchBuffer8BitPerChannelTemplate(const uint8_t* patch0, const uint8_t* buffer1, const unsigned int patch0StrideElements);
86 
87  /**
88  * Returns the zero-mean sum of square differences between two memory buffers.
89  * @param buffer0 The first memory buffer, must be valid
90  * @param buffer1 The second memory buffer, must be valid
91  * @return The resulting sum of square differences
92  * @tparam tChannels Specifies the number of channels for the given frames
93  * @tparam tPixels The number of pixels the buffer holds, in pixels, with range [1, infinity)
94  */
95  template <unsigned int tChannels, unsigned int tPixels>
96  static inline uint32_t buffer8BitPerChannelTemplate(const uint8_t* buffer0, const uint8_t* buffer1);
97 
98  /**
99  * Returns the zero-mean sum of square differences between two square patches.
100  * @param image0 The first image in which the first patch is located, must be valid
101  * @param image1 The second image in which the second patch is located, must be valid
102  * @param width0 Width of the first frame in pixels, with range [patchSize, infinity)
103  * @param width1 Width of the second frame in pixels, with range [patchSize, infinity)
104  * @param patchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
105  * @param centerX0 Horizontal center position of the (patchSize x patchSize) block in the first frame, with range [patchSize / 2, width0 - patchSize / 2 - 1]
106  * @param centerY0 Vertical center position of the (patchSize x patchSize) block in the first frame, with range [patchSize / 2, height0 - patchSize / 2 - 1]
107  * @param centerX1 Horizontal center position of the (patchSize x patchSize) block in the second frame, with range [patchSize / 2, width1 - patchSize / 2 - 1]
108  * @param centerY1 Vertical center position of the (patchSize x patchSize) block in the second frame, with range [patchSize / 2, height1 - patchSize / 2 - 1]
109  * @param image0PaddingElements The number of padding elements at the end of each row of the first image, in elements, with range [0, infinity)
110  * @param image1PaddingElements The number of padding elements at the end of each row of the second image, in elements, with range [0, infinity
111  * @return The resulting sum of square differences for `patchSize * patchSize * channels` elements
112  * @tparam tChannels The number of frame channels, with range [1, infinity)
113  */
114  template <unsigned int tChannels>
115  static OCEAN_FORCE_INLINE uint32_t patch8BitPerChannel(const uint8_t* const image0, const uint8_t* const image1, const unsigned int patchSize, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements);
116 
117  /**
118  * Returns the zero-mean sum of square differences between two square patches.
119  * @param patch0 The top-left corner of the first image patch, must be valid
120  * @param patch1 The top-left corner of the second image patch, must be valid
121  * @param patchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
122  * @param patch0StrideElements The number of elements between two row starts in the first patch, in elements, with range [patchSize * channels, infinity)
123  * @param patch1StrideElements The number of elements between two row starts in the second patch, in elements, with range [patchSize * channels, infinity)
124  * @return The resulting sum of square differences for `patchSize * patchSize * channels` elements
125  * @tparam tChannels The number of frame channels, with range [1, infinity)
126  */
127  template <unsigned int tChannels>
128  static uint32_t patch8BitPerChannel(const uint8_t* patch0, const uint8_t* patch1, const unsigned int patchSize, const unsigned int patch0StrideElements, const unsigned int patch1StrideElements);
129 
130  /**
131  * Returns the sum of square differences between a square image patch and a buffer.
132  * @param image0 The image in which the image patch is located, must be valid
133  * @param patchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
134  * @param width0 Width of the first frame in pixels, with range [tPatchSize, infinity)
135  * @param centerX0 Horizontal center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, width0 - tPatchSize / 2 - 1]
136  * @param centerY0 Vertical center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize / 2, height0 - tPatchSize / 2 - 1]
137  * @param image0PaddingElements The number of padding elements at the end of each row of the first image, in elements, with range [0, infinity)
138  * @param buffer1 The memory buffer with `tChannels * tPatchSize * tPatchSize` elements, must be valid
139  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements, with range [0, infinity)
140  * @tparam tChannels The number of frame channels, with range [1, infinity)
141  */
142  template <unsigned int tChannels>
143  static OCEAN_FORCE_INLINE uint32_t patchBuffer8BitPerChannel(const uint8_t* image0, unsigned int patchSize, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t* buffer1);
144 
145  /**
146  * Returns the sum of square differences between a square image patch and a buffer.
147  * @param patch0 The top left start position of the image patch, must be valid
148  * @param buffer1 The memory buffer, must be valid
149  * @param patchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
150  * @param patch0StrideElements The number of elements between two rows for the image patch, in elements, with range [tChannels, tPatchSize, infinity)
151  * @return The resulting sum of square differences for tPatchSize * tPatchSize * tChannels elements, with range [0, infinity)
152  * @tparam tChannels The number of frame channels, with range [1, infinity)
153  */
154  template <unsigned int tChannels>
155  static uint32_t patchBuffer8BitPerChannel(const uint8_t* patch0, const uint8_t* buffer1, unsigned int patchSize, const unsigned int patch0StrideElements);
156 
157  /**
158  * Returns the zero-mean sum of square differences between two memory buffers.
159  * @param buffer0 The first memory buffer, must be valid
160  * @param buffer1 The second memory buffer, must be valid
161  * @param pixels The number of pixels the buffer holds, in pixels, with range [1, infinity)
162  * @return The resulting sum of square differences
163  * @tparam tChannels Specifies the number of channels for the given frames
164  */
165  template <unsigned int tChannels>
166  static inline unsigned int buffer8BitPerChannel(const uint8_t* buffer0, const uint8_t* buffer1, const unsigned int pixels);
167 
168  /**
169  * Returns the zero-mean sum of square differences between two patches within an image, patch pixels outside the image will be mirrored back into the image.
170  * @param image0 The image in which the first patch is located, must be valid
171  * @param image1 The image in which the second patch is located, must be valid
172  * @param patchSize The size of the square patch (the edge length) in pixel, with range [1, infinity), must be odd
173  * @param width0 The width of the first image, in pixels, with range [tPatchSize, infinity)
174  * @param height0 The height of the first image, in pixels, with range [tPatchSize, infinity)
175  * @param width1 The width of the second image, in pixels, with range [tPatchSize, infinity)
176  * @param height1 The height of the second image, in pixels, with range [tPatchSize, infinity)
177  * @param centerX0 Horizontal center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize/2, width - tPatchSize/2 - 1]
178  * @param centerY0 Vertical center position of the (tPatchSize x tPatchSize) block in the first frame, with range [tPatchSize/2, height - tPatchSize/2 - 1]
179  * @param centerX1 Horizontal center position of the (tPatchSize x tPatchSize) block in the second frame, with range [tPatchSize/2, width - tPatchSize/2 - 1]
180  * @param centerY1 Vertical center position of the (tPatchSize x tPatchSize) block in the second frame, with range [tPatchSize/2, height - tPatchSize/2 - 1]
181  * @param image0PaddingElements The number of padding elements at the end of each row of the first image, in elements, with range [0, infinity)
182  * @param image1PaddingElements The number of padding elements at the end of each row of the second image, in elements, with range [0, infinity)
183  * @return The resulting sum of square differences, with range [0, infinity)
184  * @tparam tChannels Specifies the number of channels for the given frames
185  */
186  template <unsigned int tChannels>
187  static uint32_t patchMirroredBorder8BitPerChannel(const uint8_t* image0, const uint8_t* image1, const unsigned int patchSize, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements);
188 };
189 
190 template <unsigned int tChannels, unsigned int tPatchSize>
191 inline uint32_t ZeroMeanSumSquareDifferencesBase::patch8BitPerChannelTemplate(const uint8_t* const image0, const uint8_t* const image1, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
192 {
193  static_assert(tChannels >= 1u, "Invalid number of frame channels!");
194  static_assert(tPatchSize % 2u == 1u, "Invalid patch size!");
195 
196  ocean_assert(image0 != nullptr && image1 != nullptr);
197 
198  constexpr unsigned int tPatchSize_2 = tPatchSize / 2u;
199 
200  ocean_assert(centerX0 >= tPatchSize_2 && centerY0 >= tPatchSize_2 && centerX0 < width0 - tPatchSize_2);
201  ocean_assert(centerX1 >= tPatchSize_2 && centerY1 >= tPatchSize_2 && centerX1 < width1 - tPatchSize_2);
202 
203  ocean_assert(width0 >= tPatchSize);
204  ocean_assert(width1 >= tPatchSize);
205 
206  const unsigned int image0StrideElements = width0 * tChannels + image0PaddingElements;
207  const unsigned int image1StrideElements = width1 * tChannels + image1PaddingElements;
208 
209  return patch8BitPerChannelTemplate<tChannels, tPatchSize>(image0 + (centerY0 - tPatchSize_2) * image0StrideElements + (centerX0 - tPatchSize_2) * tChannels, image1 + (centerY1 - tPatchSize_2) * image1StrideElements + (centerX1 - tPatchSize_2) * tChannels, image0StrideElements, image1StrideElements);
210 }
211 
212 template <unsigned int tChannels, unsigned int tPatchSize>
213 uint32_t ZeroMeanSumSquareDifferencesBase::patch8BitPerChannelTemplate(const uint8_t* patch0, const uint8_t* patch1, const unsigned int patch0StrideElements, const unsigned int patch1StrideElements)
214 {
215  static_assert(tPatchSize % 2u == 1u, "Invalid image patch size, need an odd value!");
216  static_assert(tChannels > 0u, "Invalid number of frame channels!");
217 
218  ocean_assert(patch0 != nullptr && patch1 != nullptr);
219 
220  ocean_assert(patch0StrideElements >= tPatchSize * tChannels);
221  ocean_assert(patch1StrideElements >= tPatchSize * tChannels);
222 
223  uint32_t sumMean0[tChannels] = {0u};
224  uint32_t sumMean1[tChannels] = {0u};
225 
226  for (unsigned int y = 0u; y < tPatchSize; ++y)
227  {
228  for (unsigned int x = 0u; x < tPatchSize; ++x)
229  {
230  for (unsigned int c = 0u; c < tChannels; c++)
231  {
232  sumMean0[c] += patch0[c];
233  sumMean1[c] += patch1[c];
234  }
235 
236  patch0 += tChannels;
237  patch1 += tChannels;
238  }
239 
240  patch0 += patch0StrideElements - tPatchSize * tChannels;
241  patch1 += patch1StrideElements - tPatchSize * tChannels;
242  }
243 
244  uint8_t mean0[tChannels];
245  uint8_t mean1[tChannels];
246 
247  for (unsigned int n = 0u; n < tChannels; ++n)
248  {
249  mean0[n] = uint8_t((sumMean0[n] + (tPatchSize * tPatchSize / 2u)) / (tPatchSize * tPatchSize));
250  mean1[n] = uint8_t((sumMean1[n] + (tPatchSize * tPatchSize / 2u)) / (tPatchSize * tPatchSize));
251  }
252 
253  patch0 -= patch0StrideElements * tPatchSize;
254  patch1 -= patch1StrideElements * tPatchSize;
255 
256  uint32_t result = 0;
257  int16_t value = 0;
258 
259  for (unsigned int y = 0u; y < tPatchSize; ++y)
260  {
261  for (unsigned int x = 0u; x < tPatchSize; ++x)
262  {
263  for (unsigned int c = 0u; c < tChannels; c++)
264  {
265  value = int16_t(patch0[c] - mean0[c]) - int16_t(patch1[c] - mean1[c]);
266  result += value * value;
267  }
268 
269  patch0 += tChannels;
270  patch1 += tChannels;
271  }
272 
273  patch0 += patch0StrideElements - tPatchSize * tChannels;
274  patch1 += patch1StrideElements - tPatchSize * tChannels;
275  }
276 
277  return result;
278 }
279 
280 template <unsigned int tChannels, unsigned int tPatchSize>
281 OCEAN_FORCE_INLINE uint32_t ZeroMeanSumSquareDifferencesBase::patchBuffer8BitPerChannelTemplate(const uint8_t* image0, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t* buffer1)
282 {
283  static_assert(tChannels >= 1u, "Invalid number of frame channels!");
284  static_assert(tPatchSize % 2u == 1u, "Invalid patch size!");
285 
286  ocean_assert(image0 != nullptr && buffer1 != nullptr);
287 
288  constexpr unsigned int tPatchSize_2 = tPatchSize / 2u;
289 
290  ocean_assert(centerX0 >= tPatchSize_2 && centerY0 >= tPatchSize_2 && centerX0 < width0 - tPatchSize_2);
291 
292  ocean_assert(width0 >= tPatchSize);
293 
294  const unsigned int image0StrideElements = width0 * tChannels + image0PaddingElements;
295 
296  return patchBuffer8BitPerChannelTemplate<tChannels, tPatchSize>(image0 + (centerY0 - tPatchSize_2) * image0StrideElements + (centerX0 - tPatchSize_2) * tChannels, buffer1, image0StrideElements);
297 }
298 
299 template <unsigned int tChannels, unsigned int tPatchSize>
300 uint32_t ZeroMeanSumSquareDifferencesBase::patchBuffer8BitPerChannelTemplate(const uint8_t* patch0, const uint8_t* buffer1, const unsigned int patch0StrideElements)
301 {
302  return patch8BitPerChannelTemplate<tChannels, tPatchSize>(patch0, buffer1, patch0StrideElements, tChannels * tPatchSize);
303 }
304 
305 template <unsigned int tChannels, unsigned int tPixels>
306 inline uint32_t ZeroMeanSumSquareDifferencesBase::buffer8BitPerChannelTemplate(const uint8_t* buffer0, const uint8_t* buffer1)
307 {
308  static_assert(tChannels != 0u, "Invalid number of frame channels!");
309  static_assert(tPixels != 0u, "Invalid image buffer size!");
310 
311  ocean_assert(buffer0 != nullptr && buffer1 != nullptr);
312 
313  uint32_t sumMean0[tChannels] = {0u};
314  uint32_t sumMean1[tChannels] = {0u};
315 
316  for (unsigned int n = 0u; n < tPixels; ++n)
317  {
318  for (unsigned int c = 0u; c < tChannels; ++c)
319  {
320  sumMean0[c] += buffer0[c];
321  sumMean1[c] += buffer1[c];
322  }
323 
324  buffer0 += tChannels;
325  buffer1 += tChannels;
326  }
327 
328  uint8_t mean0[tChannels];
329  uint8_t mean1[tChannels];
330 
331  for (unsigned int c = 0u; c < tChannels; ++c)
332  {
333  mean0[c] = uint8_t((sumMean0[c] + tPixels / 2u) / tPixels);
334  mean1[c] = uint8_t((sumMean1[c] + tPixels / 2u) / tPixels);
335  }
336 
337  buffer0 -= tChannels * tPixels;
338  buffer1 -= tChannels * tPixels;
339 
340  int16_t value;
341  uint32_t ssd = 0u;
342 
343  for (unsigned int n = 0u; n < tPixels; ++n)
344  {
345  for (unsigned int c = 0u; c < tChannels; ++c)
346  {
347  value = int16_t(buffer0[c] - mean0[c]) - int16_t(buffer1[c] - mean1[c]);
348  ssd += uint32_t(value * value);
349  }
350 
351  buffer0 += tChannels;
352  buffer1 += tChannels;
353  }
354 
355  return ssd;
356 }
357 
358 template <unsigned int tChannels>
359 OCEAN_FORCE_INLINE uint32_t ZeroMeanSumSquareDifferencesBase::patch8BitPerChannel(const uint8_t* const image0, const uint8_t* const image1, const unsigned int patchSize, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
360 {
361  static_assert(tChannels >= 1u, "Invalid channel number!");
362 
363  ocean_assert(image0 != nullptr && image1 != nullptr);
364  ocean_assert(patchSize % 2u == 1u);
365 
366  const unsigned int patchSize_2 = patchSize / 2u;
367 
368  ocean_assert(centerX0 >= patchSize_2 && centerY0 >= patchSize_2 && centerX0 < width0 - patchSize_2);
369  ocean_assert(centerX1 >= patchSize_2 && centerY1 >= patchSize_2 && centerX1 < width1 - patchSize_2);
370 
371  ocean_assert(width0 >= patchSize_2);
372  ocean_assert(width1 >= patchSize_2);
373 
374  const unsigned int image0StrideElements = width0 * tChannels + image0PaddingElements;
375  const unsigned int image1StrideElements = width1 * tChannels + image1PaddingElements;
376 
377  return patch8BitPerChannel<tChannels>(image0 + (centerY0 - patchSize_2) * image0StrideElements + (centerX0 - patchSize_2) * tChannels, image1 + (centerY1 - patchSize_2) * image1StrideElements + (centerX1 - patchSize_2) * tChannels, patchSize, image0StrideElements, image1StrideElements);
378 }
379 
380 template <unsigned int tChannels>
381 uint32_t ZeroMeanSumSquareDifferencesBase::patch8BitPerChannel(const uint8_t* patch0, const uint8_t* patch1, const unsigned int patchSize, const unsigned int patch0StrideElements, const unsigned int patch1StrideElements)
382 {
383  static_assert(tChannels >= 1u, "Invalid channel number!");
384 
385  ocean_assert(patch0 != nullptr && patch1 != nullptr);
386  ocean_assert(patchSize % 2u == 1u);
387 
388  ocean_assert(patch0StrideElements >= patchSize * tChannels);
389  ocean_assert(patch1StrideElements >= patchSize * tChannels);
390 
391  uint32_t sumMean0[tChannels] = {0u};
392  uint32_t sumMean1[tChannels] = {0u};
393 
394  for (unsigned int y = 0u; y < patchSize; ++y)
395  {
396  for (unsigned int x = 0u; x < patchSize; ++x)
397  {
398  for (unsigned int c = 0u; c < tChannels; c++)
399  {
400  sumMean0[c] += patch0[c];
401  sumMean1[c] += patch1[c];
402  }
403 
404  patch0 += tChannels;
405  patch1 += tChannels;
406  }
407 
408  patch0 += patch0StrideElements - patchSize * tChannels;
409  patch1 += patch1StrideElements - patchSize * tChannels;
410  }
411 
412  uint8_t mean0[tChannels];
413  uint8_t mean1[tChannels];
414 
415  for (unsigned int n = 0u; n < tChannels; ++n)
416  {
417  mean0[n] = uint8_t((sumMean0[n] + (patchSize * patchSize / 2u)) / (patchSize * patchSize));
418  mean1[n] = uint8_t((sumMean1[n] + (patchSize * patchSize / 2u)) / (patchSize * patchSize));
419  }
420 
421  patch0 -= patch0StrideElements * patchSize;
422  patch1 -= patch1StrideElements * patchSize;
423 
424  uint32_t result = 0;
425  int16_t value = 0;
426 
427  for (unsigned int y = 0u; y < patchSize; ++y)
428  {
429  for (unsigned int x = 0u; x < patchSize; ++x)
430  {
431  for (unsigned int c = 0u; c < tChannels; c++)
432  {
433  value = int16_t(patch0[c] - mean0[c]) - int16_t(patch1[c] - mean1[c]);
434  result += value * value;
435  }
436 
437  patch0 += tChannels;
438  patch1 += tChannels;
439  }
440 
441  patch0 += patch0StrideElements - patchSize * tChannels;
442  patch1 += patch1StrideElements - patchSize * tChannels;
443  }
444 
445  return result;
446 }
447 
448 template <unsigned int tChannels>
449 inline unsigned int ZeroMeanSumSquareDifferencesBase::buffer8BitPerChannel(const uint8_t* buffer0, const uint8_t* buffer1, const unsigned int pixels)
450 {
451  static_assert(tChannels != 0u, "Invalid number of frame channels!");
452 
453  ocean_assert(buffer0 != nullptr && buffer1 != nullptr);
454  ocean_assert(pixels >= 1u);
455 
456  uint32_t sumMean0[tChannels] = {0u};
457  uint32_t sumMean1[tChannels] = {0u};
458 
459  for (unsigned int n = 0u; n < pixels; ++n)
460  {
461  for (unsigned int c = 0u; c < tChannels; ++c)
462  {
463  sumMean0[c] += buffer0[c];
464  sumMean1[c] += buffer1[c];
465  }
466 
467  buffer0 += tChannels;
468  buffer1 += tChannels;
469  }
470 
471  uint8_t mean0[tChannels];
472  uint8_t mean1[tChannels];
473 
474  for (unsigned int c = 0u; c < tChannels; ++c)
475  {
476  mean0[c] = uint8_t((sumMean0[c] + pixels / 2u) / pixels);
477  mean1[c] = uint8_t((sumMean1[c] + pixels / 2u) / pixels);
478  }
479 
480  buffer0 -= tChannels * pixels;
481  buffer1 -= tChannels * pixels;
482 
483  int16_t value;
484  uint32_t ssd = 0u;
485 
486  for (unsigned int n = 0u; n < pixels; ++n)
487  {
488  for (unsigned int c = 0u; c < tChannels; ++c)
489  {
490  value = int16_t(buffer0[c] - mean0[c]) - int16_t(buffer1[c] - mean1[c]);
491  ssd += uint32_t(value * value);
492  }
493 
494  buffer0 += tChannels;
495  buffer1 += tChannels;
496  }
497 
498  return ssd;
499 }
500 
501 template <unsigned int tChannels>
502 OCEAN_FORCE_INLINE uint32_t ZeroMeanSumSquareDifferencesBase::patchBuffer8BitPerChannel(const uint8_t* image0, unsigned int patchSize, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t* buffer1)
503 {
504  static_assert(tChannels >= 1u, "Invalid channel number!");
505 
506  ocean_assert(image0 != nullptr && buffer1 != nullptr);
507 
508  ocean_assert(patchSize % 2u == 1u);
509 
510  const unsigned int patchSize_2 = patchSize / 2u;
511 
512  ocean_assert(centerX0 >= patchSize_2 && centerY0 >= patchSize_2 && centerX0 < width0 - patchSize_2);
513 
514  ocean_assert(width0 >= patchSize);
515 
516  const unsigned int image0StrideElements = width0 * tChannels + image0PaddingElements;
517 
518  return patchBuffer8BitPerChannel<tChannels>(image0 + (centerY0 - patchSize_2) * image0StrideElements + (centerX0 - patchSize_2) * tChannels, buffer1, patchSize, image0StrideElements);
519 }
520 
521 template <unsigned int tChannels>
522 inline uint32_t ZeroMeanSumSquareDifferencesBase::patchBuffer8BitPerChannel(const uint8_t* patch0, const uint8_t* buffer1, unsigned int patchSize, const unsigned int patch0StrideElements)
523 {
524  return patch8BitPerChannel<tChannels>(patch0, buffer1, patchSize, patch0StrideElements, tChannels * patchSize);
525 }
526 
527 template <unsigned int tChannels>
528 uint32_t ZeroMeanSumSquareDifferencesBase::patchMirroredBorder8BitPerChannel(const uint8_t* image0, const uint8_t* image1, const unsigned int patchSize, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
529 {
530  static_assert(tChannels != 0u, "Invalid number of data channels!");
531 
532  ocean_assert(image0 != nullptr && image1 != nullptr);
533  ocean_assert(patchSize % 2u == 1u);
534 
535  const unsigned int patchSize_2 = patchSize / 2u;
536 
537  ocean_assert(width0 >= patchSize_2);
538  ocean_assert(width1 >= patchSize_2);
539 
540  ocean_assert(centerX0 < width0 && centerY0 < height0);
541  ocean_assert(centerX1 < width1 && centerY1 < height1);
542 
543  const unsigned int image0StrideElements = width0 * tChannels + image0PaddingElements;
544  const unsigned int image1StrideElements = width1 * tChannels + image1PaddingElements;
545 
546  const int left0 = int(centerX0 - patchSize_2);
547  const int top0 = int(centerY0 - patchSize_2);
548 
549  const int left1 = int(centerX1 - patchSize_2);
550  const int top1 = int(centerY1 - patchSize_2);
551 
552  const uint8_t* i0 = image0 + top0 * int(image0StrideElements) + left0 * int(tChannels);
553  const uint8_t* i1 = image1 + top1 * int(image1StrideElements) + left1 * int(tChannels);
554 
555  unsigned int mean0[tChannels] = {0u};
556  unsigned int mean1[tChannels] = {0u};
557 
558  unsigned int y0 = centerY0 - patchSize_2;
559  unsigned int y1 = centerY1 - patchSize_2;
560 
561  const uint8_t* const i0End = i0 + patchSize * image0StrideElements;
562 
563  while (i0 != i0End)
564  {
565  ocean_assert(i0 < i0End);
566 
567  const uint8_t* c0 = i0 + CVUtilities::mirrorOffset(y0, height0) * int(image0StrideElements);
568  const uint8_t* c1 = i1 + CVUtilities::mirrorOffset(y1, height1) * int(image1StrideElements);
569 
570  unsigned int x0 = centerX0 - patchSize_2;
571  unsigned int x1 = centerX1 - patchSize_2;
572 
573  const uint8_t* const c0RowEnd = c0 + patchSize * tChannels;
574 
575  while (c0 != c0RowEnd)
576  {
577  ocean_assert(c0 < c0RowEnd);
578 
579  if (x0 < width0 && x1 < width1)
580  {
581  // both pixels lie inside the frame
582 
583  for (unsigned int n = 0u; n < tChannels; ++n)
584  {
585  mean0[n] += c0[n];
586  mean1[n] += c1[n];
587  }
588 
589  c0 += tChannels;
590  c1 += tChannels;
591  }
592  else if (x0 < width0)
593  {
594  // x0 lies inside the frame
595 
596  ocean_assert(x1 >= width1);
597 
598  const uint8_t* m1 = c1 + CVUtilities::mirrorOffset(x1, width1) * int(tChannels);
599 
600  for (unsigned int n = 0u; n < tChannels; ++n)
601  {
602  mean0[n] += c0[n];
603  mean1[n] += m1[n];
604  }
605 
606  c0 += tChannels;
607  c1 += tChannels;
608  }
609  else if (x1 < width1)
610  {
611  // x1 lies inside the frame
612 
613  ocean_assert(x0 >= width0);
614 
615  const uint8_t* m0 = c0 + CVUtilities::mirrorOffset(x0, width0) * int(tChannels);
616 
617  for (unsigned int n = 0u; n < tChannels; ++n)
618  {
619  mean0[n] += m0[n];
620  mean1[n] += c1[n];
621  }
622 
623  c0 += tChannels;
624  c1 += tChannels;
625  }
626  else
627  {
628  // neither x0 nor x1 lie inside the frame
629 
630  ocean_assert(x0 >= width0 && x1 >= width1);
631 
632  const uint8_t* m1 = c1 + CVUtilities::mirrorOffset(x1, width1) * int(tChannels);
633  const uint8_t* m0 = c0 + CVUtilities::mirrorOffset(x0, width0) * int(tChannels);
634 
635  for (unsigned int n = 0u; n < tChannels; ++n)
636  {
637  mean0[n] += m0[n];
638  mean1[n] += m1[n];
639  }
640 
641  c0 += tChannels;
642  c1 += tChannels;
643  }
644 
645  ++x0;
646  ++x1;
647  }
648 
649  i0 += image0StrideElements;
650  i1 += image1StrideElements;
651 
652  ++y0;
653  ++y1;
654  }
655 
656  for (unsigned int n = 0u; n < tChannels; ++n)
657  {
658  mean0[n] = (mean0[n] + (patchSize * patchSize / 2u)) / (patchSize * patchSize);
659  mean1[n] = (mean1[n] + (patchSize * patchSize / 2u)) / (patchSize * patchSize);
660  }
661 
662  y0 = centerY0 - patchSize_2;
663  y1 = centerY1 - patchSize_2;
664 
665  i0 = image0 + top0 * int(image0StrideElements) + left0 * int(tChannels);
666  i1 = image1 + top1 * int(image1StrideElements) + left1 * int(tChannels);
667 
668  int32_t value;
669  uint32_t zmssd = 0u;
670 
671  while (i0 != i0End)
672  {
673  ocean_assert(i0 < i0End);
674 
675  const uint8_t* c0 = i0 + CVUtilities::mirrorOffset(y0, height0) * int(image0StrideElements);
676  const uint8_t* c1 = i1 + CVUtilities::mirrorOffset(y1, height1) * int(image1StrideElements);
677 
678  unsigned int x0 = centerX0 - patchSize_2;
679  unsigned int x1 = centerX1 - patchSize_2;
680 
681  const uint8_t* const c0RowEnd = c0 + patchSize * tChannels;
682 
683  while (c0 != c0RowEnd)
684  {
685  ocean_assert(c0 < c0RowEnd);
686 
687  if (x0 < width0 && x1 < width1)
688  {
689  // both pixels lie inside the frame
690 
691  for (unsigned int n = 0u; n < tChannels; ++n)
692  {
693  value = (c0[n] - mean0[n]) - (c1[n] - mean1[n]);
694  zmssd += value * value;
695  }
696 
697  c0 += tChannels;
698  c1 += tChannels;
699  }
700  else if (x0 < width0)
701  {
702  // x0 lies inside the frame
703 
704  ocean_assert(x1 >= width1);
705 
706  const uint8_t* m1 = c1 + CVUtilities::mirrorOffset(x1, width1) * int(tChannels);
707 
708  for (unsigned int n = 0u; n < tChannels; ++n)
709  {
710  value = (c0[n] - mean0[n]) - (m1[n] - mean1[n]);
711  zmssd += value * value;
712  }
713 
714  c0 += tChannels;
715  c1 += tChannels;
716  }
717  else if (x1 < width1)
718  {
719  // x1 lies inside the frame
720 
721  ocean_assert(x0 >= width0);
722 
723  const uint8_t* m0 = c0 + CVUtilities::mirrorOffset(x0, width0) * int(tChannels);
724 
725  for (unsigned int n = 0u; n < tChannels; ++n)
726  {
727  value = (m0[n] - mean0[n]) - (c1[n] - mean1[n]);
728  zmssd += value * value;
729  }
730 
731  c0 += tChannels;
732  c1 += tChannels;
733  }
734  else
735  {
736  // neither x0 nor x1 lie inside the frame
737 
738  ocean_assert(x0 >= width0 && x1 >= width1);
739 
740  const uint8_t* m1 = c1 + CVUtilities::mirrorOffset(x1, width1) * int(tChannels);
741  const uint8_t* m0 = c0 + CVUtilities::mirrorOffset(x0, width0) * int(tChannels);
742 
743  for (unsigned int n = 0u; n < tChannels; ++n)
744  {
745  value = (m0[n] - mean0[n]) - (m1[n] - mean1[n]);
746  zmssd += value * value;
747  }
748 
749  c0 += tChannels;
750  c1 += tChannels;
751  }
752 
753  ++x0;
754  ++x1;
755  }
756 
757  i0 += image0StrideElements;
758  i1 += image1StrideElements;
759 
760  ++y0;
761  ++y1;
762  }
763 
764  return zmssd;
765 }
766 
767 }
768 
769 }
770 
771 #endif // META_OCEAN_CV_SUM_ZERO_MEAN_SQUARE_DIFFERENCES_BASE_H
static int mirrorOffset(const unsigned int index, const unsigned int elements)
Deprecated.
Definition: CVUtilities.h:446
This class implements several zero-mean sum square differences functions based e.g....
Definition: ZeroMeanSumSquareDifferencesBase.h:25
static OCEAN_FORCE_INLINE uint32_t patchBuffer8BitPerChannel(const uint8_t *image0, unsigned int patchSize, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t *buffer1)
Returns the sum of square differences between a square image patch and a buffer.
Definition: ZeroMeanSumSquareDifferencesBase.h:502
static uint32_t patchMirroredBorder8BitPerChannel(const uint8_t *image0, const uint8_t *image1, const unsigned int patchSize, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
Returns the zero-mean sum of square differences between two patches within an image,...
Definition: ZeroMeanSumSquareDifferencesBase.h:528
static uint32_t buffer8BitPerChannelTemplate(const uint8_t *buffer0, const uint8_t *buffer1)
Returns the zero-mean sum of square differences between two memory buffers.
Definition: ZeroMeanSumSquareDifferencesBase.h:306
static OCEAN_FORCE_INLINE uint32_t patch8BitPerChannel(const uint8_t *const image0, const uint8_t *const image1, const unsigned int patchSize, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
Returns the zero-mean sum of square differences between two square patches.
Definition: ZeroMeanSumSquareDifferencesBase.h:359
static OCEAN_FORCE_INLINE uint32_t patchBuffer8BitPerChannelTemplate(const uint8_t *image0, const unsigned int width0, const unsigned int centerX0, const unsigned int centerY0, const unsigned int image0PaddingElements, const uint8_t *buffer1)
Returns the zero-mean sum of square differences between a square image patch and a buffer.
Definition: ZeroMeanSumSquareDifferencesBase.h:281
static OCEAN_FORCE_INLINE uint32_t patch8BitPerChannelTemplate(const uint8_t *const image0, const uint8_t *const image1, const unsigned int width0, const unsigned int width1, const unsigned int centerX0, const unsigned int centerY0, const unsigned int centerX1, const unsigned int centerY1, const unsigned int image0PaddingElements, const unsigned int image1PaddingElements)
Returns the zero-mean sum of square differences between two square patches.
static unsigned int buffer8BitPerChannel(const uint8_t *buffer0, const uint8_t *buffer1, const unsigned int pixels)
Returns the zero-mean sum of square differences between two memory buffers.
Definition: ZeroMeanSumSquareDifferencesBase.h:449
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15