File indexing completed on 2024-05-12 15:59:38

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * SPDX-License-Identifier: BSD-3-Clause
0005  */
0006 
0007 #ifndef _LUT_H_
0008 #define _LUT_H_
0009 
0010 template<typename _InputT_>
0011 class LutKey;
0012 
0013 template<typename _InputT_>
0014 class FullLutKey;
0015 
0016 /**
0017  * Provide an implementation for a look-up table for a function. Do not use directly, instead
0018  * use @ref Lut when you are not interested in having the full look-up table or for floating
0019  * point, or use @ref FullLut for 8bits and 16bits when you want to have a full Lut.
0020  *
0021  * @code
0022  * struct MyFunction {
0023  *  inline static int compute(int i)
0024  *  {
0025  *    return 1-i;
0026  *  }
0027  * }
0028  * Lut<MyFunction, int, int> myLut;
0029  * @endcode
0030  */
0031 template<typename _FunctionT_, typename _OutputT_, typename _InputT_, typename _LutKeyT_ >
0032 class BaseLut {
0033   private:
0034     /**
0035      * Initialization of the table.
0036      */
0037     inline void init()
0038     {
0039       int size = m_key.size();
0040       m_table = new _OutputT_[size];
0041       for(int i = 0; i < size; ++i)
0042       {
0043         m_table[i] = m_function(m_key.keyToInput(i));
0044       }
0045     }
0046   public:
0047     /**
0048      * Create the lut with the specific key.
0049      */
0050     inline BaseLut(_LutKeyT_ key, _FunctionT_ function = _FunctionT_()) : m_key(key), m_function(function)
0051     {
0052       init();
0053     }
0054     inline ~BaseLut() {
0055       // just leak on exit -- we get into trouble for explicitly
0056       // deleting stuff from static objects, like registries
0057       //delete[] m_table;
0058     }
0059   public:
0060     /**
0061      * @return the function value for parameter @p i
0062      */
0063     inline _OutputT_ operator()(_InputT_ i) const
0064     {
0065       if(m_key.inrange(i))
0066       {
0067         return m_table[m_key.inputToKey(i)];
0068       }
0069       return m_function(i);
0070     }
0071   private:
0072     _OutputT_* m_table;
0073     _LutKeyT_ m_key;
0074     _FunctionT_ m_function;
0075 };
0076 
0077 /**
0078  * This Lut is limited to a range of values.
0079  */
0080 template<typename _FunctionT_, typename _OutputT_, typename _InputT_>
0081 class Lut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> > {
0082   public:
0083     /**
0084      * Create the lut between @p _min and @p _max .
0085      */
0086     inline Lut(_InputT_ _min, _InputT_ _max, _FunctionT_ function = _FunctionT_()) :
0087         BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( LutKey<_InputT_>(_min, _max), function)
0088     {
0089     }
0090     inline Lut(LutKey<_InputT_> key, _FunctionT_ function = _FunctionT_()) :
0091         BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( key, function)
0092     {
0093     }
0094 };
0095 
0096 /**
0097  * This Lut has precomputed values for all elements.
0098  */
0099 template<typename _FunctionT_, typename _OutputT_, typename _InputT_>
0100 class FullLut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> > {
0101   public:
0102     inline FullLut( _FunctionT_ function = _FunctionT_()) :
0103         BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> >( FullLutKey<_InputT_>(), function)
0104     {
0105     }
0106 };
0107 
0108 #ifdef _USE_QT_TYPES_
0109 typedef quint8 lut_uint8;
0110 typedef quint16 lut_uint16;
0111 typedef quint32 lut_uint32;
0112 #else
0113 #include <stdint.h>
0114 typedef uint8_t lut_uint8;
0115 typedef uint16_t lut_uint16;
0116 typedef uint32_t lut_uint32;
0117 #endif
0118 
0119 // integer specialization
0120 
0121 #define PARTIAL_LUT_INT_SPECIALIZATION(_INT_TYPE_)                                \
0122   template<>                                                                      \
0123   class LutKey<_INT_TYPE_> {                                               \
0124     public:                                                                       \
0125       LutKey<_INT_TYPE_>(_INT_TYPE_ min, _INT_TYPE_ max) : m_min(min), m_max(max) \
0126       {                                                                           \
0127       }                                                                           \
0128     public:                                                                       \
0129       inline int inputToKey(_INT_TYPE_ i) const                                   \
0130       {                                                                           \
0131         return i - m_min;                                                         \
0132       }                                                                           \
0133       inline _INT_TYPE_ keyToInput(int k) const                                   \
0134       {                                                                           \
0135         return k + m_min;                                                         \
0136       }                                                                           \
0137       inline bool inrange(_INT_TYPE_ i) const                                     \
0138       {                                                                           \
0139         return i >= m_min && i <= m_max;                                          \
0140       }                                                                           \
0141       inline _INT_TYPE_ minimum() const                                           \
0142       {                                                                           \
0143         return m_min;                                                             \
0144       }                                                                           \
0145       inline _INT_TYPE_ maximum() const                                           \
0146       {                                                                           \
0147         return m_max;                                                             \
0148       }                                                                           \
0149       inline int size() const                                                     \
0150       {                                                                           \
0151         return m_max - m_min + 1;                                                 \
0152       }                                                                           \
0153     private:                                                                      \
0154       _INT_TYPE_ m_min, m_max;                                                    \
0155   };
0156 
0157 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint8)
0158 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint16)
0159 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint32)
0160 
0161 #define FULL_LUT_INT_SPECIALIZATION(_INT_TYPE_, _MIN_, _MAX_)                     \
0162   template<>                                                                      \
0163   class FullLutKey<_INT_TYPE_> {                                                  \
0164     public:                                                                       \
0165       FullLutKey<_INT_TYPE_>()                                                    \
0166       {                                                                           \
0167       }                                                                           \
0168     public:                                                                       \
0169       inline int inputToKey(_INT_TYPE_ i) const                                   \
0170       {                                                                           \
0171         return i - _MIN_;                                                         \
0172       }                                                                           \
0173       inline _INT_TYPE_ keyToInput(int k) const                                   \
0174       {                                                                           \
0175         return k + _MIN_;                                                         \
0176       }                                                                           \
0177       inline bool inrange(_INT_TYPE_ ) const                                      \
0178       {                                                                           \
0179         return true;                                                              \
0180       }                                                                           \
0181       inline _INT_TYPE_ minimum() const                                           \
0182       {                                                                           \
0183         return _MIN_;                                                             \
0184       }                                                                           \
0185       inline _INT_TYPE_ maximum() const                                           \
0186       {                                                                           \
0187         return _MAX_;                                                             \
0188       }                                                                           \
0189       inline int size() const                                                     \
0190       {                                                                           \
0191         return _MAX_ - _MIN_ + 1;                                                 \
0192       }                                                                           \
0193     private:                                                                      \
0194   };
0195 
0196 FULL_LUT_INT_SPECIALIZATION(lut_uint8, 0, 255)
0197 FULL_LUT_INT_SPECIALIZATION(lut_uint16, 0, 65535)
0198 
0199 // float specialization
0200 
0201 /**
0202  * This provide an implementation for a LutKey for floating point input values.
0203  *
0204  * Based on "High-speed Conversion of Floating Point Images to 8-bit" by Bill Spitzaks
0205  * (https://spitzak.github.io/conversion/sketches_0265.pdf)
0206  */
0207 template<>
0208 class LutKey<float> {
0209   public:
0210     union IFNumber {
0211       lut_uint32 i;
0212       float f;
0213     };
0214   public:
0215     LutKey<float>(float min, float max, float precision) : m_min(min), m_max(max), m_precision(precision)
0216     {
0217       // Those values where computed using the test_linear and setting the shift and then using
0218       // the standard deviation.
0219       if (precision <= 0.000011809f) {
0220         m_min =  1;
0221         m_max = -1;
0222       }
0223       else if (precision <= 0.0000237291f) m_shift =  8;
0224       else if (precision <= 0.0000475024f) m_shift =  9;
0225       else if (precision <= 0.0000948575f) m_shift = 10;
0226       else if (precision <= 0.00019013f) m_shift = 11;
0227       else if (precision <= 0.000379523f) m_shift = 12;
0228       else if (precision <= 0.000758431f) m_shift = 13;
0229       else if (precision <= 0.00151891f) m_shift = 14;
0230       else if (precision <= 0.00303725f) m_shift = 15;
0231       else m_shift = 16;
0232 
0233       if ( 0.0 <= m_min && m_min <= precision)
0234         m_min = precision;
0235       if ( -precision <= m_max && m_max <= 0.0)
0236         m_max = -precision;
0237       
0238       IFNumber uf;
0239       
0240       if(m_min > 0 && m_max > 0)
0241       {
0242         uf.f = m_min;
0243         m_tMin_p = uf.i >> m_shift;
0244         uf.f = m_max;
0245         m_tMax_p = uf.i >> m_shift;
0246         m_tMin_n = m_tMax_p;
0247         m_tMax_n = m_tMax_p;
0248      } else if( m_max < 0)
0249       {
0250         uf.f = m_min;
0251         m_tMax_n = uf.i >> m_shift;
0252         uf.f = m_max;
0253         m_tMin_n = uf.i >> m_shift;
0254         m_tMin_p = m_tMax_n;
0255         m_tMax_p = m_tMax_n;
0256       } else { // m_min <0 && m_max > 0
0257         uf.f = precision;
0258         m_tMin_p = uf.i >> m_shift;
0259         uf.f = m_max;
0260         m_tMax_p = uf.i >> m_shift;
0261         uf.f = -precision;
0262         m_tMin_n = uf.i >> m_shift;
0263         uf.f = m_min;
0264         m_tMax_n = uf.i >> m_shift;
0265       }
0266       m_diff_p = m_tMax_p - m_tMin_p;
0267     }
0268   public:
0269     inline int inputToKey(float i) const
0270     {
0271       IFNumber uf;
0272       uf.f = i;
0273       int k = (uf.i >> m_shift);
0274       if(k <= m_tMax_p)
0275       {
0276         return k - m_tMin_p;
0277       } else {
0278         return k - m_tMin_n + m_diff_p;
0279       }
0280     }
0281     inline float keyToInput(int k) const
0282     {
0283       IFNumber uf;
0284       if( k <= m_diff_p ) {
0285         uf.i = ((k + m_tMin_p) << m_shift);
0286       } else {
0287         uf.i = ((k + m_tMin_n - m_diff_p ) << m_shift);
0288       }
0289       return uf.f;
0290     }
0291     inline bool inrange(float i) const
0292     {
0293        return i >= m_min && i <= m_max && (i < -m_precision || i > m_precision);
0294     }
0295     inline float minimum() const
0296     {
0297       return m_min;
0298     }
0299     inline float maximum() const
0300     {
0301       return m_max;
0302     }
0303     inline int size() const
0304     {
0305       return m_diff_p + m_tMax_n - m_tMin_p + 1;
0306     }
0307   private:
0308     float m_min, m_max, m_precision;
0309     int m_tMin_p, m_tMax_p, m_tMin_n, m_tMax_n, m_diff_p;
0310     int m_shift;
0311 };
0312 
0313 #endif