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