You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.4 KiB
139 lines
3.4 KiB
//
|
|
// 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>
|
|
|
|
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()
|
|
, colors()
|
|
{
|
|
gammas[0].push_back(1.3);
|
|
gammas[1].push_back(2.0);
|
|
gammas[2].push_back(3.0);
|
|
|
|
gammas[0].push_back(3.0);
|
|
gammas[1].push_back(1.0);
|
|
gammas[2].push_back(1.0);
|
|
|
|
colors[0].push_back(1.5);
|
|
colors[1].push_back(2.0);
|
|
colors[2].push_back(1.0);
|
|
|
|
colors[0].push_back(-1.0);
|
|
colors[1].push_back(-0.5);
|
|
colors[2].push_back(0.7);
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected:
|
|
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;
|
|
}
|
|
std::vector<GammaCorrector> gamma_correctors;
|
|
std::array<std::vector<double>, 3> gammas;
|
|
std::array<std::vector<double>, 3> colors;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|