vector<double>
-GammaTransferFunction::make_lut (int bit_depth, bool inverse) const
+GammaTransferFunction::make_lut (double from, double to, int bit_depth, bool inverse) const
{
int const bit_length = int(std::pow(2.0f, bit_depth));
auto lut = vector<double>(bit_length);
double const gamma = inverse ? (1 / _gamma) : _gamma;
for (int i = 0; i < bit_length; ++i) {
- lut[i] = pow(double(i) / (bit_length - 1), gamma);
+ double const x = double(i) / (bit_length - 1);
+ lut[i] = pow((x * (to - from)) + from, gamma);
}
return lut;
bool about_equal (std::shared_ptr<const TransferFunction> other, double epsilon) const override;
protected:
- std::vector<double> make_lut (int bit_depth, bool inverse) const override;
+ std::vector<double> make_lut (double from, double to, int bit_depth, bool inverse) const override;
private:
double _gamma;
vector<double>
-IdentityTransferFunction::make_lut (int bit_depth, bool) const
+IdentityTransferFunction::make_lut (double from, double to, int bit_depth, bool) const
{
int const bit_length = int(std::pow(2.0f, bit_depth));
auto lut = vector<double>(bit_length);
for (int i = 0; i < bit_length; ++i) {
- lut[i] = double(i) / (bit_length - 1);
+ double x = double(i) / (bit_length - 1);
+ lut[i] = (x * (to - from)) + from;
}
return lut;
bool about_equal (std::shared_ptr<const TransferFunction> other, double epsilon) const override;
protected:
- std::vector<double> make_lut (int bit_depth, bool inverse) const override;
+ std::vector<double> make_lut (double from, double to, int bit_depth, bool inverse) const override;
};
vector<double>
-ModifiedGammaTransferFunction::make_lut (int bit_depth, bool inverse) const
+ModifiedGammaTransferFunction::make_lut (double from, double to, int bit_depth, bool inverse) const
{
int const bit_length = int(std::pow(2.0f, bit_depth));
auto lut = vector<double>(bit_length);
double const threshold = _threshold / _B;
for (int i = 0; i < bit_length; ++i) {
double const p = static_cast<double>(i) / (bit_length - 1);
- if (p > threshold) {
- lut[i] = (1 + _A) * pow (p, 1 / _power) - _A;
+ double const q = (p * (to - from)) + from;
+ if (q > threshold) {
+ lut[i] = (1 + _A) * pow (q, 1 / _power) - _A;
} else {
- lut[i] = p * _B;
+ lut[i] = q * _B;
}
}
} else {
for (int i = 0; i < bit_length; ++i) {
double const p = static_cast<double>(i) / (bit_length - 1);
- if (p > _threshold) {
- lut[i] = pow ((p + _A) / (1 + _A), _power);
+ double const q = (p * (to - from)) + from;
+ if (q > _threshold) {
+ lut[i] = pow ((q + _A) / (1 + _A), _power);
} else {
- lut[i] = p / _B;
+ lut[i] = q / _B;
}
}
}
bool about_equal (std::shared_ptr<const TransferFunction>, double epsilon) const override;
protected:
- std::vector<double> make_lut (int bit_depth, bool inverse) const override;
+ std::vector<double> make_lut (double from, double to, int bit_depth, bool inverse) const override;
private:
double _power;
int* xyz_y = xyz_image->data (1);
int* xyz_z = xyz_image->data (2);
- auto lut_in = conversion.out()->lut (12, false);
- auto lut_out = conversion.in()->lut (16, true);
+ auto lut_in = conversion.out()->lut(0, 1, 12, false);
+ auto lut_out = conversion.in()->lut(0, 1, 16, true);
boost::numeric::ublas::matrix<double> const matrix = conversion.xyz_to_rgb ();
double fast_matrix[9] = {
int* xyz_y = xyz_image->data (1);
int* xyz_z = xyz_image->data (2);
- auto lut_in = conversion.out()->lut (12, false);
- auto lut_out = conversion.in()->lut (16, true);
+ auto lut_in = conversion.out()->lut(0, 1, 12, false);
+ auto lut_out = conversion.in()->lut(0, 1, 16, true);
auto const matrix = conversion.xyz_to_rgb ();
double fast_matrix[9] = {
double x, y, z;
} d;
- auto lut_in = conversion.in()->lut (12, false);
- auto lut_out = conversion.out()->lut (16, true);
+ auto lut_in = conversion.in()->lut(0, 1, 12, false);
+ auto lut_out = conversion.out()->lut(0, 1, 16, true);
/* This is is the product of the RGB to XYZ matrix, the Bradford transform and the DCI companding */
double fast_matrix[9];
vector<double>
-SGamut3TransferFunction::make_lut (int bit_depth, bool inverse) const
+SGamut3TransferFunction::make_lut (double from, double to, int bit_depth, bool inverse) const
{
int const bit_length = int(std::pow(2.0f, bit_depth));
auto lut = vector<double>(bit_length);
if (inverse) {
for (int i = 0; i < bit_length; ++i) {
auto const p = static_cast<double>(i) / (bit_length - 1);
- if (p >= (0.01125 / 1023)) {
- lut[i] = (420 + log10((p + 0.01) / (0.18 + 0.01)) * 261.5) / 1023;
+ auto const q = (p * (to - from)) + from;
+ if (q >= (0.01125 / 1023)) {
+ lut[i] = (420 + log10((q + 0.01) / (0.18 + 0.01)) * 261.5) / 1023;
} else {
- lut[i] = (p * (171.2102946929 - 95) / 0.01125000 + 95) / 1023;
+ lut[i] = (q * (171.2102946929 - 95) / 0.01125000 + 95) / 1023;
}
}
} else {
for (int i = 0; i < bit_length; ++i) {
auto const p = static_cast<double>(i) / (bit_length - 1);
- if (p >= (171.2102946929 / 1023)) {
+ auto const q = (p * (to - from)) + from;
+ if (q >= (171.2102946929 / 1023)) {
lut[i] = pow(10, ((p * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01;
} else {
- lut[i] = (p * 1023 - 95) * 0.01125000 / (171.2102946929 - 95);
+ lut[i] = (q * 1023 - 95) * 0.01125000 / (171.2102946929 - 95);
}
}
}
bool about_equal (std::shared_ptr<const TransferFunction> other, double epsilon) const override;
protected:
- std::vector<double> make_lut (int bit_depth, bool inverse) const override;
+ std::vector<double> make_lut (double from, double to, int bit_depth, bool inverse) const override;
};
vector<double> const&
-TransferFunction::lut (int bit_depth, bool inverse) const
+TransferFunction::lut (double from, double to, int bit_depth, bool inverse) const
{
boost::mutex::scoped_lock lm (_mutex);
- auto i = _luts.find (make_pair (bit_depth, inverse));
- if (i != _luts.end ()) {
+ auto const descriptor = LUTDescriptor{from, to, bit_depth, inverse};
+
+ auto i = _luts.find(descriptor);
+ if (i != _luts.end()) {
return i->second;
}
- _luts[make_pair(bit_depth, inverse)] = make_lut (bit_depth, inverse);
- return _luts[make_pair(bit_depth, inverse)];
+ _luts[descriptor] = make_lut(from, to, bit_depth, inverse);
+ return _luts[descriptor];
+}
+
+
+bool
+TransferFunction::LUTDescriptor::operator==(TransferFunction::LUTDescriptor const& other) const
+{
+ return from == other.from && to == other.to && bit_depth == other.bit_depth && inverse == other.inverse;
+}
+
+
+std::size_t
+TransferFunction::LUTDescriptorHasher::operator()(TransferFunction::LUTDescriptor const& desc) const
+{
+ return std::hash<double>()(desc.from) ^
+ std::hash<double>()(desc.to) ^
+ std::hash<int>()(desc.bit_depth) ^
+ std::hash<bool>()(desc.inverse);
}
+
#include <boost/thread/mutex.hpp>
-#include <map>
+#include <unordered_map>
#include <memory>
#include <vector>
virtual ~TransferFunction () {}
- /** @return A look-up table (of size 2^bit_depth) whose values range from 0 to 1 */
- std::vector<double> const& lut (int bit_depth, bool inverse) const;
+ /** @return A look-up table (of size 2^bit_depth) */
+ std::vector<double> const& lut (double from, double to, int bit_depth, bool inverse) const;
virtual bool about_equal (std::shared_ptr<const TransferFunction> other, double epsilon) const = 0;
protected:
/** Make a LUT and return an array allocated by new */
- virtual std::vector<double> make_lut (int bit_depth, bool inverse) const = 0;
+ virtual std::vector<double> make_lut (double from, double to, int bit_depth, bool inverse) const = 0;
private:
- mutable std::map<std::pair<int, bool>, std::vector<double>> _luts;
+ struct LUTDescriptor {
+ double from;
+ double to;
+ int bit_depth;
+ bool inverse;
+
+ bool operator==(LUTDescriptor const& other) const;
+ };
+
+ struct LUTDescriptorHasher {
+ std::size_t operator()(LUTDescriptor const& desc) const;
+ };
+
+ mutable std::unordered_map<LUTDescriptor, std::vector<double>, LUTDescriptorHasher> _luts;
/** mutex to protect _luts */
mutable boost::mutex _mutex;
};
static void
check_gamma (shared_ptr<const TransferFunction> tf, int bit_depth, bool inverse, float gamma)
{
- auto lut = tf->lut (bit_depth, inverse);
+ auto lut = tf->lut(0, 1, bit_depth, inverse);
int const count = rint (pow (2.0, bit_depth));
for (int i = 0; i < count; ++i) {
static void
check_modified_gamma (shared_ptr<const TransferFunction> tf, int bit_depth, bool inverse, double power, double threshold, double A, double B)
{
- auto lut = tf->lut (bit_depth, inverse);
+ auto lut = tf->lut(0, 1, bit_depth, inverse);
int const count = rint (pow (2.0, bit_depth));
for (int i = 0; i < count; ++i) {