Big templatization. Fix for interpolation.
This commit is contained in:
150
lut.h
150
lut.h
@@ -3,22 +3,20 @@
|
||||
#include "color.h"
|
||||
#include "coord.h"
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
class Lut3d : public std::array<std::array<std::array<Color, B>, G>, R> {
|
||||
// Hardcoded to Color<3>, so color dimensions == LUT dimensions
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
class Lut3d : public std::array<std::array<std::array<Color<3>, X>, Y>, Z> {
|
||||
public:
|
||||
static Lut3d<R, G, B> Identity();
|
||||
static Lut3d<X, Y, Z> Identity();
|
||||
|
||||
Color MapColor(const Color& in) const;
|
||||
Color<3> MapColor(const Color<3>& in) const;
|
||||
|
||||
template <uint32_t X, uint32_t Y>
|
||||
std::unique_ptr<Image<X, Y>> MapImage(const Image<X, Y>& in) const;
|
||||
template <uint32_t IMG_X, uint32_t IMG_Y, uint32_t C>
|
||||
std::unique_ptr<Image<IMG_X, IMG_Y, C>> MapImage(const Image<IMG_X, IMG_Y, C>& in) const;
|
||||
|
||||
private:
|
||||
constexpr static Color InterpolateColor(const Color& i0, const Color& i1, uint32_t mul, uint32_t div);
|
||||
constexpr static uint32_t Interpolate(uint32_t i0, uint32_t i1, uint32_t mul, uint32_t div);
|
||||
|
||||
// Return value is (root_indices, remainders)
|
||||
constexpr static std::pair<Coord3d, Coord3d> FindRoot(const Color& in);
|
||||
constexpr static std::pair<Coord<3>, Coord<3>> FindRoot(const Color<3>& in);
|
||||
constexpr static std::pair<uint32_t, uint32_t> FindChannelRoot(uint32_t value, uint32_t points);
|
||||
|
||||
constexpr static uint32_t BlockSize(uint32_t points);
|
||||
@@ -27,22 +25,22 @@ class Lut3d : public std::array<std::array<std::array<Color, B>, G>, R> {
|
||||
// Minimum size LUT
|
||||
typedef Lut3d<2, 2, 2> MinimalLut3d;
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
Lut3d<R, G, B> Lut3d<R, G, B>::Identity() {
|
||||
Lut3d<R, G, B> ret;
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
Lut3d<X, Y, Z> Lut3d<X, Y, Z>::Identity() {
|
||||
Lut3d<X, Y, Z> ret;
|
||||
|
||||
Color color;
|
||||
for (uint32_t r = 0; r < R; ++r) {
|
||||
auto& rect = ret.at(r);
|
||||
color.at(0) = std::min(kNumColors - 1, BlockSize(R) * r);
|
||||
Color<3> color;
|
||||
for (uint32_t x = 0; x < X; ++x) {
|
||||
auto& rect = ret.at(x);
|
||||
color.at(0) = std::min(kMaxColor, BlockSize(X) * x);
|
||||
|
||||
for (uint32_t g = 0; g < G; ++g) {
|
||||
auto& row = rect.at(g);
|
||||
color.at(1) = std::min(kNumColors - 1, BlockSize(G) * g);
|
||||
for (uint32_t y = 0; y < Y; ++y) {
|
||||
auto& row = rect.at(y);
|
||||
color.at(1) = std::min(kMaxColor, BlockSize(Y) * y);
|
||||
|
||||
for (uint32_t b = 0; b < B; ++b) {
|
||||
color.at(2) = std::min(kNumColors - 1, BlockSize(B) * b);
|
||||
row.at(b) = color;
|
||||
for (uint32_t z = 0; z < Z; ++z) {
|
||||
color.at(2) = std::min(kMaxColor, BlockSize(Z) * z);
|
||||
row.at(z) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,51 +48,51 @@ Lut3d<R, G, B> Lut3d<R, G, B>::Identity() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
Color Lut3d<R, G, B>::MapColor(const Color& in) const {
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
Color<3> Lut3d<X, Y, Z>::MapColor(const Color<3>& in) const {
|
||||
const auto root_rem = FindRoot(in);
|
||||
const auto& root = root_rem.first;
|
||||
const auto& rem = root_rem.second;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Trilinear_interpolation
|
||||
auto inter00 = InterpolateColor(
|
||||
this->at(root.r + 0).at(root.g + 0).at(root.b + 0),
|
||||
this->at(root.r + 1).at(root.g + 0).at(root.b + 0),
|
||||
rem.r,
|
||||
BlockSize(R));
|
||||
auto inter00 =
|
||||
this->at(root.at(0) + 0).at(root.at(1) + 0).at(root.at(2) + 0).Interpolate(
|
||||
this->at(root.at(0) + 1).at(root.at(1) + 0).at(root.at(2) + 0),
|
||||
rem.at(0),
|
||||
BlockSize(X));
|
||||
|
||||
auto inter01 = InterpolateColor(
|
||||
this->at(root.r + 0).at(root.g + 0).at(root.b + 1),
|
||||
this->at(root.r + 1).at(root.g + 0).at(root.b + 1),
|
||||
rem.r,
|
||||
BlockSize(R));
|
||||
auto inter01 =
|
||||
this->at(root.at(0) + 0).at(root.at(1) + 0).at(root.at(2) + 1).Interpolate(
|
||||
this->at(root.at(0) + 1).at(root.at(1) + 0).at(root.at(2) + 1),
|
||||
rem.at(0),
|
||||
BlockSize(X));
|
||||
|
||||
auto inter10 = InterpolateColor(
|
||||
this->at(root.r + 0).at(root.g + 1).at(root.b + 0),
|
||||
this->at(root.r + 1).at(root.g + 1).at(root.b + 0),
|
||||
rem.r,
|
||||
BlockSize(R));
|
||||
auto inter10 =
|
||||
this->at(root.at(0) + 0).at(root.at(1) + 1).at(root.at(2) + 0).Interpolate(
|
||||
this->at(root.at(0) + 1).at(root.at(1) + 1).at(root.at(2) + 0),
|
||||
rem.at(0),
|
||||
BlockSize(X));
|
||||
|
||||
auto inter11 = InterpolateColor(
|
||||
this->at(root.r + 0).at(root.g + 1).at(root.b + 1),
|
||||
this->at(root.r + 1).at(root.g + 1).at(root.b + 1),
|
||||
rem.r,
|
||||
BlockSize(R));
|
||||
auto inter11 =
|
||||
this->at(root.at(0) + 0).at(root.at(1) + 1).at(root.at(2) + 1).Interpolate(
|
||||
this->at(root.at(0) + 1).at(root.at(1) + 1).at(root.at(2) + 1),
|
||||
rem.at(0),
|
||||
BlockSize(X));
|
||||
|
||||
auto inter0 = InterpolateColor(inter00, inter10, rem.g, BlockSize(G));
|
||||
auto inter1 = InterpolateColor(inter01, inter11, rem.g, BlockSize(G));
|
||||
auto inter0 = inter00.Interpolate(inter10, rem.at(1), BlockSize(Y));
|
||||
auto inter1 = inter01.Interpolate(inter11, rem.at(1), BlockSize(Y));
|
||||
|
||||
return InterpolateColor(inter0, inter1, rem.b, BlockSize(B));
|
||||
return inter0.Interpolate(inter1, rem.at(2), BlockSize(Z));
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
template <uint32_t X, uint32_t Y>
|
||||
std::unique_ptr<Image<X, Y>> Lut3d<R, G, B>::MapImage(const Image<X, Y>& in) const {
|
||||
auto out = std::make_unique<Image<X, Y>>();
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
template <uint32_t IMG_X, uint32_t IMG_Y, uint32_t C>
|
||||
std::unique_ptr<Image<IMG_X, IMG_Y, C>> Lut3d<X, Y, Z>::MapImage(const Image<IMG_X, IMG_Y, C>& in) const {
|
||||
auto out = std::make_unique<Image<IMG_X, IMG_Y, C>>();
|
||||
|
||||
for (uint32_t y = 0; y < Y; ++y) {
|
||||
for (uint32_t x = 0; x < X; ++x) {
|
||||
Coord coord = {x, y};
|
||||
for (uint32_t y = 0; y < IMG_Y; ++y) {
|
||||
for (uint32_t x = 0; x < IMG_X; ++x) {
|
||||
Coord<2> coord = {{{x, y}}};
|
||||
out->SetPixel(coord, MapColor(in.GetPixel(coord)));
|
||||
}
|
||||
}
|
||||
@@ -102,37 +100,19 @@ std::unique_ptr<Image<X, Y>> Lut3d<R, G, B>::MapImage(const Image<X, Y>& in) con
|
||||
return out;
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
constexpr Color Lut3d<R, G, B>::InterpolateColor(const Color& i0, const Color& i1, uint32_t mul, uint32_t div) {
|
||||
return {{{
|
||||
Interpolate(i0.at(0), i1.at(0), mul, div),
|
||||
Interpolate(i0.at(1), i1.at(1), mul, div),
|
||||
Interpolate(i0.at(2), i1.at(2), mul, div),
|
||||
}}};
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
constexpr uint32_t Lut3d<R, G, B>::Interpolate(uint32_t i0, uint32_t i1, uint32_t mul, uint32_t div) {
|
||||
if (i1 > i0) {
|
||||
return i0 + ((mul * (i1 - i0)) / div);
|
||||
} else {
|
||||
return i1 + ((mul * (i0 - i1)) / div);
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
constexpr std::pair<Coord3d, Coord3d> Lut3d<R, G, B>::FindRoot(const Color& in) {
|
||||
auto root_r = FindChannelRoot(in.at(0), R);
|
||||
auto root_g = FindChannelRoot(in.at(1), G);
|
||||
auto root_b = FindChannelRoot(in.at(2), B);
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
constexpr std::pair<Coord<3>, Coord<3>> Lut3d<X, Y, Z>::FindRoot(const Color<3>& in) {
|
||||
auto root_x = FindChannelRoot(in.at(0), X);
|
||||
auto root_y = FindChannelRoot(in.at(1), Y);
|
||||
auto root_z = FindChannelRoot(in.at(2), Z);
|
||||
return {
|
||||
{root_r.first, root_g.first, root_b.first},
|
||||
{root_r.second, root_g.second, root_b.second},
|
||||
{{{root_x.first, root_y.first, root_z.first}}},
|
||||
{{{root_x.second, root_y.second, root_z.second}}},
|
||||
};
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
constexpr std::pair<uint32_t, uint32_t> Lut3d<R, G, B>::FindChannelRoot(const uint32_t value, const uint32_t points) {
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
constexpr std::pair<uint32_t, uint32_t> Lut3d<X, Y, Z>::FindChannelRoot(const uint32_t value, const uint32_t points) {
|
||||
// points - 1 is the last point index. Since we're going to fidn the cube
|
||||
// around this point by adding to the root, we need to be at least 1 less
|
||||
// than that.
|
||||
@@ -140,7 +120,7 @@ constexpr std::pair<uint32_t, uint32_t> Lut3d<R, G, B>::FindChannelRoot(const ui
|
||||
return std::make_pair(index, value - (index * BlockSize(points)));
|
||||
}
|
||||
|
||||
template <uint32_t R, uint32_t G, uint32_t B>
|
||||
constexpr uint32_t Lut3d<R, G, B>::BlockSize(uint32_t points) {
|
||||
return kNumColors / (points - 1);
|
||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
||||
constexpr uint32_t Lut3d<X, Y, Z>::BlockSize(uint32_t points) {
|
||||
return (kMaxColor + 1) / (points - 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user