// // 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 #include #include #include #include "stf_ext.hpp" #include "Random.hpp" namespace Tonemappers { struct Normalizer { Normalizer() : max(0) {} template void analyse(C const & canvas){ max = *std::max_element(canvas.begin(), canvas.end()); } template 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 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 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 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 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(n_planes, 2.0), std::vector(n_planes, 2.0), std::vector(n_planes, 2.0)}}) , colors({{std::vector(n_planes, 2.0), std::vector(n_planes, 2.0), std::vector(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)}}) {} Colorizer(size_t n_planes, stfu::node const & n) : gamma_correctors(n_planes) , gammas(stfu::from_stf(n.getChild("gamma_matrix"))) , colors(stfu::from_stf(n.getChild("color_matrix"))) {} template void analyse(C const & canvas){ for (size_t i = 0; i < gamma_correctors.size(); ++i) { gamma_correctors[i].analyse(canvas[i]); } } template typename std::enable_if::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 const a = {{c1, c2}}; image << typename I::pixel(get_value(a, 0), get_value(a, 1), get_value(a, 2)); } } } template 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; } static Colorizer from_stf(stfu::node const & n) { if (n.getValue("class") != "colorizer") std::cerr << "trying to read an stf as colorizer whil class != \"colorizer\""; auto g = stfu::from_stf(n.getChild("gamma_matrix")); auto c = stfu::from_stf(n.getChild("color_matrix")); Colorizer tonemapper(g[0].size()); tonemapper.gammas = g; tonemapper.colors = c; return tonemapper; } protected: std::vector gamma_correctors; typedef std::array, 3> Matrix; Matrix gammas; Matrix colors; }; } #endif