2022-07-25 09:25:14 -04:00
|
|
|
//
|
|
|
|
// FILE: gamma.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
2023-01-26 13:56:10 -05:00
|
|
|
// VERSION: 0.4.0
|
2022-07-25 09:25:14 -04:00
|
|
|
// DATE: 2020-08-08
|
|
|
|
// PURPOSE: Arduino Library to efficiently hold a gamma lookup table
|
|
|
|
|
|
|
|
|
|
|
|
#include "gamma.h"
|
|
|
|
|
|
|
|
|
|
|
|
GAMMA::GAMMA(uint16_t size)
|
|
|
|
{
|
|
|
|
_shift = 7;
|
2022-11-08 11:03:54 -05:00
|
|
|
// force power of 2; get shift & mask right
|
2022-07-25 09:25:14 -04:00
|
|
|
for (uint16_t s = 2; s <= GAMMA_MAX_SIZE; s <<= 1)
|
|
|
|
{
|
|
|
|
if (size <= s)
|
|
|
|
{
|
|
|
|
_size = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_shift--;
|
|
|
|
}
|
|
|
|
_mask = (1 << _shift) - 1;
|
|
|
|
_interval = GAMMA_MAX_SIZE / _size;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GAMMA::~GAMMA()
|
|
|
|
{
|
|
|
|
if (_table) free(_table);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
bool GAMMA::begin()
|
2022-07-25 09:25:14 -04:00
|
|
|
{
|
|
|
|
if (_table == NULL)
|
|
|
|
{
|
2023-01-26 13:56:10 -05:00
|
|
|
_table = (uint8_t *) malloc(_size + 1);
|
2022-07-25 09:25:14 -04:00
|
|
|
}
|
2022-07-26 07:16:03 -04:00
|
|
|
if (_table == NULL) return false;
|
2022-07-25 09:25:14 -04:00
|
|
|
setGamma(2.8);
|
2022-07-26 07:16:03 -04:00
|
|
|
return true;
|
2022-07-25 09:25:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
bool GAMMA::setGamma(float gamma)
|
2022-07-25 09:25:14 -04:00
|
|
|
{
|
2022-07-26 07:16:03 -04:00
|
|
|
if (_table == NULL) return false;
|
|
|
|
if (gamma <= 0) return false;
|
2022-07-25 09:25:14 -04:00
|
|
|
if (_gamma != gamma)
|
|
|
|
{
|
2023-01-26 13:56:10 -05:00
|
|
|
yield(); // try to keep ESP happy
|
2022-07-25 09:25:14 -04:00
|
|
|
_gamma = gamma;
|
2023-01-26 13:56:10 -05:00
|
|
|
#if defined(ESP32)
|
|
|
|
// confirmed faster for ESP32.
|
|
|
|
float tmp = log(_interval / 255.0);
|
|
|
|
for (uint16_t i = 1; i < _size; i++)
|
|
|
|
{
|
|
|
|
float x = log(i) + tmp;
|
|
|
|
_table[i] = exp(x * _gamma) * 255 + 0.444;
|
|
|
|
}
|
|
|
|
#else
|
2022-07-25 09:25:14 -04:00
|
|
|
// REFERENCE
|
2022-07-26 07:16:03 -04:00
|
|
|
// rounding factor 0.444 optimized with error example.
|
2023-01-26 13:56:10 -05:00
|
|
|
float tmp = (_interval / 255.0);
|
2022-07-26 07:16:03 -04:00
|
|
|
for (uint16_t i = 1; i < _size; i++)
|
2022-07-25 09:25:14 -04:00
|
|
|
{
|
2023-01-26 13:56:10 -05:00
|
|
|
_table[i] = pow(i * tmp, _gamma) * 255 + 0.444;
|
2022-07-25 09:25:14 -04:00
|
|
|
}
|
2023-01-26 13:56:10 -05:00
|
|
|
#endif
|
2022-07-26 07:16:03 -04:00
|
|
|
_table[0] = 0;
|
2023-01-26 13:56:10 -05:00
|
|
|
_table[_size] = 255; // anchor for interpolation.
|
2022-07-25 09:25:14 -04:00
|
|
|
}
|
2022-07-26 07:16:03 -04:00
|
|
|
return true;
|
2022-07-25 09:25:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
float GAMMA::getGamma()
|
|
|
|
{
|
|
|
|
return _gamma;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t GAMMA::operator[] (uint8_t index)
|
|
|
|
{
|
2022-07-26 07:16:03 -04:00
|
|
|
// 0.3.0 _table test slows performance ~0.4 us.
|
|
|
|
if (_table == NULL) return 0;
|
2022-07-25 09:25:14 -04:00
|
|
|
if (_interval == 1) return _table[index];
|
2023-01-26 13:56:10 -05:00
|
|
|
|
|
|
|
// else interpolate
|
|
|
|
#if defined(ESP32)
|
|
|
|
uint32_t i = index >> _shift;
|
|
|
|
uint32_t m = index & _mask;
|
|
|
|
// exact element shortcut
|
|
|
|
if ( m == 0 ) return _table[i];
|
|
|
|
|
|
|
|
// interpolation
|
|
|
|
// delta must be uint16_t to prevent overflow. (small tables)
|
|
|
|
// delta * m can be > 8 bit.
|
|
|
|
uint32_t delta = _table[i+1] - _table[i];
|
|
|
|
delta = ( delta * m + _interval/2 ) >> _shift; // == /_interval;
|
|
|
|
return _table[i] + delta;
|
|
|
|
|
|
|
|
#else
|
|
|
|
uint16_t i = index >> _shift;
|
|
|
|
uint16_t m = index & _mask;
|
|
|
|
// exact element shortcut
|
2022-07-25 09:25:14 -04:00
|
|
|
if ( m == 0 ) return _table[i];
|
2023-01-26 13:56:10 -05:00
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
// interpolation
|
|
|
|
// delta must be uint16_t to prevent overflow. (small tables)
|
|
|
|
// delta * m can be > 8 bit.
|
2022-07-25 09:25:14 -04:00
|
|
|
uint16_t delta = _table[i+1] - _table[i];
|
2023-01-26 13:56:10 -05:00
|
|
|
// for AVR UNO this speeds up
|
|
|
|
if (delta != 0)
|
|
|
|
{
|
|
|
|
// delta = ( delta * m + _interval/2 ) >> _shift; // == /_interval;
|
|
|
|
delta += m;
|
|
|
|
delta +=_interval/2;
|
|
|
|
delta >>= _shift; // == /_interval;
|
|
|
|
}
|
2022-07-25 09:25:14 -04:00
|
|
|
return _table[i] + delta;
|
2023-01-26 13:56:10 -05:00
|
|
|
#endif
|
2022-07-25 09:25:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t GAMMA::size()
|
|
|
|
{
|
|
|
|
return _size + 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t GAMMA::distinct()
|
|
|
|
{
|
|
|
|
uint8_t last = _table[0];
|
|
|
|
uint16_t count = 1;
|
|
|
|
for (uint16_t i = 1; i <= _size; i++)
|
|
|
|
{
|
|
|
|
if (_table[i] == last) continue;
|
|
|
|
last = _table[i];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
bool GAMMA::dump(Stream *str)
|
2022-07-25 09:25:14 -04:00
|
|
|
{
|
2022-07-26 07:16:03 -04:00
|
|
|
if (_table == NULL) return false;
|
2022-07-25 09:25:14 -04:00
|
|
|
for (uint16_t i = 0; i <= _size; i++)
|
|
|
|
{
|
|
|
|
str->println(_table[i]);
|
|
|
|
}
|
2022-07-26 07:16:03 -04:00
|
|
|
return true;
|
2022-07-25 09:25:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
bool GAMMA::dumpArray(Stream *str)
|
2022-07-25 09:25:14 -04:00
|
|
|
{
|
2022-07-26 07:16:03 -04:00
|
|
|
if (_table == NULL) return false;
|
2022-07-25 09:25:14 -04:00
|
|
|
str->println();
|
|
|
|
str->print("uint8_t gamma[");
|
|
|
|
str->print(_size + 1);
|
|
|
|
str->print("] = {");
|
2023-01-26 13:56:10 -05:00
|
|
|
|
2022-07-25 09:25:14 -04:00
|
|
|
for (uint16_t i = 0; i <= _size; i++)
|
|
|
|
{
|
|
|
|
if (i % 8 == 0) str->print("\n ");
|
|
|
|
str->print(_table[i]);
|
|
|
|
if (i < _size) str->print(", ");
|
|
|
|
}
|
|
|
|
str->print("\n };\n\n");
|
2022-07-26 07:16:03 -04:00
|
|
|
return true;
|
2022-07-25 09:25:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-07-26 07:16:03 -04:00
|
|
|
// performance investigation
|
|
|
|
inline float GAMMA::fastPow(float a, float b)
|
|
|
|
{
|
|
|
|
// reference
|
|
|
|
return pow(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-26 13:56:10 -05:00
|
|
|
// -- END OF FILE --
|
2022-07-25 09:25:14 -04:00
|
|
|
|