Ocean
Histogram.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_HISTOGRAM_H
9 #define META_OCEAN_CV_HISTOGRAM_H
10 
11 #include "ocean/cv/CV.h"
12 
13 #include "ocean/base/Frame.h"
14 #include "ocean/base/Worker.h"
15 
16 #include "ocean/math/Lookup2.h"
17 #include "ocean/math/Math.h"
18 
19 #include <array>
20 
21 namespace Ocean
22 {
23 
24 namespace CV
25 {
26 
27 /**
28  * This class implements an image histogram.
29  * @ingroup cv
30  */
31 class OCEAN_CV_EXPORT Histogram
32 {
33  public:
34 
35  /**
36  * This class implements the base class for all histogram objects holding 8 bit per data channel.
37  * @tparam tChannels Defines the number of channels of the histogram
38  */
39  template <unsigned int tChannels>
41  {
42  public:
43 
44  /**
45  * Returns the bin value of a specific channel and bin.
46  * This function uses a template parameter to define the channel and the bin.<br>
47  * @tparam tChannel Data channel, with range [0, tChannels)
48  * @tparam tIndex Index of the bin
49  * @return Bin value
50  */
51  template <unsigned int tChannel, uint8_t tIndex>
52  inline unsigned int bin() const;
53 
54  /**
55  * Returns the bin value of a specific channel and bin.
56  * This function uses a template parameter to define the channel.<br>
57  * @param index The index of the bin, with range [0, 255]
58  * @tparam tChannel Data channel, with range [0, tChannels - 1]
59  * @return Bin value
60  */
61  template <unsigned int tChannel>
62  inline unsigned int bin(const uint8_t index) const;
63 
64  /**
65  * Returns the bin value of a specific channel and bin.
66  * @param channel Data channel, with range [0, tChannels)
67  * @param index The index of the bin, with range [0, 255]
68  * @return Bin value
69  */
70  inline unsigned int bin(const unsigned int channel, const uint8_t index) const;
71 
72  /**
73  * Returns the sum of all channels stored for a specific bin.
74  * @param index The index of the bin, with range [0, 255]
75  * @return Sum of all channels
76  */
77  inline unsigned int sumBin(const uint8_t index) const;
78 
79  /**
80  * Returns the 256 histogram values for a specific channel.
81  * @tparam tChannel Channel for that the histogram is requested, with range [0, tChannels)
82  * @return Channel histogram
83  */
84  template <unsigned int tChannel>
85  inline const unsigned int* bins() const;
86 
87  /**
88  * Returns the 256 histogram values for a specific channel.
89  * @param channel The channel for that the histogram is requested, with range [0, tChannels)
90  * @return Channel histogram
91  */
92  inline const unsigned int* bins(const unsigned int channel) const;
93 
94  /**
95  * Determines the highest value within the histogram for a specific channel.
96  * @tparam tChannel Channel for that the highest value has to be found, with range [0, tChannels)
97  * @return Highest value inside the specified channel
98  */
99  template <unsigned int tChannel>
100  unsigned int determineHighestValue() const;
101 
102  /**
103  * Determines the highest value within the histogram for a specific channel.
104  * @param channel The channel for that the highest value has to be found, with range [0, tChannels)
105  * @return Highest value inside the specified channel
106  */
107  unsigned int determineHighestValue(const unsigned int channel) const;
108 
109  /**
110  * Determines the highest value within the entire histogram.
111  * @return Highest histogram value
112  */
113  unsigned int determineHighestValue() const;
114 
115  /**
116  * Determines the first bin that is not zero for a specific channel.
117  * @param channel Histogram channel in that the search is invoked, with range [0, tChannels)
118  * @return First non-zero bin, otherwise -1
119  */
120  unsigned int determineStartBin(const unsigned int channel) const;
121 
122  /**
123  * Determines the last bin that is not zero for a specific channel.
124  * @param channel Histogram channel in that the search is invoked, with range [0, tChannels)
125  * @return Last non-zero bin, otherwise -1
126  */
127  unsigned int determineEndBin(const unsigned int channel) const;
128 
129  /**
130  * Normalizes the entire histogram by application of the highest histogram value.
131  * @param newMaximalValue Normalization value that will be the maximal value inside the entire histogram after normalization
132  */
133  inline void normalize(const unsigned int newMaximalValue);
134 
135  /**
136  * Normalizes one channel of the histogram by application of the highest value of the channel.
137  * @param channel Histogram channel that will be normalized, with range [0, tChannels)
138  * @param newMaximalValue Normalization value that will be the maximal value inside the histogram channel after normalization
139  */
140  inline void normalize(const unsigned int channel, const unsigned int newMaximalValue);
141 
142  /**
143  * Clears the entire histogram and sets all bins to zero.
144  */
145  void clear();
146 
147  /**
148  * Returns whether all bins inside the histogram are zero.
149  * @return True, if so
150  */
151  inline bool isNull() const;
152 
153  /**
154  * Returns whether two histogram objects are identical according to their histogram bins.
155  * @param histogram Second histogram object
156  * @return True, if so
157  */
158  inline bool operator==(const HistogramBase8BitPerChannel<tChannels>& histogram) const;
159 
160  /**
161  * Returns whether two histogram objects are not identical according to their histogram bins.
162  * @param histogram Second histogram object
163  * @return True, if so
164  */
165  inline bool operator!=(const HistogramBase8BitPerChannel<tChannels>& histogram) const;
166 
167  /**
168  * Adds the histogram bins of a second histogram to this histogram.
169  * @param histogram Second histogram that is added to this one
170  * @return Reference to this histogram object
171  */
173 
174  /**
175  * Returns all histogram bins of this histogram.
176  * The bins are stored channel by channel (first the 256 bins of the first channel, than the next 256 bins of the next channel, ...)
177  * @return Histogram bins
178  */
179  inline const unsigned int* operator()() const;
180 
181  protected:
182 
183  /**
184  * Creates an empty histogram object and sets all histogram bins to zero.
185  */
187 
188  /**
189  * Explicitly sets a value of a specific histogram bin.
190  * @param channel Histogram channel for that the bin has to be set
191  * @param index The index of the bin to be set
192  * @param value Value to be set as new histogram bin value
193  */
194  void setBin(const unsigned int channel, const uint8_t index, const unsigned int value);
195 
196  protected:
197 
198  /// The histogram bins.
199  unsigned int histogramBins[256u * tChannels];
200  };
201 
202  /**
203  * This class implements a standard histogram object storing 8 bit per channel.
204  * @tparam tChannels Defines the number of channels of the histogram
205  */
206  template <unsigned int tChannels>
208  {
209  public:
210 
211  /**
212  * Creates a new histogram object and sets all histogram bins to zero.
213  */
214  inline Histogram8BitPerChannel();
215 
216  /**
217  * Increments a specific bin of this histogram (by one).
218  * @param index The index of the bin
219  * @tparam tChannel Histogram channel in that the bin is stored
220  */
221  template <unsigned int tChannel>
222  inline void incrementBin(const uint8_t index);
223 
224  /**
225  * Increments a specific bin of this histogram (by one).
226  * @param channel Histogram channel in that the bin is stored
227  * @param index The index of the bin
228  */
229  inline void incrementBin(const unsigned int channel, const uint8_t index);
230 
231  /**
232  * Increments all channels of a specific histogram bin (by one).
233  * The given pixel value must provide as much channels as defined for this histogram (by tChannels).<br>
234  * @param pixel Pixel that is used to store all histogram channels
235  */
236  inline void increment(const uint8_t* pixel);
237 
238  /**
239  * Adds to histogram objects and returns the new histogram.
240  * @param histogram Second histogram object that is used to create the new sum histogram
241  * @return Resulting new sum histogram object
242  */
244  };
245 
246  /**
247  * This class implements an integral histogram object.
248  * This histogram holds the sum of all previous bins in each bin of the histogram.<br>
249  * @tparam tChannels Defines the number of channels of the histogram
250  */
251  template <unsigned int tChannels>
253  {
254  public:
255 
256  /**
257  * Creates a new integral histogram object and sets all histogram bins to zero.
258  */
260 
261  /**
262  * Creates a new integral histogram by application of a standard histogram.
263  * The bins of the standard histogram are used to calculate the integral histogram bins.
264  * @param histogram Standard histogram that will be converted into this integral histogram object
265  */
267 
268  /**
269  * Inverts this (normalized) integral histogram so that the inverted histogram can be used as lookup object.
270  * Beware: This histogram has to be normalized to the maximal bin value of 0xFF before!<br>
271  * @return Inverted integral histogram of this object
272  * @see HistogramBase8BitPerChannel::normalize().
273  */
274  IntegralHistogram8BitPerChannel invert() const;
275  };
276 
277  private:
278 
279  /**
280  * This class implements a simple lookup table.
281  * @tparam tChannels Defines the number of channels of the table
282  */
283  template <unsigned int tChannels>
285  {
286  public:
287 
288  /**
289  * Creates a default lookup table providing the identity lookup result.
290  */
292 
293  /**
294  * Creates a new lookup table by a given normalized integral histogram used as start position and an inverted normalized integral histogram used as end position.
295  * Beware: Both provided integral histograms have to be normalized to the maximal bin value of 0xFF before!<br>
296  * @param normalizedHistogram The normalized integral histogram that is used to create the intermediate lookup value
297  * @param invertedNormalizedHistogram The inverted normalized integral histogram that is used to translate the intermediate lookup value into the final lookup result
298  */
299  LookupTable8BitPerChannel(const IntegralHistogram8BitPerChannel<tChannels>& normalizedHistogram, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedHistogram);
300 
301  /**
302  * Lookup function providing the lookup value for a specific channel and bin.
303  * @param index The index of the lookup bin
304  * @tparam tChannel Channel in that the lookup bin in located
305  * @return Lookup value
306  */
307  template <unsigned int tChannel>
308  uint8_t lookup(const uint8_t index) const;
309 
310  /**
311  * Lookup function providing the lookup value for a specific channel and bin.
312  * @param index The index of the lookup bin
313  * @param channel The channel in that the lookup bin in located
314  * @return Lookup value
315  */
316  uint8_t lookup(const unsigned int channel, const uint8_t index) const;
317 
318  protected:
319 
320  /// The lookup data.
321  uint8_t lookupData[256u * tChannels];
322  };
323 
324  public:
325 
326  /**
327  * Determines the standard histogram for a given frame.
328  * @param frame The frame for that the histogram has to be determined
329  * @param width The width of the given frame in pixel
330  * @param height The height of the given frame in pixel
331  * @param framePaddingElements Optional number of padding elements of the input frame, range: [0, infinity)
332  * @param worker Optional worker object to distributed the computation
333  * @return Resulting standard histogram object
334  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
335  */
336  template <unsigned int tChannels>
337  static Histogram8BitPerChannel<tChannels> determineHistogram8BitPerChannel(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, Worker* worker = nullptr);
338 
339  /**
340  * Determines the standard histogram in a sub region of a given frame.
341  * @param frame The frame for that the histogram has to be determined
342  * @param width The width of the given frame in pixel
343  * @param height The height of the given frame in pixel
344  * @param subframeLeft Horizontal start position of the sub region within the frame, in pixel with range [0, width)
345  * @param subframeTop Vertical start position of the sub region within the frame, in pixel with range [0, height)
346  * @param subframeWidth The width of the sub region, in pixel with range [1, width - subframeLeft]
347  * @param subframeHeight The height of the sub region, in pixel with range [1, height - subframeTop]
348  * @param worker Optional worker object to distributed the computation
349  * @param framePaddingElements Optional number of padding elements of the input frame, range: [0, infinity), default: 0
350  * @return Resulting standard histogram object
351  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
352  */
353  template <unsigned int tChannels>
354  static Histogram8BitPerChannel<tChannels> determineHistogram8BitPerChannel(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const unsigned int framePaddingElements, Worker* worker = nullptr);
355 
356  /**
357  * Applies a histogram equalization for a given frame.
358  * The frame is equalized by application of the integral histogram of the original frame.<br>
359  * @param frame The frame that will be equalized according the histogram
360  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
361  * @param worker Optional worker object to distribute the computation
362  * @return True, if succeeded
363  */
364  static bool equalization(Frame& frame, const Scalar factor = 1, Worker* worker = nullptr);
365 
366  /**
367  * Applies a histogram equalization for a given frame.
368  * The frame is equalized by application of the integral histogram of the original frame.<br>
369  * @param source The source frame for that an equalized target frame will be created
370  * @param target The target frame receiving the equalization result
371  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
372  * @param worker Optional worker object to distribute the computation
373  * @return True, if succeeded
374  */
375  static bool equalization(const Frame& source, Frame& target, const Scalar factor = 1, Worker* worker = nullptr);
376 
377  /**
378  * Adjusts the color of a frame according to a given reference frame.
379  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.<br>
380  * The frame types of the frame and the given reference frame must be identical.
381  * @param frame The frame for that the color values will be adjusted
382  * @param reference Reference frame providing the color statistics for the new frame
383  * @param worker Optional worker object to distribute the computation
384  * @return True, if succeeded
385  */
386  static bool adjustColorToReference(Frame& frame, const Frame& reference, Worker* worker = nullptr);
387 
388  /**
389  * Adjusts the color of a frame according to a given reference frame while using corresponding bins for the adjustments only (not the entire frame information).
390  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.<br>
391  * The frame types of the frame and the given reference frame must be identical.
392  * @param frame The frame for that the color values will be adjusted
393  * @param reference Reference frame providing the color statistics for the new frame
394  * @param horizontalBins The number of horizontal bins to use, with range [1, min(frame.width(), reference.with())]
395  * @param verticalBins The number of vertical bins to use, with range [1, min(frame.height(), reference.height())]
396  * @param worker Optional worker object to distribute the computation
397  * @return True, if succeeded
398  */
399  static bool adjustColorToReference(Frame& frame, const Frame& reference, const unsigned int horizontalBins, const unsigned int verticalBins, Worker* worker = nullptr);
400 
401  /**
402  * Adjusts the color of a frame according to a given reference frame while using corresponding bins for the adjustments only (not the entire frame information).
403  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.<br>
404  * The frame types of the frame and the given reference frame must be identical.
405  * @param frame The frame for that the color values will be adjusted
406  * @param frameWidth The width of the frame in pixel, with range [1, infinity)
407  * @param frameHeight The height of the frame in pixel, with range [1, infinity)
408  * @param reference Reference frame providing the color statistics for the new frame
409  * @param referenceWidth The width of the reference frame in pixel, with range [1, infinity)
410  * @param referenceHeight The height of the reference frame in pixel, with range [1, infinity)
411  * @param horizontalBins The number of horizontal bins to use, with range [1, min(frameWidth, referenceWidth)]
412  * @param verticalBins The number of vertical bins to use, with range [1, min(frameHeight, referenceHeight)]
413  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
414  * @param referencePaddingElements The number of padding elements at the end of each reference row, in elements, with range [0, infinity)
415  * @param worker Optional worker object to distribute the computation
416  * @return True, if succeeded
417  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
418  */
419  template <unsigned int tChannels>
420  static bool adjustColorToReference(uint8_t* frame, const unsigned int frameWidth, const unsigned int frameHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int horizontalBins, const unsigned int verticalBins, const unsigned int framePaddingElements, const unsigned int referencePaddingElements, Worker* worker = nullptr);
421 
422  /**
423  * Adjusts the color of a frame according to a given reference frame.
424  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
425  * The frame types of the source frame and the given reference frame must be identical.<br>
426  * @param source The source frame that is used to create the target frame
427  * @param target The target frame with adjusted color information
428  * @param reference Reference frame providing the color statistics for the new frame
429  * @param worker Optional worker object to distribute the computation
430  * @return True, if succeeded
431  */
432  static bool adjustColorToReference(const Frame& source, Frame& target, const Frame& reference, Worker* worker = nullptr);
433 
434  /**
435  * Applies a histogram equalization for a given frame.
436  * The frame is equalized by application of the integral histogram of the original frame.<br>
437  * @param frame The frame that will be equalized according the histogram
438  * @param width The width of the frame in pixel, with range [1, infinity)
439  * @param height The height of the frame in pixel, with range [1, infinity)
440  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
441  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
442  * @param worker Optional worker object to distribute the computation
443  * @return True, if succeeded
444  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
445  */
446  template <unsigned int tChannels>
447  static inline bool equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const Scalar factor, const unsigned int framePaddingElements, Worker* worker = nullptr);
448 
449  /**
450  * Applies a histogram equalization for a given frame.
451  * The frame is equalized by application of the integral histogram of the original frame.<br>
452  * @param source The source frame for that an equalized target frame will be created
453  * @param target The target frame receiving the equalization result
454  * @param width The width of the source and target frame in pixel
455  * @param height The height of the source and target frame in pixel
456  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
457  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
458  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
459  * @param worker Optional worker object to distribute the computation
460  * @return True, if succeeded
461  * @tparam tChannels Number of channels of the source and target frame, with range [1, infinity)
462  */
463  template <unsigned int tChannels>
464  static inline bool equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
465 
466  /**
467  * Applies a histogram equalization for a given frame.
468  * The frame is equalized by application of the integral histogram of the original frame.<br>
469  * @param frame The frame that will be equalized according the histogram
470  * @param width The width of the frame in pixel
471  * @param height The height of the frame in pixel
472  * @param normalizedIntegral Already determined normalized integral histogram of the given frame
473  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
474  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
475  * @param worker Optional worker object to distribute the computation
476  * @return True, if succeeded
477  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
478  */
479  template <unsigned int tChannels>
480  static inline bool equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int framePaddingElements, Worker* worker = nullptr);
481 
482  /**
483  * Applies a histogram equalization in a sub region of a given frame.
484  * The frame is equalized by application of the integral histogram of the original frame.<br>
485  * @param frame The frame that will be equalized according the histogram
486  * @param width The width of the frame in pixel
487  * @param height The height of the frame in pixel
488  * @param subframeLeft Horizontal start position of the sub region within the frame, in pixel with range [0, width)
489  * @param subframeTop Vertical start position of the sub region within the frame, in pixel with range [0, heigh)
490  * @param subframeWidth The width of the sub region, in pixel with range [1, width - subframeLeft]
491  * @param subframeHeight The height of the sub region, in pixel with range [1, height - subframeTop]
492  * @param normalizedIntegral Already determined normalized integral histogram of the given frame
493  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
494  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
495  * @param worker Optional worker object to distribute the computation
496  * @return True, if succeeded
497  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
498  */
499  template <unsigned int tChannels>
500  static bool equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int framePaddingElements, Worker* worker = nullptr);
501 
502  /**
503  * Applies a histogram equalization for a given frame.
504  * The frame is equalized by application of the integral histogram of the original frame.<br>
505  * @param source The source frame for that an equalized target frame will be created
506  * @param target The target frame receiving the equalization result
507  * @param width The width of the source and target frame in pixel
508  * @param height The height of the source and target frame in pixel
509  * @param normalizedIntegral Already determined normalized integral histogram of the given source frame
510  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
511  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
512  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
513  * @param worker Optional worker object to distribute the computation
514  * @return True, if succeeded
515  * @tparam tChannels Number of channels of the source and target frame, with range [1, infinity)
516  */
517  template <unsigned int tChannels>
518  static inline bool equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
519 
520  /**
521  * Applies a histogram equalization for a given frame.
522  * The frame is equalized by application of the integral histogram of the original frame.<br>
523  * @param source The source frame for that an equalized target frame will be created
524  * @param target The target frame receiving the equalization result
525  * @param width The width of the source and target frame in pixel
526  * @param height The height of the source and target frame in pixel
527  * @param subframeLeft Horizontal start position of the sub region within the frame, in pixel with range [0, width)
528  * @param subframeTop Vertical start position of the sub region within the frame, in pixel with range [0, heigh)
529  * @param subframeWidth The width of the sub region, in pixel with range [1, width - subframeLeft]
530  * @param subframeHeight The height of the sub region, in pixel with range [1, height - subframeTop]
531  * @param normalizedIntegral Already determined normalized integral histogram of the given source frame
532  * @param factor Interpolation factor between the original and the fully equalized frame, with range [0, 1]: 0 means the original frame is taken by 100 percent while 1 means that the equalized frame is taken by 100 percent
533  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
534  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
535  * @param worker Optional worker object to distribute the computation
536  * @return True, if succeeded
537  * @tparam tChannels Number of channels of the source and target frame, with range [1, infinity)
538  */
539  template <unsigned int tChannels>
540  static bool equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
541 
542  /**
543  * Adjusts the color of a frame according to a given reference frame.
544  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
545  * @param frame The frame for that the color values will be adjusted
546  * @param frameWidth The width of the frame in pixel
547  * @param frameHeight The height of the frame in pixel
548  * @param reference Reference frame providing the color statistics for the new frame
549  * @param referenceWidth The width of the reference frame in pixel
550  * @param referenceHeight The height of the reference frame in pixel
551  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
552  * @param referencePaddingElements The number of padding elements at the end of each reference row, in elements, with range [0, infinity)
553  * @param worker Optional worker object to distribute the computation
554  * @return True, if succeeded
555  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
556  */
557  template <unsigned int tChannels>
558  static bool adjustColorToReference(uint8_t* frame, const unsigned int frameWidth, const unsigned int frameHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int framePaddingElements, const unsigned int referencePaddingElements, Worker* worker = nullptr);
559 
560  /**
561  * Adjusts the color of a frame according to a given reference frame.
562  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
563  * The frame types of the source frame and the given reference frame must be identical.<br>
564  * @param source The source frame that is used to create the target frame
565  * @param target The target frame with adjusted color information
566  * @param sourceWidth The width of the source and target frame in pixel
567  * @param sourceHeight The height of the source and target frame in pixel
568  * @param reference Reference frame providing the color statistics for the new frame
569  * @param referenceWidth The width of the reference frame in pixel
570  * @param referenceHeight The height of the reference frame in pixel
571  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
572  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
573  * @param referencePaddingElements The number of padding elements at the end of each reference row, in elements, with range [0, infinity)
574  * @param worker Optional worker object to distribute the computation
575  * @return True, if succeeded
576  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
577  */
578  template <unsigned int tChannels>
579  static bool adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int referencePaddingElements, Worker* worker = nullptr);
580 
581  /**
582  * Adjusts the color of a frame according to a given reference frame.
583  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
584  * @param frame The frame for that the color values will be adjusted
585  * @param width The width of the frame in pixel
586  * @param height The height of the frame in pixel
587  * @param invertedNormalizedReferenceIntegral Already determined inverted and normalized integral histogram of the reference frame
588  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
589  * @param worker Optional worker object to distribute the computation
590  * @return True, if succeeded
591  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
592  */
593  template <unsigned int tChannels>
594  static inline bool adjustColorToReference(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int framePaddingElements, Worker* worker = nullptr);
595 
596  /**
597  * Adjusts the color of a frame according to a given reference frame.
598  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
599  * @param frame The frame for that the color values will be adjusted
600  * @param width The width of the frame in pixel
601  * @param height The height of the frame in pixel
602  * @param subframeLeft Horizontal start position of the sub region within the frame, in pixel with range [0, width)
603  * @param subframeTop Vertical start position of the sub region within the frame, in pixel with range [0, heigh)
604  * @param subframeWidth The width of the sub region, in pixel with range [1, width - subframeLeft]
605  * @param subframeHeight The height of the sub region, in pixel with range [1, height - subframeTop]
606  * @param invertedNormalizedReferenceIntegral Already determined inverted and normalized integral histogram of the reference frame
607  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
608  * @param worker Optional worker object to distribute the computation
609  * @return True, if succeeded
610  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
611  */
612  template <unsigned int tChannels>
613  static bool adjustColorToReference(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int framePaddingElements, Worker* worker = nullptr);
614 
615  /**
616  * Adjusts the color of a frame according to a given reference frame.
617  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
618  * The frame types of the source frame and the given reference frame must be identical.<br>
619  * @param source The source frame that is used to create the target frame
620  * @param target The target frame with adjusted color information
621  * @param width The width of the source and target frame in pixel
622  * @param height The height of the source and target frame in pixel
623  * @param invertedNormalizedReferenceIntegral Already determined inverted and normalized integral histogram of the reference frame
624  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
625  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
626  * @param worker Optional worker object to distribute the computation
627  * @return True, if succeeded
628  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
629  */
630  template <unsigned int tChannels>
631  static inline bool adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
632 
633  /**
634  * Adjusts the color of a frame according to a given reference frame.
635  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
636  * The frame types of the source frame and the given reference frame must be identical.<br>
637  * @param source The source frame that is used to create the target frame
638  * @param target The target frame with adjusted color information
639  * @param width The width of the source and target frame in pixel
640  * @param height The height of the source and target frame in pixel
641  * @param subframeLeft Horizontal start position of the sub region within the frame, in pixel with range [0, width)
642  * @param subframeTop Vertical start position of the sub region within the frame, in pixel with range [0, heigh)
643  * @param subframeWidth The width of the sub region, in pixel with range [1, width - subframeLeft]
644  * @param subframeHeight The height of the sub region, in pixel with range [1, height - subframeTop]
645  * @param invertedNormalizedReferenceIntegral Already determined inverted and normalized integral histogram of the reference frame
646  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
647  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
648  * @param worker Optional worker object to distribute the computation
649  * @return True, if succeeded
650  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
651  */
652  template <unsigned int tChannels>
653  static bool adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
654 
655  private:
656 
657  /**
658  * Determines the standard histogram in a subset of a given frame.
659  * @param frame The frame for that the histogram has to be determined, must be valid
660  * @param width The width of the given frame in pixel, with range [1, infinity)
661  * @param height The height of the given frame in pixel, with range [1, infinity)
662  * @param histogram Resulting histogram
663  * @param lock Optional lock object that needs to be defined if this function is executed in parallel
664  * @param firstColumn First column to be handled
665  * @param numberColumns Number of columns to be handled
666  * @param framePaddingElements Optional number of padding elements of the input frame, range: [0, infinity)
667  * @param firstRow First row to be handled, with range [0, infinity)
668  * @param numberRows Number of rows to be handled, with range [1, height - firstRow]
669  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
670  */
671  template <unsigned int tChannels>
672  static void determineHistogram8BitPerChannelSubset(const uint8_t* frame, const unsigned int width, const unsigned int height, Histogram8BitPerChannel<tChannels>* histogram, Lock* lock, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows);
673 
674  /**
675  * Applies a histogram equalization in a subset of a given frame.
676  * The frame is equalized by application of the integral histogram of the original frame.<br>
677  * @param frame The frame that will be equalized according the histogram
678  * @param width The width of the frame in pixel
679  * @param height The height of the frame in pixel
680  * @param normalizedIntegral Already determined normalized integral histogram of the given frame
681  * @param factor Interpolation factor, with range [0, 256]
682  * @param firstColumn First column to be handled
683  * @param numberColumns Number of columns to be handled
684  * @param framePaddingElements Optional number of padding elements of the input frame, range: [0, infinity)
685  * @param firstRow First row to be handled
686  * @param numberRows Number of rows to be handled
687  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
688  */
689  template <unsigned int tChannels>
690  static void equalizationSubset(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>* normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows);
691 
692  /**
693  * Applies a histogram equalization in a subset of a given frame.
694  * The frame is equalized by application of the integral histogram of the original frame.<br>
695  * @param source The source frame for that an equalized target frame will be created
696  * @param target The target frame receiving the equalization result
697  * @param width The width of the source and target frame in pixel
698  * @param height The height of the source and target frame in pixel
699  * @param normalizedIntegral Already determined normalized integral histogram of the given frame
700  * @param factor Interpolation factor, with range [0, 256]
701  * @param firstColumn First column to be handled
702  * @param numberColumns Number of columns to be handled
703  * @param sourcePaddingElements Optional number of padding elements of the source frame, range: [0, infinity)
704  * @param targetPaddingElements Optional number of padding elements of the target frame, range: [0, infinity)
705  * @param firstRow First row to be handled
706  * @param numberRows Number of rows to be handled
707  * @tparam tChannels Number of channels of the source and target frame, with range [1, infinity)
708  */
709  template <unsigned int tChannels>
710  static void equalizationOfTargetSubset(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>* normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows);
711 
712  /**
713  * Adjusts the color in a subset of a frame according to a given reference frame.
714  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
715  * @param frame The frame for that the color values will be adjusted
716  * @param width The width of the frame in pixel
717  * @param height The height of the frame in pixel
718  * @param lookupTable Lookup table defining the adjustment of the color
719  * @param firstColumn First column to be handled
720  * @param numberColumns Number of columns to be handled
721  * @param framePaddingElements Optional number of padding elements of the input frame, range: [0, infinity)
722  * @param firstRow First row to be handled
723  * @param numberRows Number of rows to be handled
724  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
725  */
726  template <unsigned int tChannels>
727  static void adjustColorToReferenceSubset(uint8_t* frame, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel<tChannels>* lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows);
728 
729  /**
730  * Adjusts the color of a frame according to a given reference frame.
731  * The function applies a forward and backward mapping of the normalized integral histograms of both frames.
732  * The frame types of the source frame and the given reference frame must be identical.<br>
733  * @param source The source frame that is used to create the target frame
734  * @param target The target frame with adjusted color information
735  * @param width The width of the source and target frame in pixel
736  * @param height The height of the source and target frame in pixel
737  * @param lookupTable Lookup table defining the adjustment of the color
738  * @param firstColumn First column to be handled
739  * @param numberColumns Number of columns to be handled
740  * @param sourcePaddingElements Optional number of padding elements of the source frame, range: [0, infinity)
741  * @param targetPaddingElements Optional number of padding elements of the target frame, range: [0, infinity)
742  * @param firstRow First row to be handled
743  * @param numberRows Number of rows to be handled
744  * @tparam tChannels Number of channels of the frame, with range [1, infinity)
745  */
746  template <unsigned int tChannels>
747  static void adjustColorToReferenceOfTargetSubset(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel<tChannels>* lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows);
748 };
749 
750 /**
751  * Implementation of Contrast-Limited Adaptive Histogram Equalization (CLAHE).
752  * @ingroup cv
753  */
754 class OCEAN_CV_EXPORT ContrastLimitedAdaptiveHistogram
755 {
756  public:
757 
758  /// Number of bins in the tile histograms
759  static constexpr unsigned int histogramSize = 256u;
760 
761  /// Tile histogram
762  typedef std::array<unsigned int, histogramSize> TileHistogram;
763 
764  /// Image partitioning and tile boundary lookup
766 
767  public:
768 
769  /**
770  * Histogram equalization a la CLAHE
771  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
772  * @param width The width of the source and target frames, range: [horizontalTiles, infinity)
773  * @param height The height of the source and target frames, range: [verticalTiles, infinity)
774  * @param target Destination location for the result, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`) and have the same size as the source
775  * @param clipLimit Global scaling factor to determine the tile clip limit, `tileClipLimit = clipLimit * N`, where `N = (tileSize / histogramSize)` is the number of pixels per bin if all pixels are distributed evenly over the histogram (average), range: [0, infinity), default: 40
776  * @param horizontalTiles Number of tiles the source image will be split horizontally, range: [2, width], default: 8
777  * @param verticalTiles Number of tiles the source image will be split vertically, range: [2, height], default: 8
778  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
779  * @param targetPaddingElements Number of padding elements in the target data, range: [0, infinity), default: 0
780  * @param worker Optional worker instance for parallel execution, default: nullptr
781  */
782  static void equalization8BitPerChannel(const uint8_t* const source, const unsigned int width, const unsigned height, uint8_t* const target, const Scalar clipLimit = Scalar(40), const unsigned int horizontalTiles = 8u, const unsigned int verticalTiles = 8u, const unsigned int sourcePaddingElements = 0u, const unsigned int targetPaddingElements = 0u, Worker* worker = nullptr);
783 
784  protected:
785 
786  /**
787  * Computation of a lookup table required to normalize an image histogram (used per tile)
788  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
789  * @param width The width of the source and target frames, range: [1, infinity)
790  * @param height The height of the source and target frames, range: [1, infinity)
791  * @param lookupTable Storage location for the computed lookup table, must be initialized, expected size: 256
792  * @param clipLimit Scaling factor to determine the tile clip limit, `tileClipLimit = clipLimit * N`, where `N = (tileSize / histogramSize)` is the number of pixels per bin if all pixels are distributed evenly over the histogram (average), range: [0, infinity)
793  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
794  */
795  static inline void computeLookupTable(const uint8_t* source, const unsigned int width, const unsigned int height, uint8_t* const lookupTable, const Scalar clipLimit, const unsigned int sourcePaddingElements = 0u);
796 
797  /**
798  * Computation of per-tile lookup tables required to normalize an image histogram given a partitioned image
799  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
800  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid
801  * @param tileLookupTables Storage location for the computed lookup tables; will be initialized internally to size N x 256, where N = the total number of bins
802  * @param clipLimit Scaling factor to determine the tile clip limit, `tileClipLimit = clipLimit * N`, where `N = (tileSize / histogramSize)` is the number of pixels per bin if all pixels are distributed evenly over the histogram (average), range: [0, infinity)
803  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
804  * @param worker Optional worker instance for parallel execution, default: nullptr
805  */
806  static void computeTileLookupTables(const uint8_t* const source, const TileLookupCenter2& lookupCenter2, std::vector<uint8_t>& tileLookupTables, const Scalar clipLimit, const unsigned int sourcePaddingElements = 0u, Worker* worker = nullptr);
807 
808  /**
809  * Computation of the bilinear interpolation parameters for the low bins of an image pixel
810  * If `isHorizontal == true`, this function computes the horizontal interpolation parameters, i.e., the left bins and left interpolation factors, otherwise it will compute the top bins and interpolation factors. For the horizontal parameters (`isHorizontal == true`), the right counterparts can be computed as:
811  *
812  * `rightBins[i] = lowBins[i] + 1u`
813  * `rightFactors_fixed7[i] = 128u - lowFactors_fixed7[i]`
814  *
815  * and, similarly, for the vertical parameters (`isHorizontal == false`).
816  *
817  * Note: 128u is the fixed-point, 7-bit precision equivalent of 1.0f
818  *
819  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid, number of bins (`binsX()`) must >= 2
820  * @param isHorizontal If true, it will compute the horizontal interpolation parameters, otherwise the vertical parameters will be computed
821  * @param lowBins Stores the indices of the closest lower (lower = left if `isHorizontal == true`, otherwise lower = top) bins of a pixel location, must be initialized before calling this function, expected size: image width if `isHorizontal == true`, otherwise image height
822  * @param lowFactors_fixed7 Stores the horizontal (if `isHorizontal == true`) or vertical (if `isHorizontal == false`) interpolation factors for the lower bins (as 8-bit fixed point numbers with 7-bit precision, i.e. range: [0, 1]), must be initialized before calling this function, expected size: image width if `isHorizontal == true`, otherwise image height
823  */
824  static void computeLowBilinearInterpolationFactors7BitPrecision(const TileLookupCenter2& lookupCenter2, const bool isHorizontal, Index32* lowBins, uint8_t* lowFactors_fixed7);
825 
826  /**
827  * Histogram normalization by bilinearly interpolating pixels using the CLAHE per-tile lookup tables
828  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
829  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid
830  * @param target Pointer to the data of the target frame, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
831  * @param tileLookupTables Storage location for the computed lookup tables; will be initialized internally to size N x 256, where N = the total number of bins
832  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
833  * @param targetPaddingElements Number of padding elements in the target data, range: [0, infinity), default: 0
834  * @param worker Optional worker instance for parallel execution, default: nullptr
835  */
836  static void bilinearInterpolation(const uint8_t* const source, const TileLookupCenter2& lookupCenter2, uint8_t* const target, const std::vector<uint8_t>& tileLookupTables, const unsigned int sourcePaddingElements = 0u, const unsigned int targetPaddingElements = 0u, Worker* worker = nullptr);
837 
838  /**
839  * Helper function for the computation of per-tile lookup tables required to normalize an image histogram given a partitioned image
840  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
841  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid
842  * @param tileLookupTables Storage location for the computed lookup tables; will be initialized internally to size N x 256, where N = the total number of bins
843  * @param clipLimit Scaling factor to determine the tile clip limit, `tileClipLimit = clipLimit * N`, where `N = (tileSize / histogramSize)` is the number of pixels per bin if all pixels are distributed evenly over the histogram (average), range: [0, infinity)
844  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
845  * @param firstTile Index of first tile to process, range: [0, N), where N is the total number of tiles
846  * @param tileCount Number of tiles to process, range: [1, N], such `firstTile + tileCount < N` where N is the total number of tiles
847  */
848  static void computeTileLookupTablesSubset(const uint8_t* const source, const TileLookupCenter2* lookupCenter2, uint8_t* const tileLookupTables, const Scalar clipLimit, const unsigned int sourcePaddingElements = 0u, const unsigned int firstTile = 0u, const unsigned int tileCount = 0u);
849 
850  /**
851  * Integer-based (fixed-point arithmetic) helper function for the histogram normalization by bilinearly interpolating pixels using the CLAHE per-tile lookup tables
852  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
853  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid
854  * @param target Pointer to the data of the target frame, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
855  * @param tileLookupTables Storage location for the computed lookup tables; will be initialized internally to size N x 256, where N = the total number of bins
856  * @param leftBins Stores the indices of the closest bins left of a horizontal pixel location, must be initialized, expected size: image width
857  * @param leftFactors_fixed7 Stores the horizontal interpolation factors for the left bins (as fixed-point number with 7-bit precision), must be initialized, expected size: image width
858  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
859  * @param targetPaddingElements Number of padding elements in the target data, range: [0, infinity), default: 0
860  * @param rowStart First image row to process, range: [0, height)
861  * @param rowCount Number of rows to process, range: [0, height - rowStart)
862  */
863  static void bilinearInterpolation7BitPrecisionSubset(const uint8_t* const source, const TileLookupCenter2* lookupCenter2, uint8_t* const target, const uint8_t* const tileLookupTables, const Index32* const leftBins, const uint8_t* const leftFactors_fixed7, const unsigned int sourcePaddingElements = 0u, const unsigned int targetPaddingElements = 0u, const unsigned int rowStart = 0u, const unsigned int rowCount = 0u);
864 
865 #if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
866 
867  /**
868  * Helper function for the histogram normalization by bilinearly interpolating pixels using the CLAHE per-tile lookup tables
869  * @param source Pointer to the data of the source frame that will be processed, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
870  * @param lookupCenter2 Defines how the source frame is partitioned, image size and number of bins will be extracted from this object, must be valid
871  * @param target Pointer to the data of the target frame, must be valid and 8-bit unsigned, 1-channel (`FrameType::FORMAT_Y8`)
872  * @param tileLookupTables Storage location for the computed lookup tables; will be initialized internally to size N x 256, where N = the total number of bins
873  * @param leftBins Stores the indices of the closest bins left of a horizontal pixel location, must be initialized, expected size: image width
874  * @param leftFactors_fixed7 Stores the horizontal interpolation factors for the left bins (as fixed-point number with 7-bit precision), must be initialized, expected size: image width
875  * @param topBins Stores the indices of the closest vertical bins above a pixel location, must be initialized, expected size: image height
876  * @param topFactors_fixed7 Stores the vertical interpolation factors for the top bins (as fixed-point number with 7-bit precision), must be initialized, expected size: image height
877  * @param sourcePaddingElements Number of padding elements in the source data, range: [0, infinity), default: 0
878  * @param targetPaddingElements Number of padding elements in the target data, range: [0, infinity), default: 0
879  * @param tileStart First tile to process, range: [0, N), where N = number of tiles
880  * @param tileCount Number of tiles to process, range: [0, N - tileStart)
881  */
882  static void bilinearInterpolationNEON7BitPrecisionSubset(const uint8_t* const source, const TileLookupCenter2* lookupCenter2, uint8_t* const target, const uint8_t* const tileLookupTables, const Index32* const leftBins, const uint8_t* const leftFactors_fixed7, const Index32* const topBins, const uint8_t* const topFactors_fixed7, const unsigned int sourcePaddingElements = 0u, const unsigned int targetPaddingElements = 0u, const unsigned int tileStart = 0u, const unsigned int tileCount = 0u);
883 
884 #endif // OCEAN_HARDWARE_NEON_VERSION >= 10
885 };
886 
887 inline void ContrastLimitedAdaptiveHistogram::computeLookupTable(const uint8_t* source, const unsigned int width, const unsigned int height, uint8_t* const lookupTable, const Scalar clipLimit, const unsigned int sourcePaddingElements)
888 {
889  ocean_assert(source != nullptr);
890  ocean_assert(width != 0u && height != 0u);
891  ocean_assert(lookupTable != nullptr);
892  ocean_assert(clipLimit >= Scalar(0));
893 
894  const unsigned int sourceArea = width * height;
895  const unsigned int sourceStrideElements = width + sourcePaddingElements;
896  const uint8_t* const sourceEnd = source + height * sourceStrideElements;
897 
898  // Histogram computation
899  TileHistogram histogram;
900  memset(histogram.data(), 0u, histogram.size() * sizeof(TileHistogram::value_type));
901  const unsigned int widthEnd = width >= 4u ? width - 4u : 0u;
902 
903  for (unsigned int y = 0u; y < height; ++y)
904  {
905  unsigned int x = 0u;
906 
907  while (x < widthEnd)
908  {
909  ocean_assert_and_suppress_unused(source + x + 3u < sourceEnd, sourceEnd);
910  histogram[source[x + 0u]]++;
911  histogram[source[x + 1u]]++;
912  histogram[source[x + 2u]]++;
913  histogram[source[x + 3u]]++;
914 
915  x += 4u;
916  }
917 
918  while (x < width)
919  {
920  ocean_assert(source + x < sourceEnd);
921  histogram[source[x]]++;
922 
923  ++x;
924  }
925 
926  source += sourceStrideElements;
927  }
928 
929  // Clip histogram peaks and redistribute area exceeding the clip limit
930  ocean_assert(histogramSize != 0u);
931  const unsigned int scaledClipLimit = std::max(1u, (unsigned int)(clipLimit * float(sourceArea) / float(histogramSize)));
932  unsigned int clippedArea = 0u;
933 
934  for (unsigned int i = 0u; i < histogramSize; ++i)
935  {
936  if (histogram[i] > scaledClipLimit)
937  {
938  clippedArea += histogram[i] - scaledClipLimit;
939  histogram[i] = scaledClipLimit;
940  }
941  }
942 
943  if (clippedArea != 0u)
944  {
945  const unsigned int redistribution = clippedArea / histogramSize;
946  const unsigned int residual = clippedArea - (redistribution * histogramSize);
947 
948  for (unsigned int i = 0u; i < residual; ++i)
949  {
950  histogram[i] += (redistribution + 1u);
951  }
952 
953  for (unsigned int i = residual; i < histogramSize; ++i)
954  {
955  histogram[i] += redistribution;
956  }
957  }
958 
959  // Normalize histogram (CDF + normalization)
960  ocean_assert(sourceArea != 0u);
961  const float normalizationFactor = float(histogramSize - 1u) / float(sourceArea);
962  unsigned int sum = 0u;
963 
964  for (unsigned int i = 0u; i < histogramSize; ++i)
965  {
966  sum += histogram[i];
967 
968  ocean_assert((int)(float(sum) * normalizationFactor + 0.5f) >= 0);
969  ocean_assert((int)(float(sum) * normalizationFactor + 0.5f) <= (int)(NumericT<uint8_t>::maxValue()));
970  lookupTable[i] = (uint8_t)(float(sum) * normalizationFactor + 0.5f);
971  }
972 }
973 
974 template <unsigned int tChannels>
976 {
977  memset(histogramBins, 0x00, sizeof(unsigned int) * 256u * tChannels);
978 }
979 
980 template <unsigned int tChannels>
981 template <unsigned int tChannel>
982 inline unsigned int Histogram::HistogramBase8BitPerChannel<tChannels>::bin(const uint8_t index) const
983 {
984  static_assert(tChannel < tChannels, "Invalid channel index!");
985 
986  return histogramBins[tChannel * 256u + index];
987 }
988 
989 template <unsigned int tChannels>
990 inline unsigned int Histogram::HistogramBase8BitPerChannel<tChannels>::bin(const unsigned int channel, const uint8_t index) const
991 {
992  ocean_assert(channel < tChannels);
993 
994  return histogramBins[channel * 256u + index];
995 }
996 
997 template <unsigned int tChannels>
998 inline unsigned int Histogram::HistogramBase8BitPerChannel<tChannels>::sumBin(const uint8_t index) const
999 {
1000  unsigned int result = 0u;
1001 
1002  for (unsigned int n = 0u; n < tChannels; ++n)
1003  {
1004  result += histogramBins[n * 256u + index];
1005  }
1006 
1007  return result;
1008 }
1009 
1010 template <unsigned int tChannels>
1011 template <unsigned int tChannel>
1013 {
1014  static_assert(tChannel < tChannels, "Invalid channel index!");
1015 
1016  return histogramBins + 256u * tChannel;
1017 }
1018 
1019 template <unsigned int tChannels>
1020 inline const unsigned int* Histogram::HistogramBase8BitPerChannel<tChannels>::bins(const unsigned int channel) const
1021 {
1022  ocean_assert(channel < tChannels);
1023 
1024  return histogramBins + 256u * channel;
1025 }
1026 
1027 template <unsigned int tChannels>
1028 template <unsigned int tChannel>
1030 {
1031  static_assert(tChannel < tChannels, "Invalid channel index!");
1032 
1033  unsigned int value = 0u;
1034  const unsigned int* bins = histogramBins + 256u * tChannel;
1035 
1036  for (unsigned int n = 0u; n < 256u; ++n)
1037  {
1038  if (bins[n] > value)
1039  {
1040  value = bins[n];
1041  }
1042  }
1043 
1044  return value;
1045 }
1046 
1047 template <unsigned int tChannels>
1049 {
1050  ocean_assert(channel < tChannels);
1051 
1052  unsigned int value = 0u;
1053  const unsigned int* bins = histogramBins + 256u * channel;
1054 
1055  for (unsigned int n = 0u; n < 256u; ++n)
1056  {
1057  if (bins[n] > value)
1058  {
1059  value = bins[n];
1060  }
1061  }
1062 
1063  return value;
1064 }
1065 
1066 template <unsigned int tChannels>
1068 {
1069  unsigned int value = 0u;
1070 
1071  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1072  {
1073  if (histogramBins[n] > value)
1074  {
1075  value = histogramBins[n];
1076  }
1077  }
1078 
1079  return value;
1080 }
1081 
1082 template <unsigned int tChannels>
1083 unsigned int Histogram::HistogramBase8BitPerChannel<tChannels>::determineStartBin(const unsigned int channel) const
1084 {
1085  ocean_assert(channel < tChannels);
1086 
1087  const unsigned int* bins = histogramBins + 256u * channel;
1088 
1089  for (unsigned int n = 0u; n < 256u; ++n)
1090  {
1091  if (bins[n] != 0u)
1092  {
1093  return n;
1094  }
1095  }
1096 
1097  return (unsigned int)(-1);
1098 }
1099 
1100 template <unsigned int tChannels>
1101 unsigned int Histogram::HistogramBase8BitPerChannel<tChannels>::determineEndBin(const unsigned int channel) const
1102 {
1103  ocean_assert(channel < tChannels);
1104 
1105  const unsigned int* bins = histogramBins + 256u * channel;
1106 
1107  for (unsigned int n = 255u; n < 256u; --n)
1108  {
1109  if (bins[n] != 0u)
1110  {
1111  return n;
1112  }
1113  }
1114 
1115  return (unsigned int)(-1);
1116 }
1117 
1118 template <unsigned int tChannels>
1119 inline void Histogram::HistogramBase8BitPerChannel<tChannels>::normalize(const unsigned int newMaximalValue)
1120 {
1121  const unsigned int maximalValue = determineHighestValue();
1122 
1123  if (maximalValue == 0u)
1124  {
1125  return;
1126  }
1127 
1128  const unsigned int maximalValue_2 = maximalValue / 2u;
1129 
1130  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1131  {
1132  histogramBins[n] = (histogramBins[n] * newMaximalValue + maximalValue_2) / maximalValue;
1133  }
1134 }
1135 
1136 template <unsigned int tChannels>
1137 inline void Histogram::HistogramBase8BitPerChannel<tChannels>::normalize(const unsigned int channel, const unsigned int newMaximalValue)
1138 {
1139  ocean_assert(channel < tChannels);
1140 
1141  const unsigned int maximalValue = determineHighestValue(channel);
1142 
1143  if (maximalValue == 0u)
1144  {
1145  return;
1146  }
1147 
1148  const unsigned int maximalValue_2 = maximalValue / 2u;
1149 
1150  unsigned int* bins = histogramBins + 256u * channel;
1151 
1152  for (unsigned int n = 0u; n < 256u; ++n)
1153  {
1154  bins[n] = (bins[n] * newMaximalValue + maximalValue_2) / maximalValue;
1155  }
1156 }
1157 
1158 template <unsigned int tChannels>
1160 {
1161  memset(histogramBins, 0x00, sizeof(unsigned int) * 256u * tChannels);
1162 }
1163 
1164 template <unsigned int tChannels>
1166 {
1167  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1168  {
1169  if (histogramBins[n] != histogram.histogramBins[n])
1170  {
1171  return false;
1172  }
1173  }
1174 
1175  return true;
1176 }
1177 
1178 template <unsigned int tChannels>
1180 {
1181  return !(*this == histogram);
1182 }
1183 
1184 template <unsigned int tChannels>
1186 {
1187  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1188  {
1190  }
1191 
1192  return *this;
1193 }
1194 
1195 template <unsigned int tChannels>
1197 {
1198  return histogramBins;
1199 }
1200 
1201 template <unsigned int tChannels>
1202 void Histogram::HistogramBase8BitPerChannel<tChannels>::setBin(const unsigned int channel, const uint8_t index, const unsigned int value)
1203 {
1204  ocean_assert(channel < tChannels);
1205 
1206  histogramBins[channel * 256u + index] = value;
1207 }
1208 
1209 template <unsigned int tChannels>
1211 {
1212  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1213  {
1214  if (histogramBins[n] != 0u)
1215  {
1216  return false;
1217  }
1218  }
1219 
1220  return true;
1221 }
1222 
1223 template <unsigned int tChannels>
1225  HistogramBase8BitPerChannel<tChannels>()
1226 {
1227  // nothing to do here
1228 }
1229 
1230 template <unsigned int tChannels>
1231 template <unsigned int tChannel>
1233 {
1234  static_assert(tChannel < tChannels, "Invalid channel index!");
1235 
1236  HistogramBase8BitPerChannel<tChannels>::histogramBins[tChannel * 256u + index]++;
1237 }
1238 
1239 template <unsigned int tChannels>
1240 inline void Histogram::Histogram8BitPerChannel<tChannels>::incrementBin(const unsigned int channel, const uint8_t index)
1241 {
1242  ocean_assert(channel < tChannels);
1243 
1245 }
1246 
1247 template <unsigned int tChannels>
1249 {
1250  ocean_assert(pixel != nullptr);
1251 
1252  for (unsigned int n = 0u; n < tChannels; ++n)
1253  {
1255  }
1256 }
1257 
1258 template <unsigned int tChannels>
1260 {
1262 
1263  for (unsigned int n = 0u; n < 256u * tChannels; ++n)
1264  {
1266  }
1267 
1268  return result;
1269 }
1270 
1271 template <unsigned int tChannels>
1273  HistogramBase8BitPerChannel<tChannels>()
1274 {
1275  // nothing to do here
1276 }
1277 
1278 template <unsigned int tChannels>
1280  HistogramBase8BitPerChannel<tChannels>()
1281 {
1282  for (unsigned int c = 0u; c < tChannels; ++c)
1283  {
1284  const unsigned int* const bins = histogram.bins(c);
1285  unsigned int* const thisBins = HistogramBase8BitPerChannel<tChannels>::histogramBins + 256u * c;
1286 
1287  // copy the first bin
1288  thisBins[0] = bins[0];
1289 
1290  // copy and increment the remaining bins
1291  for (unsigned int b = 1u; b < 256u; ++b)
1292  {
1293  thisBins[b] = thisBins[b - 1u] + bins[b];
1294  }
1295  }
1296 
1297 #ifdef OCEAN_DEBUG
1298 
1299  // check whether the increment values are identical
1300  for (unsigned int c = 1u; c < tChannels; ++c)
1301  {
1303  }
1304 
1305 #endif // OCEAN_DEBUG
1306 }
1307 
1308 template <unsigned int tChannels>
1310 {
1312 
1314 
1315  for (unsigned int c = 0u; c < tChannels; ++c)
1316  {
1317  for (unsigned int n = 0u; n < 256u; ++n)
1318  {
1319  const unsigned int value = HistogramBase8BitPerChannel<tChannels>::bin(c, (uint8_t)(n));
1320 
1321  for (int r = int(value); r >= 0; --r)
1322  {
1323  if (result.bin(c, (uint8_t)(r)) == 0)
1324  {
1325  result.setBin(c, (uint8_t)(r), n);
1326  }
1327  else
1328  {
1329  break;
1330  }
1331  }
1332  }
1333  }
1334 
1335  return result;
1336 }
1337 
1338 template <unsigned int tChannels>
1340 {
1341  for (unsigned int c = 0u; c < tChannels; ++c)
1342  {
1343  for (unsigned int n = 0u; n < 256u; ++n)
1344  {
1345  lookupData[c * 256u + n] = n;
1346  }
1347  }
1348 }
1349 
1350 template <unsigned int tChannels>
1352 {
1353  ocean_assert(normalizedHistogram.determineHighestValue() <= 255u);
1354  ocean_assert(invertedNormalizedHistogram.determineHighestValue() <= 255u);
1355 
1356  for (unsigned int c = 0u; c < tChannels; ++c)
1357  {
1358  for (unsigned int n = 0u; n < 256u; ++n)
1359  {
1360  lookupData[c * 256u + n] = (uint8_t)(invertedNormalizedHistogram.bin(c, (uint8_t)(normalizedHistogram.bin(c, (uint8_t)(n)))));
1361  }
1362  }
1363 }
1364 
1365 template <unsigned int tChannels>
1366 template <unsigned int tChannel>
1368 {
1369  static_assert(tChannel < tChannels, "Invalid channel!");
1370 
1371  return lookupData[tChannel * 256u + index];
1372 }
1373 
1374 template <unsigned int tChannels>
1375 uint8_t Histogram::LookupTable8BitPerChannel<tChannels>::lookup(const unsigned int channel, const uint8_t index) const
1376 {
1377  ocean_assert(channel < tChannels);
1378 
1379  return lookupData[channel * 256u + index];
1380 }
1381 
1382 template <unsigned int tChannels>
1383 Histogram::Histogram8BitPerChannel<tChannels> Histogram::determineHistogram8BitPerChannel(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, Worker* worker)
1384 {
1385  ocean_assert(frame && width >= 1u && height >= 1u);
1386 
1388 
1389  if (worker)
1390  {
1391  Lock lock;
1392  worker->executeFunction(Worker::Function::createStatic(determineHistogram8BitPerChannelSubset<tChannels>, frame, width, height, &result, &lock, 0u, width, framePaddingElements, 0u, 0u), 0u, height, 8u, 9u, 20u);
1393  }
1394  else
1395  {
1396  if (framePaddingElements == 0u)
1397  {
1398  const uint8_t* const frameEnd = frame + height * width * tChannels;
1399 
1400  while (frame != frameEnd)
1401  {
1402  result.increment(frame);
1403  frame += tChannels;
1404  }
1405  }
1406  else
1407  {
1408  for (unsigned int y = 0u; y < height; ++y)
1409  {
1410  for (unsigned int x = 0u; x < width; ++x)
1411  {
1412  result.increment(frame);
1413  frame += tChannels;
1414  }
1415 
1416  frame += framePaddingElements;
1417  }
1418  }
1419  }
1420 
1421  return result;
1422 }
1423 
1424 template <unsigned int tChannels>
1425 Histogram::Histogram8BitPerChannel<tChannels> Histogram::determineHistogram8BitPerChannel(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const unsigned int framePaddingElements, Worker* worker)
1426 {
1427  ocean_assert(frame && width >= 1u && height >= 1u);
1428 
1429  ocean_assert(subframeLeft + subframeWidth <= width);
1430  ocean_assert(subframeTop + subframeHeight <= height);
1431 
1433 
1434  if (worker)
1435  {
1436  Lock lock;
1437  worker->executeFunction(Worker::Function::createStatic(determineHistogram8BitPerChannelSubset<tChannels>, frame, width, height, &result, &lock, subframeLeft, subframeWidth, framePaddingElements, 0u, 0u), subframeTop, subframeHeight, 8u, 9u, 20u);
1438  }
1439  else
1440  {
1441  determineHistogram8BitPerChannelSubset<tChannels>(frame, width, height, &result, nullptr, subframeLeft, subframeWidth, framePaddingElements, subframeTop, subframeHeight);
1442  }
1443 
1444  return result;
1445 }
1446 
1447 template <unsigned int tChannels>
1448 bool Histogram::adjustColorToReference(uint8_t* frame, const unsigned int frameWidth, const unsigned int frameHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int horizontalBins, const unsigned int verticalBins, const unsigned int framePaddingElements, const unsigned int referencePaddingElements, Worker* worker)
1449 {
1450  ocean_assert(frame != nullptr && reference != nullptr);
1451 
1452  ocean_assert(horizontalBins > 0u && verticalBins > 0u);
1453  ocean_assert(horizontalBins <= min(frameWidth, referenceWidth));
1454  ocean_assert(verticalBins <= min(frameHeight, referenceHeight));
1455 
1456  if (frame == nullptr || reference == nullptr || verticalBins == 0u || horizontalBins == 0u || horizontalBins > frameWidth || horizontalBins > referenceWidth || verticalBins > frameHeight || verticalBins > referenceHeight)
1457  {
1458  return false;
1459  }
1460 
1461  std::vector<LookupTable8BitPerChannel<tChannels>> lookups;
1462  lookups.reserve(horizontalBins * verticalBins);
1463 
1464  // create reference histograms
1465  for (unsigned int y = 0; y < verticalBins; ++y)
1466  {
1467  for (unsigned int x = 0; x < horizontalBins; ++x)
1468  {
1469  const unsigned int referenceBinLeft = x * referenceWidth / horizontalBins;
1470  const unsigned int referenceBinTop = y * referenceHeight / verticalBins;
1471 
1472  const unsigned int referenceBinRight = min((x + 1) * referenceWidth / horizontalBins, referenceWidth);
1473  const unsigned int referenceBinBottom = min((y + 1) * referenceHeight / verticalBins, referenceHeight);
1474 
1475  const unsigned int referenceBinWidth = referenceBinRight - referenceBinLeft;
1476  const unsigned int referenceBinHeight = referenceBinBottom - referenceBinTop;
1477 
1478  IntegralHistogram8BitPerChannel<tChannels> integralReferenceHistogram(determineHistogram8BitPerChannel<tChannels>(reference, referenceWidth, referenceHeight, referenceBinLeft, referenceBinTop, referenceBinWidth, referenceBinHeight, referencePaddingElements, worker));
1479  integralReferenceHistogram.normalize(0xFF);
1480 
1481  const unsigned int frameBinLeft = x * frameWidth / horizontalBins;
1482  const unsigned int frameBinTop = y * frameHeight / verticalBins;
1483 
1484  const unsigned int frameBinRight = min((x + 1) * frameWidth / horizontalBins, frameWidth);
1485  const unsigned int frameBinBottom = min((y + 1) * frameHeight / verticalBins, frameHeight);
1486 
1487  const unsigned int frameBinWidth = frameBinRight - frameBinLeft;
1488  const unsigned int frameBinHeight = frameBinBottom - frameBinTop;
1489 
1490  IntegralHistogram8BitPerChannel<tChannels> frameHistogram(determineHistogram8BitPerChannel<tChannels>(frame, frameWidth, frameHeight, frameBinLeft, frameBinTop, frameBinWidth, frameBinHeight, framePaddingElements, worker));
1491  frameHistogram.normalize(0xFF);
1492 
1493  lookups.push_back(LookupTable8BitPerChannel<tChannels>(frameHistogram, integralReferenceHistogram.invert()));
1494  }
1495  }
1496 
1497  const unsigned int frameStrideElements = frameWidth * tChannels + framePaddingElements;
1498 
1499  for (unsigned int y = 0u; y < frameHeight; ++y)
1500  {
1501  for (unsigned int x = 0u; x < frameWidth; ++x)
1502  {
1503  const unsigned int xBin = (x * horizontalBins) / frameWidth;
1504  const unsigned int yBin = (y * verticalBins) / frameHeight;
1505 
1506  const unsigned int xBinCenter = (xBin * frameWidth / horizontalBins + min((xBin + 1u) * frameWidth / horizontalBins, frameWidth)) / 2u;
1507  const unsigned int yBinCenter = (yBin * frameHeight / verticalBins + min((yBin + 1u) * frameHeight / verticalBins, frameHeight)) / 2u;
1508 
1509  ocean_assert(xBinCenter < frameWidth);
1510  ocean_assert(yBinCenter < frameHeight);
1511 
1512  const unsigned int xLowBin = (x >= xBinCenter) ? xBin : max(0, int(xBin) - 1);
1513  const unsigned int xHighBin = (x < xBinCenter) ? xBin : min(xLowBin + 1u, horizontalBins - 1u);
1514 
1515  const unsigned int yLowBin = (y >= yBinCenter) ? yBin : max(0, int(yBin) - 1);
1516  const unsigned int yHighBin = (y < yBinCenter) ? yBin : min(yLowBin + 1u, verticalBins - 1u);
1517 
1518  ocean_assert(((xLowBin == 0u || xLowBin == horizontalBins - 1u) && xHighBin == xLowBin) || xLowBin + 1u == xHighBin);
1519  ocean_assert(((yLowBin == 0u || yLowBin == verticalBins - 1u) && yHighBin == yLowBin) || yLowBin + 1u == yHighBin);
1520 
1521  const unsigned int leftCenter = (xLowBin * frameWidth / horizontalBins + min((xLowBin + 1u) * frameWidth / horizontalBins, frameWidth)) / 2u;
1522  const unsigned int rightCenter = (xHighBin * frameWidth / horizontalBins + min((xHighBin + 1u) * frameWidth / horizontalBins, frameWidth)) / 2u;
1523 
1524  const unsigned int topCenter = (yLowBin * frameHeight / verticalBins + min((yLowBin + 1u) * frameHeight / verticalBins, frameHeight)) / 2u;
1525  const unsigned int bottomCenter = (yHighBin * frameHeight / verticalBins + min((yHighBin + 1u) * frameHeight / verticalBins, frameHeight)) / 2u;
1526 
1527 
1528  ocean_assert(leftCenter <= rightCenter);
1529  ocean_assert(topCenter <= bottomCenter);
1530 
1531  const unsigned int centerWidth = rightCenter - leftCenter;
1532  const unsigned int centerHeight = bottomCenter - topCenter;
1533 
1534  const unsigned int xFactor = centerWidth != 0u ? (abs(int(x) - int(leftCenter)) * 256u + centerWidth / 2u) / centerWidth : 256u;
1535  const unsigned int yFactor = centerHeight != 0u ? (abs(int(y) - int(topCenter)) * 256u + centerHeight / 2u) / centerHeight : 256u;
1536 
1537  ocean_assert(xFactor <= 256u);
1538  ocean_assert(yFactor <= 256u);
1539 
1540  uint8_t* const framePixel = frame + y * frameStrideElements + x * tChannels;
1541 
1542  const LookupTable8BitPerChannel<tChannels>& topLeft = lookups[yLowBin * horizontalBins + xLowBin];
1543  const LookupTable8BitPerChannel<tChannels>& topRight = lookups[yLowBin * horizontalBins + xHighBin];
1544  const LookupTable8BitPerChannel<tChannels>& bottomLeft = lookups[yHighBin * horizontalBins + xLowBin];
1545  const LookupTable8BitPerChannel<tChannels>& bottomRight = lookups[yHighBin * horizontalBins + xHighBin];
1546 
1547  const unsigned int factorTopLeft = (256u - xFactor) * (256u - yFactor);
1548  const unsigned int factorTopRight = xFactor * (256u - yFactor);
1549  const unsigned int factorBottomLeft = (256u - xFactor) * yFactor;
1550  const unsigned int factorBottomRight = xFactor * yFactor;
1551 
1552  for (unsigned int n = 0u; n < tChannels; ++n)
1553  {
1554  const uint8_t value = framePixel[n];
1555 
1556  framePixel[n] = (uint8_t)((topLeft.lookup(n, value) * factorTopLeft + topRight.lookup(n, value) * factorTopRight
1557  + bottomLeft.lookup(n, value) * factorBottomLeft + bottomRight.lookup(n, value) * factorBottomRight + 32768u) >> 16u); // / 65536;
1558  }
1559  }
1560  }
1561 
1562  return true;
1563 }
1564 
1565 template <unsigned int tChannels>
1566 inline bool Histogram::equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const Scalar factor, const unsigned int framePaddingElements, Worker* worker)
1567 {
1568  ocean_assert(frame && width > 0u && height > 0u);
1569  ocean_assert(factor >= 0 && factor <= 1);
1570 
1571  if (factor < 0 || factor > 1)
1572  {
1573  return false;
1574  }
1575 
1576  IntegralHistogram8BitPerChannel<tChannels> integralHistogram(determineHistogram8BitPerChannel<tChannels>(frame, width, height, framePaddingElements, worker));
1577  integralHistogram.normalize(0xFF);
1578 
1579  return equalization<tChannels>(frame, width, height, integralHistogram, factor, framePaddingElements, worker);
1580 }
1581 
1582 template <unsigned int tChannels>
1583 inline bool Histogram::equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
1584 {
1585  ocean_assert(source && target && width > 0u && height > 0u);
1586  ocean_assert(factor >= 0 && factor <= 1);
1587 
1588  if (factor < 0 || factor > 1)
1589  {
1590  return false;
1591  }
1592 
1593  IntegralHistogram8BitPerChannel<tChannels> integralHistogram(determineHistogram8BitPerChannel<tChannels>(source, width, height, sourcePaddingElements, worker));
1594  integralHistogram.normalize(0xFF);
1595 
1596  return equalization<tChannels>(source, target, width, height, integralHistogram, factor, sourcePaddingElements, targetPaddingElements, worker);
1597 }
1598 
1599 template <unsigned int tChannels>
1600 inline bool Histogram::equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int framePaddingElements, Worker* worker)
1601 {
1602  return equalization<tChannels>(frame, width, height, 0u, 0u, width, height, normalizedIntegral, factor, framePaddingElements, worker);
1603 }
1604 
1605 template <unsigned int tChannels>
1606 bool Histogram::equalization(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int framePaddingElements, Worker* worker)
1607 {
1608  ocean_assert(frame && width > 0u && height > 0u);
1609  ocean_assert(factor >= 0 && factor <= 1);
1610 
1611  ocean_assert(subframeLeft + subframeWidth <= width);
1612  ocean_assert(subframeTop + subframeHeight <= height);
1613 
1614  if (factor < 0 || factor > 1 || subframeLeft + subframeWidth > width || subframeTop + subframeHeight > height)
1615  {
1616  return false;
1617  }
1618 
1619  const unsigned int iFactor = (unsigned int)(factor * Scalar(256));
1620 
1621  if (worker)
1622  {
1623  worker->executeFunction(Worker::Function::createStatic(equalizationSubset<tChannels>, frame, width, height, (const IntegralHistogram8BitPerChannel<tChannels>*)&normalizedIntegral, iFactor, subframeLeft, subframeWidth, framePaddingElements, 0u, 0u), 0u, height, 8u, 9u, 20u);
1624  }
1625  else
1626  {
1627  equalizationSubset<tChannels>(frame, width, height, &normalizedIntegral, iFactor, subframeLeft, subframeWidth, framePaddingElements, subframeTop, subframeHeight);
1628  }
1629 
1630  return true;
1631 }
1632 
1633 template <unsigned int tChannels>
1634 inline bool Histogram::equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
1635 {
1636  return equalization<tChannels>(source, target, width, height, 0u, 0u, width, height, normalizedIntegral, factor, sourcePaddingElements, targetPaddingElements, worker);
1637 }
1638 
1639 template <unsigned int tChannels>
1640 bool Histogram::equalization(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& normalizedIntegral, const Scalar factor, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
1641 {
1642  ocean_assert(source && target && width > 0u && height > 0u);
1643  ocean_assert(factor >= 0 && factor <= 1);
1644 
1645  ocean_assert(subframeLeft + subframeWidth <= width);
1646  ocean_assert(subframeTop + subframeHeight <= height);
1647 
1648  if (factor < 0 || factor > 1 || subframeLeft + subframeWidth > width || subframeTop + subframeHeight > height)
1649  {
1650  return false;
1651  }
1652 
1653  const unsigned int iFactor = (unsigned int)(factor * Scalar(256));
1654 
1655  if (worker)
1656  {
1657  worker->executeFunction(Worker::Function::createStatic(equalizationOfTargetSubset<tChannels>, source, target, width, height, &normalizedIntegral, iFactor, subframeLeft, subframeWidth, sourcePaddingElements, targetPaddingElements, 0u, 0u), subframeTop, subframeHeight, 10u, 11u, 20u);
1658  }
1659  else
1660  {
1661  equalizationOfTargetSubset<tChannels>(source, target, width, height, &normalizedIntegral, iFactor, subframeLeft, subframeWidth, sourcePaddingElements, targetPaddingElements, subframeTop, subframeHeight);
1662  }
1663 
1664  return true;
1665 }
1666 
1667 template <unsigned int tChannels>
1668 bool Histogram::adjustColorToReference(uint8_t* frame, const unsigned int frameWidth, const unsigned int frameHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int framePaddingElements, const unsigned int referencePaddingElements, Worker* worker)
1669 {
1670  ocean_assert(frame && reference);
1671 
1672  IntegralHistogram8BitPerChannel<tChannels> integralReferenceHistogram(determineHistogram8BitPerChannel<tChannels>(reference, referenceWidth, referenceHeight, referencePaddingElements, worker));
1673  integralReferenceHistogram.normalize(0xFF);
1674  const IntegralHistogram8BitPerChannel<tChannels> invertedReferenceHistogram(integralReferenceHistogram.invert());
1675 
1676  return adjustColorToReference<tChannels>(frame, frameWidth, frameHeight, invertedReferenceHistogram, framePaddingElements, worker);
1677 }
1678 
1679 template <unsigned int tChannels>
1680 bool Histogram::adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const uint8_t* reference, const unsigned int referenceWidth, const unsigned int referenceHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int referencePaddingElements, Worker* worker)
1681 {
1682  ocean_assert(source && target && reference);
1683 
1684  IntegralHistogram8BitPerChannel<tChannels> integralReferenceHistogram(determineHistogram8BitPerChannel<tChannels>(reference, referenceWidth, referenceHeight, referencePaddingElements, worker));
1685  integralReferenceHistogram.normalize(0xFF);
1686  const IntegralHistogram8BitPerChannel<tChannels> invertedReferenceHistogram(integralReferenceHistogram.invert());
1687 
1688  return adjustColorToReference<tChannels>(source, target, sourceWidth, sourceHeight, invertedReferenceHistogram, sourcePaddingElements, targetPaddingElements, worker);
1689 }
1690 
1691 template <unsigned int tChannels>
1692 inline bool Histogram::adjustColorToReference(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int framePaddingElements, Worker* worker)
1693 {
1694  return adjustColorToReference<tChannels>(frame, width, height, 0u, 0u, width, height, invertedNormalizedReferenceIntegral, framePaddingElements, worker);
1695 }
1696 
1697 template <unsigned int tChannels>
1698 bool Histogram::adjustColorToReference(uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int framePaddingElements, Worker* worker)
1699 {
1700  ocean_assert(frame);
1701 
1702  if (!frame || subframeLeft + subframeWidth > width || subframeTop + subframeHeight > height)
1703  {
1704  return false;
1705  }
1706 
1707  IntegralHistogram8BitPerChannel<tChannels> frameHistogram(determineHistogram8BitPerChannel<tChannels>(frame, width, height, framePaddingElements, worker));
1708  frameHistogram.normalize(0xFF);
1709 
1710  const LookupTable8BitPerChannel<tChannels> lookupTable(frameHistogram, invertedNormalizedReferenceIntegral);
1711 
1712  if (worker)
1713  {
1714  worker->executeFunction(Worker::Function::createStatic(adjustColorToReferenceSubset<tChannels>, frame, width, height, &lookupTable, subframeLeft, subframeWidth, framePaddingElements, 0u, 0u), subframeTop, subframeHeight, 8u, 9u, 20u);
1715  }
1716  else
1717  {
1718  adjustColorToReferenceSubset<tChannels>(frame, width, height, &lookupTable, subframeLeft, subframeWidth, framePaddingElements, subframeTop, subframeHeight);
1719  }
1720 
1721  return true;
1722 }
1723 
1724 template <unsigned int tChannels>
1725 inline bool Histogram::adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
1726 {
1727  return adjustColorToReference<tChannels>(source, target, width, height, 0u, 0u, width, height, invertedNormalizedReferenceIntegral, sourcePaddingElements, targetPaddingElements, worker);
1728 }
1729 
1730 template <unsigned int tChannels>
1731 bool Histogram::adjustColorToReference(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const unsigned int subframeLeft, const unsigned int subframeTop, const unsigned int subframeWidth, const unsigned int subframeHeight, const IntegralHistogram8BitPerChannel<tChannels>& invertedNormalizedReferenceIntegral, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
1732 {
1733  ocean_assert(source && target);
1734 
1735  if (!source || !target || subframeLeft + subframeWidth > width || subframeTop + subframeHeight > height)
1736  {
1737  return false;
1738  }
1739 
1740  IntegralHistogram8BitPerChannel<tChannels> frameHistogram(determineHistogram8BitPerChannel<tChannels>(source, width, height, sourcePaddingElements, worker));
1741  frameHistogram.normalize(0xFF);
1742 
1743  const LookupTable8BitPerChannel<tChannels> lookupTable(frameHistogram, invertedNormalizedReferenceIntegral);
1744 
1745  if (worker)
1746  {
1747  worker->executeFunction(Worker::Function::createStatic(adjustColorToReferenceOfTargetSubset<tChannels>, source, target, width, height, &lookupTable, subframeLeft, subframeWidth, sourcePaddingElements, targetPaddingElements, 0u, 0u), subframeTop, subframeHeight, 9u, 10u, 20u);
1748  }
1749  else
1750  {
1751  adjustColorToReferenceOfTargetSubset<tChannels>(source, target, width, height, &lookupTable, subframeLeft, subframeWidth, sourcePaddingElements, targetPaddingElements, subframeTop, subframeHeight);
1752  }
1753 
1754  return true;
1755 }
1756 
1757 template <unsigned int tChannels>
1758 void Histogram::determineHistogram8BitPerChannelSubset(const uint8_t* frame, const unsigned int width, const unsigned int height, Histogram8BitPerChannel<tChannels>* histogram, Lock* lock, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
1759 {
1760  ocean_assert(frame != nullptr);
1761 
1762  ocean_assert(firstColumn + numberColumns <= width);
1763  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
1764 
1765  Histogram8BitPerChannel<tChannels> localHistogram;
1766 
1767  if (numberColumns == width && framePaddingElements == 0u)
1768  {
1769  ocean_assert(firstColumn == 0u);
1770 
1771  frame += firstRow * width * tChannels;
1772  const uint8_t* const frameEnd = frame + numberRows * width * tChannels;
1773 
1774  while (frame != frameEnd)
1775  {
1776  localHistogram.increment(frame);
1777  frame += tChannels;
1778  }
1779  }
1780  else if (framePaddingElements == 0u)
1781  {
1782 #ifdef OCEAN_DEBUG
1783  const uint8_t* const debugFrame = frame;
1784 #endif
1785 
1786  frame += (firstRow * width + firstColumn) * tChannels;
1787  const uint8_t* const frameEnd = frame + numberRows * width * tChannels;
1788 
1789  const unsigned int rowOffset = (width - numberColumns) * tChannels;
1790 
1791  while (frame != frameEnd)
1792  {
1793  ocean_assert(frame < frameEnd);
1794  ocean_assert((frame - debugFrame) % (width * tChannels) == firstColumn * tChannels);
1795 
1796  const uint8_t* const frameRowEnd = frame + numberColumns * tChannels;
1797 
1798  while (frame != frameRowEnd)
1799  {
1800  ocean_assert(frame < frameEnd);
1801  ocean_assert(frame < frameRowEnd);
1802 
1803  localHistogram.increment(frame);
1804  frame += tChannels;
1805  }
1806 
1807  frame += rowOffset;
1808  }
1809  }
1810  else
1811  {
1812  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1813  frame += firstRow * frameStrideElements + firstColumn * tChannels;
1814 
1815  const unsigned int rowOffset = (width - numberColumns) * tChannels + framePaddingElements;
1816 
1817  for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1818  {
1819  for (unsigned int x = firstColumn; x < firstColumn + numberColumns; ++x)
1820  {
1821  localHistogram.increment(frame);
1822  frame += tChannels;
1823  }
1824 
1825  frame += rowOffset;
1826  }
1827  }
1828 
1829  const OptionalScopedLock scopedLock(lock);
1830  *histogram += localHistogram;
1831 }
1832 
1833 template <unsigned int tChannels>
1834 void Histogram::equalizationSubset(uint8_t* frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>* normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
1835 {
1836  ocean_assert(frame != nullptr && normalizedIntegral != nullptr);
1837  ocean_assert(width > 0u && height > 0u);
1838 
1839  ocean_assert(firstColumn + numberColumns <= width);
1840  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
1841 
1842  ocean_assert(normalizedIntegral->determineHighestValue() <= 0xFFu);
1843 
1844  ocean_assert(factor <= 256u);
1845  const unsigned int factor_ = 256u - factor;
1846 
1847  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1848 
1849  for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1850  {
1851  uint8_t* frameRow = frame + y * frameStrideElements + firstColumn * tChannels;
1852 
1853  for (unsigned int x = 0u; x < numberColumns; ++x)
1854  {
1855  for (unsigned int n = 0u; n < tChannels; ++n)
1856  {
1857  frameRow[n] = (uint8_t)((normalizedIntegral->bin(n, (uint8_t)(frameRow[n])) * factor + frameRow[n] * factor_) >> 8u);
1858  }
1859 
1860  frameRow += tChannels;
1861  }
1862  }
1863 }
1864 
1865 template <unsigned int tChannels>
1866 void Histogram::equalizationOfTargetSubset(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel<tChannels>* normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
1867 {
1868  ocean_assert(source != nullptr && target != nullptr && normalizedIntegral != nullptr);
1869  ocean_assert(width > 0u && height > 0u);
1870 
1871  ocean_assert(firstColumn + numberColumns <= width);
1872  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
1873 
1874  ocean_assert(normalizedIntegral->determineHighestValue() <= 0xFF);
1875 
1876  ocean_assert(factor <= 256u);
1877  const unsigned int factor_ = 256u - factor;
1878 
1879  const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1880  const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
1881 
1882  for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1883  {
1884  const uint8_t* sourceRow = source + y * sourceStrideElements + firstColumn * tChannels;
1885  uint8_t* targtRow = target + y * targetStrideElements + firstColumn * tChannels;
1886 
1887  for (unsigned int x = 0u; x < numberColumns; ++x)
1888  {
1889  for (unsigned int n = 0u; n < tChannels; ++n)
1890  {
1891  targtRow[n] = (uint8_t)((normalizedIntegral->bin(n, sourceRow[n]) * factor + sourceRow[n] * factor_) >> 8u);
1892  }
1893 
1894  sourceRow += tChannels;
1895  targtRow += tChannels;
1896  }
1897  }
1898 }
1899 
1900 template <unsigned int tChannels>
1901 void Histogram::adjustColorToReferenceSubset(uint8_t* frame, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel<tChannels>* lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
1902 {
1903  ocean_assert(frame != nullptr && lookupTable != nullptr);
1904 
1905  ocean_assert(firstColumn + numberColumns <= width);
1906  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
1907 
1908  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1909 
1910  for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1911  {
1912  uint8_t* frameRow = frame + y * frameStrideElements + firstColumn * tChannels;
1913 
1914  for (unsigned int x = 0u; x < numberColumns; ++x)
1915  {
1916  for (unsigned int n = 0u; n < tChannels; ++n)
1917  {
1918  frameRow[n] = lookupTable->lookup(n, frameRow[n]);
1919  }
1920 
1921  frameRow += tChannels;
1922  }
1923  }
1924 }
1925 
1926 template <unsigned int tChannels>
1927 void Histogram::adjustColorToReferenceOfTargetSubset(const uint8_t* source, uint8_t* target, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel<tChannels>* lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
1928 {
1929  ocean_assert(source && target && lookupTable);
1930 
1931  ocean_assert(firstColumn + numberColumns <= width);
1932  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
1933 
1934  const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
1935  const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
1936 
1937  for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
1938  {
1939  const uint8_t* sourceRow = source + y * sourceStrideElements + firstColumn * tChannels;
1940  uint8_t* targetRow = target + y * targetStrideElements + firstColumn * tChannels;
1941 
1942  for (unsigned int x = 0u; x < numberColumns; ++x)
1943  {
1944  for (unsigned int n = 0u; n < tChannels; ++n)
1945  {
1946  targetRow[n] = lookupTable->lookup(n, sourceRow[n]);
1947  }
1948 
1949  sourceRow += tChannels;
1950  targetRow += tChannels;
1951  }
1952  }
1953 }
1954 
1955 } // namespace CV
1956 
1957 } // namespace Ocean
1958 
1959 #endif // META_OCEAN_CV_HISTOGRAM_H
Implementation of Contrast-Limited Adaptive Histogram Equalization (CLAHE).
Definition: Histogram.h:755
static void bilinearInterpolationNEON7BitPrecisionSubset(const uint8_t *const source, const TileLookupCenter2 *lookupCenter2, uint8_t *const target, const uint8_t *const tileLookupTables, const Index32 *const leftBins, const uint8_t *const leftFactors_fixed7, const Index32 *const topBins, const uint8_t *const topFactors_fixed7, const unsigned int sourcePaddingElements=0u, const unsigned int targetPaddingElements=0u, const unsigned int tileStart=0u, const unsigned int tileCount=0u)
Helper function for the histogram normalization by bilinearly interpolating pixels using the CLAHE pe...
LookupCenter2< uint8_t > TileLookupCenter2
Image partitioning and tile boundary lookup.
Definition: Histogram.h:765
static void computeLookupTable(const uint8_t *source, const unsigned int width, const unsigned int height, uint8_t *const lookupTable, const Scalar clipLimit, const unsigned int sourcePaddingElements=0u)
Computation of a lookup table required to normalize an image histogram (used per tile)
Definition: Histogram.h:887
static void bilinearInterpolation7BitPrecisionSubset(const uint8_t *const source, const TileLookupCenter2 *lookupCenter2, uint8_t *const target, const uint8_t *const tileLookupTables, const Index32 *const leftBins, const uint8_t *const leftFactors_fixed7, const unsigned int sourcePaddingElements=0u, const unsigned int targetPaddingElements=0u, const unsigned int rowStart=0u, const unsigned int rowCount=0u)
Integer-based (fixed-point arithmetic) helper function for the histogram normalization by bilinearly ...
static void computeTileLookupTables(const uint8_t *const source, const TileLookupCenter2 &lookupCenter2, std::vector< uint8_t > &tileLookupTables, const Scalar clipLimit, const unsigned int sourcePaddingElements=0u, Worker *worker=nullptr)
Computation of per-tile lookup tables required to normalize an image histogram given a partitioned im...
std::array< unsigned int, histogramSize > TileHistogram
Tile histogram.
Definition: Histogram.h:762
static void bilinearInterpolation(const uint8_t *const source, const TileLookupCenter2 &lookupCenter2, uint8_t *const target, const std::vector< uint8_t > &tileLookupTables, const unsigned int sourcePaddingElements=0u, const unsigned int targetPaddingElements=0u, Worker *worker=nullptr)
Histogram normalization by bilinearly interpolating pixels using the CLAHE per-tile lookup tables.
static void computeTileLookupTablesSubset(const uint8_t *const source, const TileLookupCenter2 *lookupCenter2, uint8_t *const tileLookupTables, const Scalar clipLimit, const unsigned int sourcePaddingElements=0u, const unsigned int firstTile=0u, const unsigned int tileCount=0u)
Helper function for the computation of per-tile lookup tables required to normalize an image histogra...
static void computeLowBilinearInterpolationFactors7BitPrecision(const TileLookupCenter2 &lookupCenter2, const bool isHorizontal, Index32 *lowBins, uint8_t *lowFactors_fixed7)
Computation of the bilinear interpolation parameters for the low bins of an image pixel If isHorizont...
static void equalization8BitPerChannel(const uint8_t *const source, const unsigned int width, const unsigned height, uint8_t *const target, const Scalar clipLimit=Scalar(40), const unsigned int horizontalTiles=8u, const unsigned int verticalTiles=8u, const unsigned int sourcePaddingElements=0u, const unsigned int targetPaddingElements=0u, Worker *worker=nullptr)
Histogram equalization a la CLAHE.
static constexpr unsigned int histogramSize
Number of bins in the tile histograms.
Definition: Histogram.h:759
This class implements a standard histogram object storing 8 bit per channel.
Definition: Histogram.h:208
void incrementBin(const uint8_t index)
Increments a specific bin of this histogram (by one).
Definition: Histogram.h:1232
void increment(const uint8_t *pixel)
Increments all channels of a specific histogram bin (by one).
Definition: Histogram.h:1248
Histogram8BitPerChannel< tChannels > operator+(const Histogram8BitPerChannel< tChannels > &histogram) const
Adds to histogram objects and returns the new histogram.
Definition: Histogram.h:1259
Histogram8BitPerChannel()
Creates a new histogram object and sets all histogram bins to zero.
Definition: Histogram.h:1224
This class implements the base class for all histogram objects holding 8 bit per data channel.
Definition: Histogram.h:41
unsigned int determineHighestValue() const
Determines the highest value within the entire histogram.
unsigned int determineEndBin(const unsigned int channel) const
Determines the last bin that is not zero for a specific channel.
Definition: Histogram.h:1101
void clear()
Clears the entire histogram and sets all bins to zero.
Definition: Histogram.h:1159
void normalize(const unsigned int newMaximalValue)
Normalizes the entire histogram by application of the highest histogram value.
Definition: Histogram.h:1119
unsigned int determineStartBin(const unsigned int channel) const
Determines the first bin that is not zero for a specific channel.
Definition: Histogram.h:1083
void setBin(const unsigned int channel, const uint8_t index, const unsigned int value)
Explicitly sets a value of a specific histogram bin.
Definition: Histogram.h:1202
HistogramBase8BitPerChannel< tChannels > & operator+=(const HistogramBase8BitPerChannel< tChannels > &histogram)
Adds the histogram bins of a second histogram to this histogram.
Definition: Histogram.h:1185
HistogramBase8BitPerChannel()
Creates an empty histogram object and sets all histogram bins to zero.
Definition: Histogram.h:975
const unsigned int * bins() const
Returns the 256 histogram values for a specific channel.
Definition: Histogram.h:1012
unsigned int determineHighestValue() const
Determines the highest value within the histogram for a specific channel.
Definition: Histogram.h:1029
bool isNull() const
Returns whether all bins inside the histogram are zero.
Definition: Histogram.h:1210
const unsigned int * operator()() const
Returns all histogram bins of this histogram.
Definition: Histogram.h:1196
bool operator!=(const HistogramBase8BitPerChannel< tChannels > &histogram) const
Returns whether two histogram objects are not identical according to their histogram bins.
Definition: Histogram.h:1179
unsigned int histogramBins[256u *tChannels]
The histogram bins.
Definition: Histogram.h:199
bool operator==(const HistogramBase8BitPerChannel< tChannels > &histogram) const
Returns whether two histogram objects are identical according to their histogram bins.
Definition: Histogram.h:1165
unsigned int bin() const
Returns the bin value of a specific channel and bin.
unsigned int sumBin(const uint8_t index) const
Returns the sum of all channels stored for a specific bin.
Definition: Histogram.h:998
This class implements an integral histogram object.
Definition: Histogram.h:253
IntegralHistogram8BitPerChannel()
Creates a new integral histogram object and sets all histogram bins to zero.
Definition: Histogram.h:1272
IntegralHistogram8BitPerChannel invert() const
Inverts this (normalized) integral histogram so that the inverted histogram can be used as lookup obj...
Definition: Histogram.h:1309
This class implements a simple lookup table.
Definition: Histogram.h:285
LookupTable8BitPerChannel()
Creates a default lookup table providing the identity lookup result.
Definition: Histogram.h:1339
uint8_t lookup(const uint8_t index) const
Lookup function providing the lookup value for a specific channel and bin.
Definition: Histogram.h:1367
This class implements an image histogram.
Definition: Histogram.h:32
static void adjustColorToReferenceSubset(uint8_t *frame, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel< tChannels > *lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Adjusts the color in a subset of a frame according to a given reference frame.
Definition: Histogram.h:1901
static void equalizationOfTargetSubset(const uint8_t *source, uint8_t *target, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel< tChannels > *normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Applies a histogram equalization in a subset of a given frame.
Definition: Histogram.h:1866
static bool equalization(const Frame &source, Frame &target, const Scalar factor=1, Worker *worker=nullptr)
Applies a histogram equalization for a given frame.
static bool adjustColorToReference(const Frame &source, Frame &target, const Frame &reference, Worker *worker=nullptr)
Adjusts the color of a frame according to a given reference frame.
static bool adjustColorToReference(Frame &frame, const Frame &reference, const unsigned int horizontalBins, const unsigned int verticalBins, Worker *worker=nullptr)
Adjusts the color of a frame according to a given reference frame while using corresponding bins for ...
static Histogram8BitPerChannel< tChannels > determineHistogram8BitPerChannel(const uint8_t *frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, Worker *worker=nullptr)
Determines the standard histogram for a given frame.
Definition: Histogram.h:1383
static bool adjustColorToReference(Frame &frame, const Frame &reference, Worker *worker=nullptr)
Adjusts the color of a frame according to a given reference frame.
static void adjustColorToReferenceOfTargetSubset(const uint8_t *source, uint8_t *target, const unsigned int width, const unsigned int height, const LookupTable8BitPerChannel< tChannels > *lookupTable, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Adjusts the color of a frame according to a given reference frame.
Definition: Histogram.h:1927
static bool equalization(Frame &frame, const Scalar factor=1, Worker *worker=nullptr)
Applies a histogram equalization for a given frame.
static void determineHistogram8BitPerChannelSubset(const uint8_t *frame, const unsigned int width, const unsigned int height, Histogram8BitPerChannel< tChannels > *histogram, Lock *lock, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Determines the standard histogram in a subset of a given frame.
Definition: Histogram.h:1758
static void equalizationSubset(uint8_t *frame, const unsigned int width, const unsigned int height, const IntegralHistogram8BitPerChannel< tChannels > *normalizedIntegral, const unsigned int factor, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int framePaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Applies a histogram equalization in a subset of a given frame.
Definition: Histogram.h:1834
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:1760
This class implements a recursive lock object.
Definition: Lock.h:31
This class implements a 2D lookup object with values at the bins' center positions defining the indiv...
Definition: Lookup2.h:198
This class provides basic numeric functionalities.
Definition: Numeric.h:57
This class implements an optional recursive scoped lock object locking the lock object only if it's d...
Definition: Lock.h:325
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.
uint32_t Index32
Definition of a 32 bit index value.
Definition: Base.h:84
float Scalar
Definition of a scalar type.
Definition: Math.h:128
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15
AutomaticDifferentiationT< T1, TNumeric1 > operator+(const T2 &left, const AutomaticDifferentiationT< T1, TNumeric1 > &right)
Definition: AutomaticDifferentiation.h:418