|
|
|
//
|
|
|
|
// Tonemapper.hpp
|
|
|
|
// AwesomeAttractorND
|
|
|
|
//
|
|
|
|
// Created by Joshua Moerman on 10/28/11.
|
|
|
|
// Copyright 2011 Vadovas. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef AwesomeAttractorND_Tonemapper_hpp
|
|
|
|
#define AwesomeAttractorND_Tonemapper_hpp
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <numeric>
|
|
|
|
#include <cmath>
|
|
|
|
#include <array>
|
|
|
|
|
|
|
|
#include "stf_ext.hpp"
|
|
|
|
#include "Random.hpp"
|
|
|
|
|
|
|
|
namespace Tonemappers {
|
|
|
|
|
|
|
|
struct Normalizer {
|
|
|
|
Normalizer()
|
|
|
|
: max(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
template <typename C>
|
|
|
|
void analyse(C const & canvas){
|
|
|
|
max = *std::max_element(canvas.begin(), canvas.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename C, typename I>
|
|
|
|
void process(C const & canvas, I & image) const {
|
|
|
|
for (typename C::const_iterator it = canvas.begin(); it != canvas.end(); ++it) {
|
|
|
|
const double grayscale = get_value(*it);
|
|
|
|
image << typename I::pixel(grayscale, grayscale, grayscale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
double get_value(T const & n) const {
|
|
|
|
return (double) n / (double) max;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
unsigned int max;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GammaCorrector : public Normalizer {
|
|
|
|
GammaCorrector(double gamma = 1.0)
|
|
|
|
: power(1.0)
|
|
|
|
, gamma(gamma)
|
|
|
|
{}
|
|
|
|
|
|
|
|
template <typename C>
|
|
|
|
void analyse(C const & canvas){
|
|
|
|
Normalizer::analyse(canvas);
|
|
|
|
const unsigned int sum = std::accumulate(canvas.begin(), canvas.end(), 0);
|
|
|
|
const double average = sum / (double) canvas.size();
|
|
|
|
power = -2.5/std::log(average/max);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename C, typename I>
|
|
|
|
void process(C const & canvas, I & image) const {
|
|
|
|
for (typename C::const_iterator it = canvas.begin(); it != canvas.end(); ++it) {
|
|
|
|
const double grayscale = get_value(*it);
|
|
|
|
image << typename I::pixel(grayscale, grayscale, grayscale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
double get_value(T const & n, double factor = 1.0) const {
|
|
|
|
return std::pow(Normalizer::get_value(n), factor * power / gamma);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
double power;
|
|
|
|
double gamma;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Colorizer {
|
|
|
|
Colorizer(size_t n_planes)
|
|
|
|
: gamma_correctors(n_planes)
|
|
|
|
, gammas({{std::vector<double>(n_planes, 2.0), std::vector<double>(n_planes, 2.0), std::vector<double>(n_planes, 2.0)}})
|
|
|
|
, colors({{std::vector<double>(n_planes, 2.0), std::vector<double>(n_planes, 2.0), std::vector<double>(n_planes, 2.0)}})
|
|
|
|
{}
|
|
|
|
|
|
|
|
Colorizer(size_t n_planes, Random::parameters)
|
|
|
|
: gamma_correctors(n_planes)
|
|
|
|
, gammas({{Random::make_vector(1.0, 3.0, n_planes), Random::make_vector(1.0, 3.0, n_planes), Random::make_vector(1.0, 3.0, n_planes)}})
|
|
|
|
, colors({{Random::make_vector(-2.0, 4.0, n_planes), Random::make_vector(-2.0, 4.0, n_planes), Random::make_vector(-2.0, 4.0, n_planes)}})
|
|
|
|
{}
|
|
|
|
|
|
|
|
template <typename C>
|
|
|
|
void analyse(C const & canvas){
|
|
|
|
for (size_t i = 0; i < gamma_correctors.size(); ++i) {
|
|
|
|
gamma_correctors[i].analyse(canvas[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename C, typename I>
|
|
|
|
typename std::enable_if<C::dimension == 2, void>::type process(C & canvas, I & image) const {
|
|
|
|
for (unsigned int r = 0; r < canvas.template size<1>(); ++r){
|
|
|
|
for (unsigned int c = 0; c < canvas.template size<0>(); ++c){
|
|
|
|
auto const c1 = canvas[0][r][c];
|
|
|
|
auto const c2 = canvas[1][r][c];
|
|
|
|
std::array<decltype(c1), 2> const a = {{c1, c2}};
|
|
|
|
image << typename I::pixel(get_value(a, 0), get_value(a, 1), get_value(a, 2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
double get_value(T const & n, size_t color) const {
|
|
|
|
double ret = 0.0;
|
|
|
|
for (size_t i = 0; i < n.size(); ++i){
|
|
|
|
ret += gamma_correctors[i].get_value(n[i], gammas[color][i]) * colors[color][i];
|
|
|
|
}
|
|
|
|
if(std::isnormal(ret))
|
|
|
|
return ret;
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
stfu::node to_stf() const {
|
|
|
|
stfu::node node;
|
|
|
|
node.addValue("class") = "colorizer";
|
|
|
|
node.addChild("gamma_matrix") = stfu::to_stf(gammas);
|
|
|
|
node.addChild("color_matrix") = stfu::to_stf(colors);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
std::vector<GammaCorrector> gamma_correctors;
|
|
|
|
std::array<std::vector<double>, 3> gammas;
|
|
|
|
std::array<std::vector<double>, 3> colors;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|