Working identity LUT

This commit is contained in:
Ian Gulliver
2017-08-07 06:15:20 +00:00
parent 89a54867f3
commit 100c44fe4e
7 changed files with 81 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
all: piphoto all: piphoto
objects = piphoto.o coord.o util.o objects = piphoto.o color.o coord.o util.o
piphoto: $(objects) Makefile piphoto: $(objects) Makefile
clang-3.9 -O3 -g -Weverything -Werror -Wno-c++98-compat -Wno-c++98-c++11-compat-pedantic --std=c++1z --stdlib=libc++ -o piphoto $(objects) -lc++ -lunwind -lpng clang-3.9 -O3 -g -Weverything -Werror -Wno-c++98-compat -Wno-c++98-c++11-compat-pedantic --std=c++1z --stdlib=libc++ -o piphoto $(objects) -lc++ -lunwind -lpng

13
color.cc Normal file
View File

@@ -0,0 +1,13 @@
#include "color.h"
#include <iomanip>
std::ostream& operator<<(std::ostream& os, const Color& color) {
return os
<< std::hex << std::setfill('0')
<< "rgb("
<< "0x" << std::setw(4) << color.r << ", "
<< "0x" << std::setw(4) << color.g << ", "
<< "0x" << std::setw(4) << color.b
<< ")" << std::dec;
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <iostream>
constexpr uint32_t kNumColors = (1 << 16); constexpr uint32_t kNumColors = (1 << 16);
@@ -20,3 +21,5 @@ constexpr uint32_t Color::Difference(const Color& other) const {
((b > other.b) ? (b - other.b) : (other.b - b)) ((b > other.b) ? (b - other.b) : (other.b - b))
); );
} }
std::ostream& operator<<(std::ostream& os, const Color& color);

View File

@@ -5,6 +5,9 @@
#include "color.h" #include "color.h"
#include "coord.h" #include "coord.h"
#include "image.h" #include "image.h"
#include "lut.h"
typedef Lut3d<4, 3, 3> ColorCheckerLut3d;
constexpr std::array<Color, 24> kColorCheckerSrgb = {{ constexpr std::array<Color, 24> kColorCheckerSrgb = {{
{0x7300, 0x5200, 0x4400}, {0x7300, 0x5200, 0x4400},

View File

@@ -61,7 +61,7 @@ void Image<X, Y>::DrawSquare(const Coord& start, const Color& color, uint32_t le
DrawRectangle(start, color, length, length); DrawRectangle(start, color, length, length);
} }
static void WriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) { static inline void WriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
auto dest = static_cast<std::string*>(png_get_io_ptr(png_ptr)); auto dest = static_cast<std::string*>(png_get_io_ptr(png_ptr));
dest->append(reinterpret_cast<char*>(data), length); dest->append(reinterpret_cast<char*>(data), length);
} }

52
lut.h
View File

@@ -11,8 +11,13 @@ struct Coord3d {
template <uint32_t R, uint32_t G, uint32_t B> template <uint32_t R, uint32_t G, uint32_t B>
class Lut3d : public std::array<std::array<std::array<Color, B>, G>, R> { class Lut3d : public std::array<std::array<std::array<Color, B>, G>, R> {
public: public:
static std::unique_ptr<Lut3d<R, G, B>> Identity();
Color MapColor(const Color& in) const; Color MapColor(const Color& in) const;
template <uint32_t X, uint32_t Y>
std::unique_ptr<Image<X, Y>> MapImage(const Image<X, Y>& in) const;
private: private:
constexpr static Color InterpolateColor(const Color& i0, const Color& i1, uint32_t mul, uint32_t div); 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); constexpr static uint32_t Interpolate(uint32_t i0, uint32_t i1, uint32_t mul, uint32_t div);
@@ -24,6 +29,29 @@ class Lut3d : public std::array<std::array<std::array<Color, B>, G>, R> {
constexpr static uint32_t BlockSize(uint32_t points); constexpr static uint32_t BlockSize(uint32_t points);
}; };
template <uint32_t R, uint32_t G, uint32_t B>
std::unique_ptr<Lut3d<R, G, B>> Lut3d<R, G, B>::Identity() {
auto ret = std::make_unique<Lut3d<R, G, B>>();
Color color;
for (uint32_t r = 0; r < R; ++r) {
auto& rect = ret->at(r);
color.r = std::min(kNumColors - 1, BlockSize(R) * r);
for (uint32_t g = 0; g < G; ++g) {
auto& row = rect.at(g);
color.g = std::min(kNumColors - 1, BlockSize(G) * g);
for (uint32_t b = 0; b < B; ++b) {
color.b = std::min(kNumColors - 1, BlockSize(B) * b);
row.at(b) = color;
}
}
}
return ret;
}
template <uint32_t R, uint32_t G, uint32_t B> template <uint32_t R, uint32_t G, uint32_t B>
Color Lut3d<R, G, B>::MapColor(const Color& in) const { Color Lut3d<R, G, B>::MapColor(const Color& in) const {
const auto root_rem = FindRoot(in); const auto root_rem = FindRoot(in);
@@ -61,6 +89,21 @@ Color Lut3d<R, G, B>::MapColor(const Color& in) const {
return InterpolateColor(inter0, inter1, rem.b, BlockSize(B)); return InterpolateColor(inter0, inter1, rem.b, BlockSize(B));
} }
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>>();
for (uint32_t y = 0; y < Y; ++y) {
for (uint32_t x = 0; x < X; ++x) {
Coord coord = {x, y};
out->SetPixel(coord, MapColor(in.GetPixel(coord)));
}
}
return out;
}
template <uint32_t R, uint32_t G, uint32_t B> 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) { constexpr Color Lut3d<R, G, B>::InterpolateColor(const Color& i0, const Color& i1, uint32_t mul, uint32_t div) {
return { return {
@@ -72,14 +115,15 @@ constexpr Color Lut3d<R, G, B>::InterpolateColor(const Color& i0, const Color& i
template <uint32_t R, uint32_t G, uint32_t B> 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) { constexpr uint32_t Lut3d<R, G, B>::Interpolate(uint32_t i0, uint32_t i1, uint32_t mul, uint32_t div) {
return i0 + ((mul * i1) / div); assert(i1 >= i0);
return i0 + ((mul * (i1 - i0)) / div);
} }
template <uint32_t R, uint32_t G, uint32_t B> template <uint32_t R, uint32_t G, uint32_t B>
constexpr std::pair<Coord3d, Coord3d> Lut3d<R, G, B>::FindRoot(const Color& in) { constexpr std::pair<Coord3d, Coord3d> Lut3d<R, G, B>::FindRoot(const Color& in) {
auto root_r = FindChannelRoot(in.r, R); auto root_r = FindChannelRoot(in.r, R);
auto root_g = FindChannelRoot(in.r, G); auto root_g = FindChannelRoot(in.g, G);
auto root_b = FindChannelRoot(in.r, B); auto root_b = FindChannelRoot(in.b, B);
return { return {
{root_r.first, root_g.first, root_b.first}, {root_r.first, root_g.first, root_b.first},
{root_r.second, root_g.second, root_b.second}, {root_r.second, root_g.second, root_b.second},
@@ -95,6 +139,6 @@ constexpr std::pair<uint32_t, uint32_t> Lut3d<R, G, B>::FindChannelRoot(const ui
} }
template <uint32_t R, uint32_t G, uint32_t B> template <uint32_t R, uint32_t G, uint32_t B>
constexpr uint32_t BlockSize(uint32_t points) { constexpr uint32_t Lut3d<R, G, B>::BlockSize(uint32_t points) {
return kNumColors / (points - 1); return kNumColors / (points - 1);
} }

View File

@@ -11,16 +11,20 @@
int main() { int main() {
auto image = PiRaw2::FromJpeg(ReadFile("test.jpg")); auto image = PiRaw2::FromJpeg(ReadFile("test.jpg"));
auto closest = ColorCheckerClosest(*image);
auto lut = ColorCheckerLut3d::Identity();
auto image2 = lut->MapImage(*image);
auto closest = ColorCheckerClosest(*image2);
for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) { for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) {
const auto& coord = closest.at(cc); const auto& coord = closest.at(cc);
const auto& color = kColorCheckerSrgb.at(cc); const auto& color = kColorCheckerSrgb.at(cc);
std::cout << cc << ": " << coord << " difference=" << color.Difference(image->GetPixel(coord)) << std::endl; std::cout << cc << ": " << coord << " difference=" << color.Difference(image2->GetPixel(coord)) << std::endl;
image->DrawSquare({std::max(5U, coord.x) - 5, std::max(5U, coord.y) - 5}, kBlack, 10); image2->DrawSquare({std::max(5U, coord.x) - 5, std::max(5U, coord.y) - 5}, kBlack, 10);
image->DrawSquare({std::max(6U, coord.x) - 6, std::max(6U, coord.y) - 6}, color, 12); image2->DrawSquare({std::max(6U, coord.x) - 6, std::max(6U, coord.y) - 6}, color, 12);
image->DrawSquare({std::max(7U, coord.x) - 7, std::max(7U, coord.y) - 7}, color, 14); image2->DrawSquare({std::max(7U, coord.x) - 7, std::max(7U, coord.y) - 7}, color, 14);
image->DrawSquare({std::max(8U, coord.x) - 8, std::max(8U, coord.y) - 8}, color, 16); image2->DrawSquare({std::max(8U, coord.x) - 8, std::max(8U, coord.y) - 8}, color, 16);
image->DrawSquare({std::max(9U, coord.x) - 9, std::max(9U, coord.y) - 9}, kWhite, 18); image2->DrawSquare({std::max(9U, coord.x) - 9, std::max(9U, coord.y) - 9}, kWhite, 18);
} }
WriteFile("test.png", image->ToPng()); WriteFile("test.png", image2->ToPng());
} }