File indexing completed on 2024-05-12 05:46:27

0001 /*
0002  *  Copyright (c) 2010 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  *
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  * 3. The name of the author may not be used to endorse or promote products
0014  *    derived from this software without specific prior written permission.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifndef _LUT_H_
0029 #define _LUT_H_
0030 
0031 template<typename _InputT_>
0032 class LutKey;
0033 
0034 template<typename _InputT_>
0035 class FullLutKey;
0036 
0037 /**
0038  * Provide an implementation for a look-up table for a function. Do not use directly, instead
0039  * use @ref Lut when you are not interested in having the full look-up table or for floating
0040  * point, or use @ref FullLut for 8bits and 16bits when you want to have a full Lut.
0041  *
0042  * @code
0043  * struct MyFunction {
0044  *  inline static int compute(int i)
0045  *  {
0046  *    return 1-i;
0047  *  }
0048  * }
0049  * Lut<MyFunction, int, int> myLut;
0050  * @endcode
0051  */
0052 template<typename _FunctionT_, typename _OutputT_, typename _InputT_, typename _LutKeyT_ >
0053 class BaseLut {
0054   private:
0055     /**
0056      * Initialization of the table.
0057      */
0058     inline void init()
0059     {
0060       int size = m_key.size();
0061       m_table = new _OutputT_[size];
0062       for(int i = 0; i < size; ++i)
0063       {
0064         m_table[i] = m_function(m_key.keyToInput(i));
0065       }
0066     }
0067   public:
0068     /**
0069      * Create the lut with the specific key.
0070      */
0071     inline BaseLut(_LutKeyT_ key, _FunctionT_ function = _FunctionT_()) : m_key(key), m_function(function)
0072     {
0073       init();
0074     }
0075     inline ~BaseLut() {
0076       // just leak on exit -- we get into trouble for explicitly
0077       // deleting stuff from static objects, like registries
0078       //delete[] m_table;
0079     }
0080   public:
0081     /**
0082      * @return the function value for parameter @p i
0083      */
0084     inline _OutputT_ operator()(_InputT_ i) const
0085     {
0086       if(m_key.inrange(i))
0087       {
0088         return m_table[m_key.inputToKey(i)];
0089       }
0090       return m_function(i);
0091     }
0092   private:
0093     _OutputT_* m_table;
0094     _LutKeyT_ m_key;
0095     _FunctionT_ m_function;
0096 };
0097 
0098 /**
0099  * This Lut is limited to a range of values.
0100  */
0101 template<typename _FunctionT_, typename _OutputT_, typename _InputT_>
0102 class Lut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> > {
0103   public:
0104     /**
0105      * Create the lut between @p _min and @p _max .
0106      */
0107     inline Lut(_InputT_ _min, _InputT_ _max, _FunctionT_ function = _FunctionT_()) :
0108         BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( LutKey<_InputT_>(_min, _max), function)
0109     {
0110     }
0111     inline Lut(LutKey<_InputT_> key, _FunctionT_ function = _FunctionT_()) :
0112         BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( key, function)
0113     {
0114     }
0115 };
0116 
0117 /**
0118  * This Lut has precomputed values for all elements.
0119  */
0120 template<typename _FunctionT_, typename _OutputT_, typename _InputT_>
0121 class FullLut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> > {
0122   public:
0123     inline FullLut( _FunctionT_ function = _FunctionT_()) :
0124         BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> >( FullLutKey<_InputT_>(), function)
0125     {
0126     }
0127 };
0128 
0129 #ifdef _USE_QT_TYPES_
0130 typedef quint8 lut_uint8;
0131 typedef quint16 lut_uint16;
0132 typedef quint32 lut_uint32;
0133 #else
0134 #include <stdint.h>
0135 typedef uint8_t lut_uint8;
0136 typedef uint16_t lut_uint16;
0137 typedef uint32_t lut_uint32;
0138 #endif
0139 
0140 // integer specialization
0141 
0142 #define PARTIAL_LUT_INT_SPECIALIZATION(_INT_TYPE_)                                \
0143   template<>                                                                      \
0144   class LutKey<_INT_TYPE_> {                                               \
0145     public:                                                                       \
0146       LutKey<_INT_TYPE_>(_INT_TYPE_ min, _INT_TYPE_ max) : m_min(min), m_max(max) \
0147       {                                                                           \
0148       }                                                                           \
0149     public:                                                                       \
0150       inline int inputToKey(_INT_TYPE_ i) const                                   \
0151       {                                                                           \
0152         return i - m_min;                                                         \
0153       }                                                                           \
0154       inline _INT_TYPE_ keyToInput(int k) const                                   \
0155       {                                                                           \
0156         return k + m_min;                                                         \
0157       }                                                                           \
0158       inline bool inrange(_INT_TYPE_ i) const                                     \
0159       {                                                                           \
0160         return i >= m_min && i <= m_max;                                          \
0161       }                                                                           \
0162       inline _INT_TYPE_ minimum() const                                           \
0163       {                                                                           \
0164         return m_min;                                                             \
0165       }                                                                           \
0166       inline _INT_TYPE_ maximum() const                                           \
0167       {                                                                           \
0168         return m_max;                                                             \
0169       }                                                                           \
0170       inline int size() const                                                     \
0171       {                                                                           \
0172         return m_max - m_min + 1;                                                 \
0173       }                                                                           \
0174     private:                                                                      \
0175       _INT_TYPE_ m_min, m_max;                                                    \
0176   };
0177 
0178 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint8)
0179 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint16)
0180 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint32)
0181 
0182 #define FULL_LUT_INT_SPECIALIZATION(_INT_TYPE_, _MIN_, _MAX_)                     \
0183   template<>                                                                      \
0184   class FullLutKey<_INT_TYPE_> {                                                  \
0185     public:                                                                       \
0186       FullLutKey<_INT_TYPE_>()                                                    \
0187       {                                                                           \
0188       }                                                                           \
0189     public:                                                                       \
0190       inline int inputToKey(_INT_TYPE_ i) const                                   \
0191       {                                                                           \
0192         return i - _MIN_;                                                         \
0193       }                                                                           \
0194       inline _INT_TYPE_ keyToInput(int k) const                                   \
0195       {                                                                           \
0196         return k + _MIN_;                                                         \
0197       }                                                                           \
0198       inline bool inrange(_INT_TYPE_ ) const                                      \
0199       {                                                                           \
0200         return true;                                                              \
0201       }                                                                           \
0202       inline _INT_TYPE_ minimum() const                                           \
0203       {                                                                           \
0204         return _MIN_;                                                             \
0205       }                                                                           \
0206       inline _INT_TYPE_ maximum() const                                           \
0207       {                                                                           \
0208         return _MAX_;                                                             \
0209       }                                                                           \
0210       inline int size() const                                                     \
0211       {                                                                           \
0212         return _MAX_ - _MIN_ + 1;                                                 \
0213       }                                                                           \
0214     private:                                                                      \
0215   };
0216 
0217 FULL_LUT_INT_SPECIALIZATION(lut_uint8, 0, 255)
0218 FULL_LUT_INT_SPECIALIZATION(lut_uint16, 0, 65535)
0219 
0220 // float specialization
0221 
0222 /**
0223  * This provide an implementation for a LutKey for floating point input values.
0224  *
0225  * Based on "High-speed Conversion of Floating Point Images to 8-bit" by Bill Spitzaks
0226  * (https://spitzak.github.io/conversion/sketches_0265.pdf)
0227  */
0228 template<>
0229 class LutKey<float> {
0230   public:
0231     union IFNumber {
0232       lut_uint32 i;
0233       float f;
0234     };
0235   public:
0236     LutKey<float>(float min, float max, float precision) : m_min(min), m_max(max), m_precision(precision)
0237     {
0238       // Those values where computed using the test_linear and setting the shift and then using
0239       // the standard deviation.
0240       if (precision <= 0.000011809f) {
0241         m_min =  1;
0242         m_max = -1;
0243       }
0244       else if (precision <= 0.0000237291f) m_shift =  8;
0245       else if (precision <= 0.0000475024f) m_shift =  9;
0246       else if (precision <= 0.0000948575f) m_shift = 10;
0247       else if (precision <= 0.00019013f) m_shift = 11;
0248       else if (precision <= 0.000379523f) m_shift = 12;
0249       else if (precision <= 0.000758431f) m_shift = 13;
0250       else if (precision <= 0.00151891f) m_shift = 14;
0251       else if (precision <= 0.00303725f) m_shift = 15;
0252       else m_shift = 16;
0253 
0254       if ( 0.0 <= m_min && m_min <= precision)
0255         m_min = precision;
0256       if ( -precision <= m_max && m_max <= 0.0)
0257         m_max = -precision;
0258       
0259       IFNumber uf;
0260       
0261       if(m_min > 0 && m_max > 0)
0262       {
0263         uf.f = m_min;
0264         m_tMin_p = uf.i >> m_shift;
0265         uf.f = m_max;
0266         m_tMax_p = uf.i >> m_shift;
0267         m_tMin_n = m_tMax_p;
0268         m_tMax_n = m_tMax_p;
0269      } else if( m_max < 0)
0270       {
0271         uf.f = m_min;
0272         m_tMax_n = uf.i >> m_shift;
0273         uf.f = m_max;
0274         m_tMin_n = uf.i >> m_shift;
0275         m_tMin_p = m_tMax_n;
0276         m_tMax_p = m_tMax_n;
0277       } else { // m_min <0 && m_max > 0
0278         uf.f = precision;
0279         m_tMin_p = uf.i >> m_shift;
0280         uf.f = m_max;
0281         m_tMax_p = uf.i >> m_shift;
0282         uf.f = -precision;
0283         m_tMin_n = uf.i >> m_shift;
0284         uf.f = m_min;
0285         m_tMax_n = uf.i >> m_shift;
0286       }
0287       m_diff_p = m_tMax_p - m_tMin_p;
0288     }
0289   public:
0290     inline int inputToKey(float i) const
0291     {
0292       IFNumber uf;
0293       uf.f = i;
0294       int k = (uf.i >> m_shift);
0295       if(k <= m_tMax_p)
0296       {
0297         return k - m_tMin_p;
0298       } else {
0299         return k - m_tMin_n + m_diff_p;
0300       }
0301     }
0302     inline float keyToInput(int k) const
0303     {
0304       IFNumber uf;
0305       if( k <= m_diff_p ) {
0306         uf.i = ((k + m_tMin_p) << m_shift);
0307       } else {
0308         uf.i = ((k + m_tMin_n - m_diff_p ) << m_shift);
0309       }
0310       return uf.f;
0311     }
0312     inline bool inrange(float i) const
0313     {
0314        return i >= m_min && i <= m_max && (i < -m_precision || i > m_precision);
0315     }
0316     inline float minimum() const
0317     {
0318       return m_min;
0319     }
0320     inline float maximum() const
0321     {
0322       return m_max;
0323     }
0324     inline int size() const
0325     {
0326       return m_diff_p + m_tMax_n - m_tMin_p + 1;
0327     }
0328   private:
0329     float m_min, m_max, m_precision;
0330     int m_tMin_p, m_tMax_p, m_tMin_n, m_tMax_n, m_diff_p;
0331     int m_shift;
0332 };
0333 
0334 #endif