Conversion to signed
This commit is contained in:
44
array.h
Normal file
44
array.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
template <class T, int32_t N>
|
||||||
|
struct Array : std::array<T, N> {
|
||||||
|
using reference = typename std::array<T, N>::reference;
|
||||||
|
using const_reference = typename std::array<T, N>::const_reference;
|
||||||
|
using size_type = typename std::array<T, N>::size_type;
|
||||||
|
|
||||||
|
constexpr int32_t ssize() const;
|
||||||
|
|
||||||
|
constexpr reference at(int32_t pos);
|
||||||
|
constexpr const_reference at(int32_t pos) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, int32_t N>
|
||||||
|
constexpr int32_t Array<T, N>::ssize() const {
|
||||||
|
auto size = this->size();
|
||||||
|
assert(size < INT32_MAX);
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||||
|
return size;
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, int32_t N>
|
||||||
|
constexpr typename Array<T, N>::reference Array<T, N>::at(int32_t pos) {
|
||||||
|
assert(pos >= 0);
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||||
|
return std::array<T, N>::at(static_cast<size_type>(pos));
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, int32_t N>
|
||||||
|
constexpr typename Array<T, N>::const_reference Array<T, N>::at(int32_t pos) const {
|
||||||
|
assert(pos >= 0);
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||||
|
return std::array<T, N>::at(static_cast<size_type>(pos));
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
}
|
||||||
31
color.h
31
color.h
@@ -1,56 +1,55 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
#include "intmath.h"
|
#include "intmath.h"
|
||||||
|
|
||||||
constexpr int32_t kMinColor = 0;
|
constexpr int32_t kMinColor = 0;
|
||||||
constexpr int32_t kMaxColor = UINT16_MAX;
|
constexpr int32_t kMaxColor = UINT16_MAX;
|
||||||
|
|
||||||
// 32-bit for compiler convenience, but values are 16-bit
|
template <int32_t C>
|
||||||
template <uint32_t C>
|
struct Color : public Array<int32_t, C> {
|
||||||
struct Color : public std::array<int32_t, C> {
|
constexpr int32_t AbsDiff(const Color<C>& other) const;
|
||||||
constexpr uint32_t AbsDiff(const Color<C>& other) const;
|
|
||||||
constexpr Color<C> Interpolate(const Color<C>& other, int32_t mul, int32_t div) const;
|
constexpr Color<C> Interpolate(const Color<C>& other, int32_t mul, int32_t div) const;
|
||||||
constexpr Color<C> Crop() const;
|
constexpr Color<C> Crop() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RgbColor : public Color<3> {};
|
struct RgbColor : public Color<3> {};
|
||||||
|
|
||||||
template <uint32_t C>
|
template <int32_t C>
|
||||||
constexpr uint32_t Color<C>::AbsDiff(const Color<C>& other) const {
|
constexpr int32_t Color<C>::AbsDiff(const Color<C>& other) const {
|
||||||
uint32_t diff = 0;
|
int32_t diff = 0;
|
||||||
for (uint32_t c = 0; c < C; ++c) {
|
for (int32_t c = 0; c < C; ++c) {
|
||||||
diff += static_cast<uint32_t>(::AbsDiff(this->at(c), other.at(c)));
|
diff += ::AbsDiff(this->at(c), other.at(c));
|
||||||
}
|
}
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t C>
|
template <int32_t C>
|
||||||
constexpr Color<C> Color<C>::Interpolate(const Color<C>& other, int32_t mul, int32_t div) const {
|
constexpr Color<C> Color<C>::Interpolate(const Color<C>& other, int32_t mul, int32_t div) const {
|
||||||
Color<C> ret;
|
Color<C> ret;
|
||||||
for (uint32_t c = 0; c < C; ++c) {
|
for (int32_t c = 0; c < C; ++c) {
|
||||||
ret.at(c) = ::Interpolate(this->at(c), other.at(c), mul, div);
|
ret.at(c) = ::Interpolate(this->at(c), other.at(c), mul, div);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t C>
|
template <int32_t C>
|
||||||
constexpr Color<C> Color<C>::Crop() const {
|
constexpr Color<C> Color<C>::Crop() const {
|
||||||
Color<C> ret;
|
Color<C> ret;
|
||||||
for (uint32_t c = 0; c < C; ++c) {
|
for (int32_t c = 0; c < C; ++c) {
|
||||||
ret.at(c) = std::max(kMinColor, std::min(kMaxColor, this->at(c)));
|
ret.at(c) = std::max(kMinColor, std::min(kMaxColor, this->at(c)));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t C>
|
template <int32_t C>
|
||||||
std::ostream& operator<<(std::ostream& os, const Color<C>& color) {
|
std::ostream& operator<<(std::ostream& os, const Color<C>& color) {
|
||||||
os << std::hex << std::setfill('0') << "Color(";
|
os << std::hex << std::setfill('0') << "Color(";
|
||||||
for (uint32_t c = 0; c < C; ++c) {
|
for (int32_t c = 0; c < C; ++c) {
|
||||||
os << "0x" << std::setw(4) << color.at(0);
|
os << "0x" << std::setw(4) << color.at(0);
|
||||||
if (c < C - 1) {
|
if (c < C - 1) {
|
||||||
os << ", ";
|
os << ", ";
|
||||||
|
|||||||
120
colorchecker.h
120
colorchecker.h
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "colors.h"
|
#include "colors.h"
|
||||||
#include "coord.h"
|
#include "coord.h"
|
||||||
@@ -14,52 +14,52 @@
|
|||||||
// Maximum LUT size that has each point adjacent to at least one ColorChecker color.
|
// Maximum LUT size that has each point adjacent to at least one ColorChecker color.
|
||||||
typedef Lut3d<4, 3, 3> ColorCheckerLut3d;
|
typedef Lut3d<4, 3, 3> ColorCheckerLut3d;
|
||||||
|
|
||||||
constexpr std::array<RgbColor, 24> kColorCheckerSrgb = {{
|
constexpr Array<RgbColor, 24> kColorCheckerSrgb = {{{
|
||||||
{{{{0x7300, 0x5200, 0x4400}}}},
|
{{{{{0x7300, 0x5200, 0x4400}}}}},
|
||||||
{{{{0xc200, 0x9600, 0x8200}}}},
|
{{{{{0xc200, 0x9600, 0x8200}}}}},
|
||||||
{{{{0x6200, 0x7a00, 0x9d00}}}},
|
{{{{{0x6200, 0x7a00, 0x9d00}}}}},
|
||||||
{{{{0x5700, 0x6c00, 0x4300}}}},
|
{{{{{0x5700, 0x6c00, 0x4300}}}}},
|
||||||
{{{{0x8500, 0x8000, 0xb100}}}},
|
{{{{{0x8500, 0x8000, 0xb100}}}}},
|
||||||
{{{{0x6700, 0xbd00, 0xaa00}}}},
|
{{{{{0x6700, 0xbd00, 0xaa00}}}}},
|
||||||
{{{{0xd600, 0x7e00, 0x2c00}}}},
|
{{{{{0xd600, 0x7e00, 0x2c00}}}}},
|
||||||
{{{{0x5000, 0x5b00, 0xa600}}}},
|
{{{{{0x5000, 0x5b00, 0xa600}}}}},
|
||||||
{{{{0xc100, 0x5a00, 0x6300}}}},
|
{{{{{0xc100, 0x5a00, 0x6300}}}}},
|
||||||
{{{{0x5e00, 0x3c00, 0x6c00}}}},
|
{{{{{0x5e00, 0x3c00, 0x6c00}}}}},
|
||||||
{{{{0x9d00, 0xbc00, 0x4000}}}},
|
{{{{{0x9d00, 0xbc00, 0x4000}}}}},
|
||||||
{{{{0xe000, 0xa300, 0x2e00}}}},
|
{{{{{0xe000, 0xa300, 0x2e00}}}}},
|
||||||
{{{{0x3800, 0x3d00, 0x9600}}}},
|
{{{{{0x3800, 0x3d00, 0x9600}}}}},
|
||||||
{{{{0x4600, 0x9400, 0x4900}}}},
|
{{{{{0x4600, 0x9400, 0x4900}}}}},
|
||||||
{{{{0xaf00, 0x3600, 0x3c00}}}},
|
{{{{{0xaf00, 0x3600, 0x3c00}}}}},
|
||||||
{{{{0xe700, 0xc700, 0x1f00}}}},
|
{{{{{0xe700, 0xc700, 0x1f00}}}}},
|
||||||
{{{{0xbb00, 0x5600, 0x9500}}}},
|
{{{{{0xbb00, 0x5600, 0x9500}}}}},
|
||||||
{{{{0x0800, 0x8500, 0xa100}}}},
|
{{{{{0x0800, 0x8500, 0xa100}}}}},
|
||||||
{{{{0xf300, 0xf300, 0xf200}}}},
|
{{{{{0xf300, 0xf300, 0xf200}}}}},
|
||||||
{{{{0xc800, 0xc800, 0xc800}}}},
|
{{{{{0xc800, 0xc800, 0xc800}}}}},
|
||||||
{{{{0xa000, 0xa000, 0xa000}}}},
|
{{{{{0xa000, 0xa000, 0xa000}}}}},
|
||||||
{{{{0x7a00, 0x7a00, 0x7900}}}},
|
{{{{{0x7a00, 0x7a00, 0x7900}}}}},
|
||||||
{{{{0x5500, 0x5500, 0x5500}}}},
|
{{{{{0x5500, 0x5500, 0x5500}}}}},
|
||||||
{{{{0x3400, 0x3400, 0x3400}}}},
|
{{{{{0x3400, 0x3400, 0x3400}}}}},
|
||||||
}};
|
}}};
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
std::array<Coord<2>, kColorCheckerSrgb.size()> FindClosest(const Image<X, Y, C>& image) {
|
Array<Coord<2>, kColorCheckerSrgb.size()> FindClosest(const Image<X, Y, C>& image) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
std::array<Coord<2>, kColorCheckerSrgb.size()> closest;
|
Array<Coord<2>, kColorCheckerSrgb.size()> closest;
|
||||||
std::array<uint32_t, kColorCheckerSrgb.size()> diff;
|
Array<int32_t, kColorCheckerSrgb.size()> diff;
|
||||||
diff.fill(UINT32_MAX);
|
diff.fill(INT32_MAX);
|
||||||
|
|
||||||
for (uint32_t y = 0; y < Y; ++y) {
|
for (int32_t y = 0; y < Y; ++y) {
|
||||||
const auto& row = image.at(y);
|
const auto& row = image.at(y);
|
||||||
|
|
||||||
for (uint32_t x = 0; x < X; ++x) {
|
for (int32_t x = 0; x < X; ++x) {
|
||||||
const auto& pixel = row.at(x);
|
const auto& pixel = row.at(x);
|
||||||
|
|
||||||
for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) {
|
for (int32_t cc = 0; cc < kColorCheckerSrgb.ssize(); ++cc) {
|
||||||
auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc));
|
auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc));
|
||||||
if (pixel_diff < diff.at(cc)) {
|
if (pixel_diff < diff.at(cc)) {
|
||||||
diff.at(cc) = pixel_diff;
|
diff.at(cc) = pixel_diff;
|
||||||
closest.at(cc) = {{{x, y}}};
|
closest.at(cc) = {{{{x, y}}}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,20 +68,20 @@ std::array<Coord<2>, kColorCheckerSrgb.size()> FindClosest(const Image<X, Y, C>&
|
|||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
uint32_t ScoreImage(const Image<X, Y, C>& image) {
|
int32_t ScoreImage(const Image<X, Y, C>& image) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
std::array<uint32_t, kColorCheckerSrgb.size()> diff;
|
Array<int32_t, kColorCheckerSrgb.size()> diff;
|
||||||
diff.fill(UINT32_MAX);
|
diff.fill(INT32_MAX);
|
||||||
|
|
||||||
for (uint32_t y = 0; y < Y; ++y) {
|
for (int32_t y = 0; y < Y; ++y) {
|
||||||
const auto& row = image.at(y);
|
const auto& row = image.at(y);
|
||||||
|
|
||||||
for (uint32_t x = 0; x < X; ++x) {
|
for (int32_t x = 0; x < X; ++x) {
|
||||||
const auto& pixel = row.at(x);
|
const auto& pixel = row.at(x);
|
||||||
|
|
||||||
for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) {
|
for (int32_t cc = 0; cc < kColorCheckerSrgb.ssize(); ++cc) {
|
||||||
auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc));
|
auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc));
|
||||||
if (pixel_diff < diff.at(cc)) {
|
if (pixel_diff < diff.at(cc)) {
|
||||||
diff.at(cc) = pixel_diff;
|
diff.at(cc) = pixel_diff;
|
||||||
@@ -90,47 +90,47 @@ uint32_t ScoreImage(const Image<X, Y, C>& image) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::accumulate(diff.begin(), diff.end(), UINT32_C(0));
|
return std::accumulate(diff.begin(), diff.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
std::unique_ptr<Image<X, Y, C>> HighlightClosest(const Image<X, Y, C>& image) {
|
std::unique_ptr<Image<X, Y, C>> HighlightClosest(const Image<X, Y, C>& image) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
auto out = std::make_unique<Image<X, Y, C>>(image);
|
auto out = std::make_unique<Image<X, Y, C>>(image);
|
||||||
|
|
||||||
auto closest = FindClosest(*out);
|
auto closest = FindClosest(*out);
|
||||||
for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) {
|
for (int32_t cc = 0; cc < kColorCheckerSrgb.ssize(); ++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);
|
||||||
out->DrawSquare({{{std::max(5U, coord.at(0)) - 5, std::max(5U, coord.at(1)) - 5}}}, kBlack, 10);
|
out->DrawSquare({{{{std::max(5, coord.at(0)) - 5, std::max(5, coord.at(1)) - 5}}}}, kBlack, 10);
|
||||||
out->DrawSquare({{{std::max(6U, coord.at(0)) - 6, std::max(6U, coord.at(1)) - 6}}}, color, 12);
|
out->DrawSquare({{{{std::max(6, coord.at(0)) - 6, std::max(6, coord.at(1)) - 6}}}}, color, 12);
|
||||||
out->DrawSquare({{{std::max(7U, coord.at(0)) - 7, std::max(7U, coord.at(1)) - 7}}}, color, 14);
|
out->DrawSquare({{{{std::max(7, coord.at(0)) - 7, std::max(7, coord.at(1)) - 7}}}}, color, 14);
|
||||||
out->DrawSquare({{{std::max(8U, coord.at(0)) - 8, std::max(8U, coord.at(1)) - 8}}}, color, 16);
|
out->DrawSquare({{{{std::max(8, coord.at(0)) - 8, std::max(8, coord.at(1)) - 8}}}}, color, 16);
|
||||||
out->DrawSquare({{{std::max(9U, coord.at(0)) - 9, std::max(9U, coord.at(1)) - 9}}}, kWhite, 18);
|
out->DrawSquare({{{{std::max(9, coord.at(0)) - 9, std::max(9, coord.at(1)) - 9}}}}, kWhite, 18);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t P, uint32_t LUT_X, uint32_t LUT_Y, uint32_t LUT_Z, uint32_t IMG_X, uint32_t IMG_Y, uint32_t C>
|
template <int32_t P, int32_t LUT_X, int32_t LUT_Y, int32_t LUT_Z, int32_t IMG_X, int32_t IMG_Y, int32_t C>
|
||||||
uint32_t OptimizeLut(const Image<IMG_X, IMG_Y, C>& image, Lut3d<LUT_X, LUT_Y, LUT_Z>* lut) {
|
int32_t OptimizeLut(const Image<IMG_X, IMG_Y, C>& image, Lut3d<LUT_X, LUT_Y, LUT_Z>* lut) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
auto snapshot = *lut;
|
auto snapshot = *lut;
|
||||||
uint32_t diff = 0;
|
int32_t diff = 0;
|
||||||
|
|
||||||
for (uint32_t x = 0; x < LUT_X; ++x) {
|
for (int32_t x = 0; x < LUT_X; ++x) {
|
||||||
auto& rect = lut->at(x);
|
auto& rect = lut->at(x);
|
||||||
|
|
||||||
for (uint32_t y = 0; y < LUT_Y; ++y) {
|
for (int32_t y = 0; y < LUT_Y; ++y) {
|
||||||
auto& row = rect.at(y);
|
auto& row = rect.at(y);
|
||||||
|
|
||||||
for (uint32_t z = 0; z < LUT_Z; ++z) {
|
for (int32_t z = 0; z < LUT_Z; ++z) {
|
||||||
auto& color = row.at(z);
|
auto& color = row.at(z);
|
||||||
|
|
||||||
std::cout << Coord<3>{{{x, y, z}}} << std::endl;
|
std::cout << Coord<3>{{{{x, y, z}}}} << std::endl;
|
||||||
|
|
||||||
for (uint32_t c = 0; c < C; ++c) {
|
for (int32_t c = 0; c < C; ++c) {
|
||||||
auto& channel = color.at(c);
|
auto& channel = color.at(c);
|
||||||
|
|
||||||
auto min = FindPossibleMinimum<int32_t, int32_t, 8>(
|
auto min = FindPossibleMinimum<int32_t, int32_t, 8>(
|
||||||
@@ -144,7 +144,7 @@ uint32_t OptimizeLut(const Image<IMG_X, IMG_Y, C>& image, Lut3d<LUT_X, LUT_Y, LU
|
|||||||
// of points that control any given given LUT mapping.
|
// of points that control any given given LUT mapping.
|
||||||
auto new_value = Interpolate(channel, min, INT32_C(1), INT32_C(8));
|
auto new_value = Interpolate(channel, min, INT32_C(1), INT32_C(8));
|
||||||
std::cout << "\tC" << c << ": " << channel << " -> " << new_value << " (interpolated from " << min << ")" << std::endl;
|
std::cout << "\tC" << c << ": " << channel << " -> " << new_value << " (interpolated from " << min << ")" << std::endl;
|
||||||
diff += static_cast<uint32_t>(AbsDiff(channel, new_value));
|
diff += AbsDiff(channel, new_value);
|
||||||
channel = new_value;
|
channel = new_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
colors.h
4
colors.h
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
|
||||||
constexpr RgbColor kBlack = {{{{0x0000, 0x0000, 0x0000}}}};
|
constexpr RgbColor kBlack = {{{{{0x0000, 0x0000, 0x0000}}}}};
|
||||||
constexpr RgbColor kWhite = {{{{0xffff, 0xffff, 0xffff}}}};
|
constexpr RgbColor kWhite = {{{{{0xffff, 0xffff, 0xffff}}}}};
|
||||||
|
|||||||
10
coord.h
10
coord.h
@@ -3,13 +3,15 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
template <uint32_t D>
|
#include "array.h"
|
||||||
struct Coord : public std::array<uint32_t, D> {};
|
|
||||||
|
|
||||||
template <uint32_t D>
|
template <int32_t D>
|
||||||
|
struct Coord : public Array<int32_t, D> {};
|
||||||
|
|
||||||
|
template <int32_t D>
|
||||||
std::ostream& operator<<(std::ostream& os, const Coord<D>& coord) {
|
std::ostream& operator<<(std::ostream& os, const Coord<D>& coord) {
|
||||||
os << "(";
|
os << "(";
|
||||||
for (uint32_t d = 0; d < D; ++d) {
|
for (int32_t d = 0; d < D; ++d) {
|
||||||
os << coord.at(d);
|
os << coord.at(d);
|
||||||
if (d < D - 1) {
|
if (d < D - 1) {
|
||||||
os << ", ";
|
os << ", ";
|
||||||
|
|||||||
55
image.h
55
image.h
@@ -5,59 +5,60 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "coord.h"
|
#include "coord.h"
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
class Image : public std::array<std::array<Color<C>, X>, Y> {
|
class Image : public Array<Array<Color<C>, X>, Y> {
|
||||||
public:
|
public:
|
||||||
constexpr const Color<C>& GetPixel(const Coord<2>& coord) const;
|
constexpr const Color<C>& GetPixel(const Coord<2>& coord) const;
|
||||||
|
|
||||||
void SetPixel(const Coord<2>& coord, const Color<C>& color);
|
void SetPixel(const Coord<2>& coord, const Color<C>& color);
|
||||||
void DrawXLine(const Coord<2>& start, const Color<C>& color, uint32_t length);
|
void DrawXLine(const Coord<2>& start, const Color<C>& color, int32_t length);
|
||||||
void DrawYLine(const Coord<2>& start, const Color<C>& color, uint32_t length);
|
void DrawYLine(const Coord<2>& start, const Color<C>& color, int32_t length);
|
||||||
void DrawRectangle(const Coord<2>& start, const Color<C>& color, uint32_t x_length, uint32_t y_length);
|
void DrawRectangle(const Coord<2>& start, const Color<C>& color, int32_t x_length, int32_t y_length);
|
||||||
void DrawSquare(const Coord<2>& start, const Color<C>& color, uint32_t length);
|
void DrawSquare(const Coord<2>& start, const Color<C>& color, int32_t length);
|
||||||
|
|
||||||
std::string ToPng();
|
std::string ToPng();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
constexpr const Color<C>& Image<X, Y, C>::GetPixel(const Coord<2>& coord) const {
|
constexpr const Color<C>& Image<X, Y, C>::GetPixel(const Coord<2>& coord) const {
|
||||||
return this->at(coord.at(1)).at(coord.at(0));
|
return this->at(coord.at(1)).at(coord.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
void Image<X, Y, C>::SetPixel(const Coord<2>& coord, const Color<C>& color) {
|
void Image<X, Y, C>::SetPixel(const Coord<2>& coord, const Color<C>& color) {
|
||||||
this->at(coord.at(1)).at(coord.at(0)) = color;
|
this->at(coord.at(1)).at(coord.at(0)) = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
void Image<X, Y, C>::DrawXLine(const Coord<2>& coord, const Color<C>& color, uint32_t length) {
|
void Image<X, Y, C>::DrawXLine(const Coord<2>& coord, const Color<C>& color, int32_t length) {
|
||||||
auto& row = this->at(coord.at(1));
|
auto& row = this->at(coord.at(1));
|
||||||
|
|
||||||
for (uint32_t x = coord.at(0); x < std::min(X, coord.at(0) + length); ++x) {
|
for (int32_t x = coord.at(0); x < std::min(X, coord.at(0) + length); ++x) {
|
||||||
row.at(x) = color;
|
row.at(x) = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
void Image<X, Y, C>::DrawYLine(const Coord<2>& coord, const Color<C>& color, uint32_t length) {
|
void Image<X, Y, C>::DrawYLine(const Coord<2>& coord, const Color<C>& color, int32_t length) {
|
||||||
for (uint32_t y = coord.at(1); y <= std::min(Y, coord.at(1) + length); ++y) {
|
for (int32_t y = coord.at(1); y <= std::min(Y, coord.at(1) + length); ++y) {
|
||||||
SetPixel({{{coord.at(0), y}}}, color);
|
SetPixel({{{{coord.at(0), y}}}}, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
void Image<X, Y, C>::DrawRectangle(const Coord<2>& start, const Color<C>& color, uint32_t x_length, uint32_t y_length) {
|
void Image<X, Y, C>::DrawRectangle(const Coord<2>& start, const Color<C>& color, int32_t x_length, int32_t y_length) {
|
||||||
DrawXLine(start, color, x_length);
|
DrawXLine(start, color, x_length);
|
||||||
DrawXLine({{{start.at(0), start.at(1) + y_length}}}, color, x_length);
|
DrawXLine({{{{start.at(0), start.at(1) + y_length}}}}, color, x_length);
|
||||||
DrawYLine(start, color, y_length);
|
DrawYLine(start, color, y_length);
|
||||||
DrawYLine({{{start.at(0) + x_length, start.at(1)}}}, color, y_length);
|
DrawYLine({{{{start.at(0) + x_length, start.at(1)}}}}, color, y_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
void Image<X, Y, C>::DrawSquare(const Coord<2>& start, const Color<C>& color, uint32_t length) {
|
void Image<X, Y, C>::DrawSquare(const Coord<2>& start, const Color<C>& color, int32_t length) {
|
||||||
DrawRectangle(start, color, length, length);
|
DrawRectangle(start, color, length, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ static inline void WriteCallback(png_structp png_ptr, png_bytep data, png_size_t
|
|||||||
dest->append(reinterpret_cast<char*>(data), length);
|
dest->append(reinterpret_cast<char*>(data), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C>
|
template <int32_t X, int32_t Y, int32_t C>
|
||||||
std::string Image<X, Y, C>::ToPng() {
|
std::string Image<X, Y, C>::ToPng() {
|
||||||
static_assert(C == 3); // PNG only supports RGB
|
static_assert(C == 3); // PNG only supports RGB
|
||||||
|
|
||||||
@@ -84,11 +85,11 @@ std::string Image<X, Y, C>::ToPng() {
|
|||||||
|
|
||||||
png_write_info(png_ptr, info_ptr);
|
png_write_info(png_ptr, info_ptr);
|
||||||
for (auto& row : *this) {
|
for (auto& row : *this) {
|
||||||
std::array<uint16_t, X * 3> out_row;
|
Array<uint16_t, X * 3> out_row;
|
||||||
for (uint32_t x = 0; x < X; ++x) {
|
for (int32_t x = 0; x < X; ++x) {
|
||||||
out_row[x * 3 + 0] = htons(static_cast<uint16_t>(row[x].at(0)));
|
out_row.at(x * 3 + 0) = htons(static_cast<uint16_t>(row.at(x).at(0)));
|
||||||
out_row[x * 3 + 1] = htons(static_cast<uint16_t>(row[x].at(1)));
|
out_row.at(x * 3 + 1) = htons(static_cast<uint16_t>(row.at(x).at(1)));
|
||||||
out_row[x * 3 + 2] = htons(static_cast<uint16_t>(row[x].at(2)));
|
out_row.at(x * 3 + 2) = htons(static_cast<uint16_t>(row.at(x).at(2)));
|
||||||
}
|
}
|
||||||
png_write_row(png_ptr, reinterpret_cast<unsigned char*>(out_row.data()));
|
png_write_row(png_ptr, reinterpret_cast<unsigned char*>(out_row.data()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ constexpr T AbsDiff(T a, T b) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T Interpolate(T val0, T val1, T mul, T div) {
|
constexpr T Interpolate(T val0, T val1, T mul, T div) {
|
||||||
return val0 + ((mul * (val1 - val0)) / div);
|
return val0 + static_cast<int32_t>((static_cast<int64_t>(mul) * (val1 - val0)) / div);
|
||||||
}
|
}
|
||||||
|
|||||||
77
lut.h
77
lut.h
@@ -1,45 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "coord.h"
|
#include "coord.h"
|
||||||
|
|
||||||
// Hardcoded to Color<3>, so color dimensions == LUT dimensions
|
// Hardcoded to Color<3>, so color dimensions == LUT dimensions
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
class Lut3d : public std::array<std::array<std::array<Color<3>, X>, Y>, Z> {
|
class Lut3d : public Array<Array<Array<Color<3>, X>, Y>, Z> {
|
||||||
public:
|
public:
|
||||||
static Lut3d<X, Y, Z> Identity();
|
static Lut3d<X, Y, Z> Identity();
|
||||||
|
|
||||||
Color<3> MapColor(const Color<3>& in) const;
|
Color<3> MapColor(const Color<3>& in) const;
|
||||||
|
|
||||||
template <uint32_t IMG_X, uint32_t IMG_Y, uint32_t C>
|
template <int32_t IMG_X, int32_t IMG_Y, int32_t C>
|
||||||
std::unique_ptr<Image<IMG_X, IMG_Y, C>> MapImage(const Image<IMG_X, IMG_Y, C>& in) const;
|
std::unique_ptr<Image<IMG_X, IMG_Y, C>> MapImage(const Image<IMG_X, IMG_Y, C>& in) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Return value is (root_indices, remainders)
|
// Return value is (root_indices, remainders)
|
||||||
constexpr static std::pair<Coord<3>, Coord<3>> FindRoot(const Color<3>& 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 std::pair<int32_t, int32_t> FindChannelRoot(int32_t value, int32_t points);
|
||||||
|
|
||||||
constexpr static uint32_t BlockSize(uint32_t points);
|
constexpr static int32_t BlockSize(int32_t points);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Minimum size LUT
|
// Minimum size LUT
|
||||||
typedef Lut3d<2, 2, 2> MinimalLut3d;
|
typedef Lut3d<2, 2, 2> MinimalLut3d;
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
Lut3d<X, Y, Z> Lut3d<X, Y, Z>::Identity() {
|
Lut3d<X, Y, Z> Lut3d<X, Y, Z>::Identity() {
|
||||||
Lut3d<X, Y, Z> ret;
|
Lut3d<X, Y, Z> ret;
|
||||||
|
|
||||||
Color<3> color;
|
Color<3> color;
|
||||||
for (uint32_t x = 0; x < X; ++x) {
|
for (int32_t x = 0; x < X; ++x) {
|
||||||
auto& rect = ret.at(x);
|
auto& rect = ret.at(x);
|
||||||
color.at(0) = std::min(kMaxColor, static_cast<int32_t>(BlockSize(X) * x));
|
color.at(0) = std::min(kMaxColor, BlockSize(X) * x);
|
||||||
|
|
||||||
for (uint32_t y = 0; y < Y; ++y) {
|
for (int32_t y = 0; y < Y; ++y) {
|
||||||
auto& row = rect.at(y);
|
auto& row = rect.at(y);
|
||||||
color.at(1) = std::min(kMaxColor, static_cast<int32_t>(BlockSize(Y) * y));
|
color.at(1) = std::min(kMaxColor, BlockSize(Y) * y);
|
||||||
|
|
||||||
for (uint32_t z = 0; z < Z; ++z) {
|
for (int32_t z = 0; z < Z; ++z) {
|
||||||
color.at(2) = std::min(kMaxColor, static_cast<int32_t>(BlockSize(Z) * z));
|
color.at(2) = std::min(kMaxColor, BlockSize(Z) * z);
|
||||||
row.at(z) = color;
|
row.at(z) = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@ Lut3d<X, Y, Z> Lut3d<X, Y, Z>::Identity() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
Color<3> Lut3d<X, Y, Z>::MapColor(const Color<3>& in) const {
|
Color<3> Lut3d<X, Y, Z>::MapColor(const Color<3>& in) const {
|
||||||
const auto root_rem = FindRoot(in);
|
const auto root_rem = FindRoot(in);
|
||||||
const auto& root = root_rem.first;
|
const auto& root = root_rem.first;
|
||||||
@@ -58,41 +59,37 @@ Color<3> Lut3d<X, Y, Z>::MapColor(const Color<3>& in) const {
|
|||||||
auto inter00 =
|
auto inter00 =
|
||||||
this->at(root.at(0) + 0).at(root.at(1) + 0).at(root.at(2) + 0).Interpolate(
|
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),
|
this->at(root.at(0) + 1).at(root.at(1) + 0).at(root.at(2) + 0),
|
||||||
static_cast<int32_t>(rem.at(0)),
|
rem.at(0), BlockSize(X));
|
||||||
BlockSize(X));
|
|
||||||
|
|
||||||
auto inter01 =
|
auto inter01 =
|
||||||
this->at(root.at(0) + 0).at(root.at(1) + 0).at(root.at(2) + 1).Interpolate(
|
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),
|
this->at(root.at(0) + 1).at(root.at(1) + 0).at(root.at(2) + 1),
|
||||||
static_cast<int32_t>(rem.at(0)),
|
rem.at(0), BlockSize(X));
|
||||||
BlockSize(X));
|
|
||||||
|
|
||||||
auto inter10 =
|
auto inter10 =
|
||||||
this->at(root.at(0) + 0).at(root.at(1) + 1).at(root.at(2) + 0).Interpolate(
|
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),
|
this->at(root.at(0) + 1).at(root.at(1) + 1).at(root.at(2) + 0),
|
||||||
static_cast<int32_t>(rem.at(0)),
|
rem.at(0), BlockSize(X));
|
||||||
BlockSize(X));
|
|
||||||
|
|
||||||
auto inter11 =
|
auto inter11 =
|
||||||
this->at(root.at(0) + 0).at(root.at(1) + 1).at(root.at(2) + 1).Interpolate(
|
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),
|
this->at(root.at(0) + 1).at(root.at(1) + 1).at(root.at(2) + 1),
|
||||||
static_cast<int32_t>(rem.at(0)),
|
rem.at(0), BlockSize(X));
|
||||||
BlockSize(X));
|
|
||||||
|
|
||||||
auto inter0 = inter00.Interpolate(inter10, static_cast<int32_t>(rem.at(1)), BlockSize(Y));
|
auto inter0 = inter00.Interpolate(inter10, rem.at(1), BlockSize(Y));
|
||||||
auto inter1 = inter01.Interpolate(inter11, static_cast<int32_t>(rem.at(1)), BlockSize(Y));
|
auto inter1 = inter01.Interpolate(inter11, rem.at(1), BlockSize(Y));
|
||||||
|
|
||||||
return inter0.Interpolate(inter1, static_cast<int32_t>(rem.at(2)), BlockSize(Z)).Crop();
|
return inter0.Interpolate(inter1, rem.at(2), BlockSize(Z)).Crop();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
template <uint32_t IMG_X, uint32_t IMG_Y, uint32_t C>
|
template <int32_t IMG_X, int32_t IMG_Y, int32_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 {
|
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>>();
|
auto out = std::make_unique<Image<IMG_X, IMG_Y, C>>();
|
||||||
|
|
||||||
for (uint32_t y = 0; y < IMG_Y; ++y) {
|
for (int32_t y = 0; y < IMG_Y; ++y) {
|
||||||
for (uint32_t x = 0; x < IMG_X; ++x) {
|
for (int32_t x = 0; x < IMG_X; ++x) {
|
||||||
Coord<2> coord = {{{x, y}}};
|
Coord<2> coord = {{{{x, y}}}};
|
||||||
out->SetPixel(coord, MapColor(in.GetPixel(coord)));
|
out->SetPixel(coord, MapColor(in.GetPixel(coord)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,27 +97,27 @@ std::unique_ptr<Image<IMG_X, IMG_Y, C>> Lut3d<X, Y, Z>::MapImage(const Image<IMG
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
constexpr std::pair<Coord<3>, Coord<3>> Lut3d<X, Y, Z>::FindRoot(const Color<3>& in) {
|
constexpr std::pair<Coord<3>, Coord<3>> Lut3d<X, Y, Z>::FindRoot(const Color<3>& in) {
|
||||||
auto root_x = FindChannelRoot(static_cast<uint32_t>(in.at(0)), X);
|
auto root_x = FindChannelRoot(in.at(0), X);
|
||||||
auto root_y = FindChannelRoot(static_cast<uint32_t>(in.at(1)), Y);
|
auto root_y = FindChannelRoot(in.at(1), Y);
|
||||||
auto root_z = FindChannelRoot(static_cast<uint32_t>(in.at(2)), Z);
|
auto root_z = FindChannelRoot(in.at(2), Z);
|
||||||
return {
|
return {
|
||||||
{{{root_x.first, root_y.first, root_z.first}}},
|
{{{{root_x.first, root_y.first, root_z.first}}}},
|
||||||
{{{root_x.second, root_y.second, root_z.second}}},
|
{{{{root_x.second, root_y.second, root_z.second}}}},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
constexpr std::pair<uint32_t, uint32_t> Lut3d<X, Y, Z>::FindChannelRoot(const uint32_t value, const uint32_t points) {
|
constexpr std::pair<int32_t, int32_t> Lut3d<X, Y, Z>::FindChannelRoot(const int32_t value, const int32_t points) {
|
||||||
// points - 1 is the last point index. Since we're going to fidn the cube
|
// 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
|
// around this point by adding to the root, we need to be at least 1 less
|
||||||
// than that.
|
// than that.
|
||||||
uint32_t index = std::min(points - 2, value / BlockSize(points));
|
int32_t index = std::min(points - 2, value / BlockSize(points));
|
||||||
return std::make_pair(index, value - (index * BlockSize(points)));
|
return std::make_pair(index, value - (index * BlockSize(points)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t Z>
|
template <int32_t X, int32_t Y, int32_t Z>
|
||||||
constexpr uint32_t Lut3d<X, Y, Z>::BlockSize(uint32_t points) {
|
constexpr int32_t Lut3d<X, Y, Z>::BlockSize(int32_t points) {
|
||||||
return (kMaxColor + 1) / (points - 1);
|
return (kMaxColor + 1) / (points - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ I FindPossibleMinimum(I min, I max, std::function<O(I)> callback) {
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<Range<I, O>, P> ranges;
|
Array<Range<I, O>, P> ranges;
|
||||||
|
|
||||||
const I step = ((max - min) / P) + 1;
|
const I step = ((max - min) / P) + 1;
|
||||||
const I offset = step / 2;
|
const I offset = step / 2;
|
||||||
for (uint32_t i = 0; i < P; ++i) {
|
for (int32_t i = 0; i < P; ++i) {
|
||||||
auto& range = ranges.at(i);
|
auto& range = ranges.at(i);
|
||||||
range.start = std::min(max, min + static_cast<int32_t>(i) * step);
|
range.start = std::min(max, min + i * step);
|
||||||
range.end = std::min(max, range.start + (step - 1));
|
range.end = std::min(max, range.start + (step - 1));
|
||||||
range.testpoint = range.start + offset;
|
range.testpoint = range.start + offset;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ int main() {
|
|||||||
std::cout << "Initial error: " << ScoreImage(*image) << std::endl;
|
std::cout << "Initial error: " << ScoreImage(*image) << std::endl;
|
||||||
|
|
||||||
auto lut = MinimalLut3d::Identity();
|
auto lut = MinimalLut3d::Identity();
|
||||||
uint32_t diff = 1;
|
int32_t diff = 1;
|
||||||
while (diff) {
|
while (diff) {
|
||||||
diff = OptimizeLut<4>(*image, &lut);
|
diff = OptimizeLut<4>(*image, &lut);
|
||||||
std::cout << "diff=" << diff << " error=" << ScoreImage(*lut.MapImage(*image)) << std::endl;
|
std::cout << "diff=" << diff << " error=" << ScoreImage(*lut.MapImage(*image)) << std::endl;
|
||||||
|
|||||||
72
piraw.h
72
piraw.h
@@ -10,7 +10,7 @@ namespace std {
|
|||||||
using string_view = experimental::string_view;
|
using string_view = experimental::string_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
class PiRaw {
|
class PiRaw {
|
||||||
public:
|
public:
|
||||||
PiRaw() = delete;
|
PiRaw() = delete;
|
||||||
@@ -21,36 +21,36 @@ class PiRaw {
|
|||||||
static std::unique_ptr<Image<X / 2, Y / 2, C>> FromRaw(const std::string_view& raw);
|
static std::unique_ptr<Image<X / 2, Y / 2, C>> FromRaw(const std::string_view& raw);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint32_t kJpegHeaderBytes = 32768;
|
static constexpr int32_t kJpegHeaderBytes = 32768;
|
||||||
static constexpr const char* kJpegHeaderMagic = "BRCM";
|
static constexpr const char* kJpegHeaderMagic = "BRCM";
|
||||||
static constexpr uint32_t kPixelsPerChunk = 4;
|
static constexpr int32_t kPixelsPerChunk = 4;
|
||||||
static constexpr uint32_t kBitsPerByte = 8;
|
static constexpr int32_t kBitsPerByte = 8;
|
||||||
|
|
||||||
static constexpr uint32_t GetRawBytes();
|
static constexpr int32_t GetRawBytes();
|
||||||
static constexpr uint32_t GetRowBytes();
|
static constexpr int32_t GetRowBytes();
|
||||||
static constexpr uint32_t GetNumRows();
|
static constexpr int32_t GetNumRows();
|
||||||
static constexpr uint32_t GetChunkBytes();
|
static constexpr int32_t GetChunkBytes();
|
||||||
|
|
||||||
static constexpr uint32_t Align(uint32_t val);
|
static constexpr int32_t Align(int32_t val);
|
||||||
|
|
||||||
typedef std::array<uint32_t, kPixelsPerChunk> Chunk;
|
typedef Array<int32_t, kPixelsPerChunk> Chunk;
|
||||||
|
|
||||||
static constexpr Chunk GetChunk(const std::string_view& raw, const uint32_t x_chunk, const uint32_t y);
|
static constexpr Chunk GetChunk(const std::string_view& raw, const int32_t x_chunk, const int32_t y);
|
||||||
static constexpr Color<C> CombineRaw(uint32_t y0x0, uint32_t y0x1, uint32_t y1x0, uint32_t y1x1);
|
static constexpr Color<C> CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PiRaw<3280, 2464, 3, 10, 16, 2> PiRaw2;
|
typedef PiRaw<3280, 2464, 3, 10, 16, 2> PiRaw2;
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromJpeg(const std::string_view& jpeg) {
|
typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromJpeg(const std::string_view& jpeg) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
auto container_len = GetRawBytes() + kJpegHeaderBytes;
|
size_t container_len = GetRawBytes() + kJpegHeaderBytes;
|
||||||
assert(jpeg.substr(jpeg.size() - container_len, 4) == kJpegHeaderMagic);
|
assert(jpeg.substr(jpeg.size() - container_len, 4) == kJpegHeaderMagic);
|
||||||
return FromRaw(jpeg.substr(jpeg.size() - GetRawBytes(), GetRawBytes()));
|
return FromRaw(jpeg.substr(jpeg.size() - GetRawBytes(), GetRawBytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromRaw(const std::string_view& raw) {
|
typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromRaw(const std::string_view& raw) {
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
static_assert(X % 2 == 0);
|
static_assert(X % 2 == 0);
|
||||||
@@ -61,8 +61,8 @@ typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromRa
|
|||||||
|
|
||||||
auto image = std::make_unique<Image<X / 2, Y / 2, C>>();
|
auto image = std::make_unique<Image<X / 2, Y / 2, C>>();
|
||||||
|
|
||||||
for (uint32_t y = 0, out_y = 0; y < Y; y += 2, ++out_y) {
|
for (int32_t y = 0, out_y = 0; y < Y; y += 2, ++out_y) {
|
||||||
for (uint32_t x_chunk = 0, out_x = 0; x_chunk < X / kPixelsPerChunk; ++x_chunk, out_x += kPixelsPerChunk / 2) {
|
for (int32_t x_chunk = 0, out_x = 0; x_chunk < X / kPixelsPerChunk; ++x_chunk, out_x += kPixelsPerChunk / 2) {
|
||||||
auto chunk1 = GetChunk(raw, x_chunk, y + 0);
|
auto chunk1 = GetChunk(raw, x_chunk, y + 0);
|
||||||
auto chunk2 = GetChunk(raw, x_chunk, y + 1);
|
auto chunk2 = GetChunk(raw, x_chunk, y + 1);
|
||||||
image->at(out_y).at(out_x + 0) = CombineRaw(chunk1.at(0), chunk1.at(1), chunk2.at(0), chunk2.at(1));
|
image->at(out_y).at(out_x + 0) = CombineRaw(chunk1.at(0), chunk1.at(1), chunk2.at(0), chunk2.at(1));
|
||||||
@@ -72,38 +72,38 @@ typename std::unique_ptr<Image<X / 2, Y / 2, C>> PiRaw<X, Y, C, D, A, P>::FromRa
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr uint32_t PiRaw<X, Y, C, D, A, P>::GetRawBytes() {
|
constexpr int32_t PiRaw<X, Y, C, D, A, P>::GetRawBytes() {
|
||||||
return GetRowBytes() * GetNumRows();
|
return GetRowBytes() * GetNumRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr uint32_t PiRaw<X, Y, C, D, A, P>::GetRowBytes() {
|
constexpr int32_t PiRaw<X, Y, C, D, A, P>::GetRowBytes() {
|
||||||
return Align(Align(X + P) * D / kBitsPerByte);
|
return Align(Align(X + P) * D / kBitsPerByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr uint32_t PiRaw<X, Y, C, D, A, P>::GetNumRows() {
|
constexpr int32_t PiRaw<X, Y, C, D, A, P>::GetNumRows() {
|
||||||
return Align(Y + P);
|
return Align(Y + P);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr uint32_t PiRaw<X, Y, C, D, A, P>::GetChunkBytes() {
|
constexpr int32_t PiRaw<X, Y, C, D, A, P>::GetChunkBytes() {
|
||||||
return D * kPixelsPerChunk / kBitsPerByte;
|
return D * kPixelsPerChunk / kBitsPerByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr uint32_t PiRaw<X, Y, C, D, A, P>::Align(uint32_t val) {
|
constexpr int32_t PiRaw<X, Y, C, D, A, P>::Align(int32_t val) {
|
||||||
return (~(A - 1)) & ((val) + (A - 1));
|
return (~(A - 1)) & ((val) + (A - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr typename PiRaw<X, Y, C, D, A, P>::Chunk PiRaw<X, Y, C, D, A, P>::GetChunk(const std::string_view& raw, const uint32_t x_chunk, const uint32_t y) {
|
constexpr typename PiRaw<X, Y, C, D, A, P>::Chunk PiRaw<X, Y, C, D, A, P>::GetChunk(const std::string_view& raw, const int32_t x_chunk, const int32_t y) {
|
||||||
// Function is bit depth & layout specific
|
// Function is bit depth & layout specific
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
static_assert(D == 10);
|
static_assert(D == 10);
|
||||||
|
|
||||||
uint32_t start = y * GetRowBytes() + x_chunk * GetChunkBytes();
|
size_t start = static_cast<size_t>(y * GetRowBytes() + x_chunk * GetChunkBytes());
|
||||||
uint32_t high0 = static_cast<uint8_t>(raw.at(start + 0));
|
uint32_t high0 = static_cast<uint8_t>(raw.at(start + 0));
|
||||||
uint32_t high1 = static_cast<uint8_t>(raw.at(start + 1));
|
uint32_t high1 = static_cast<uint8_t>(raw.at(start + 1));
|
||||||
uint32_t high2 = static_cast<uint8_t>(raw.at(start + 2));
|
uint32_t high2 = static_cast<uint8_t>(raw.at(start + 2));
|
||||||
@@ -111,15 +111,15 @@ constexpr typename PiRaw<X, Y, C, D, A, P>::Chunk PiRaw<X, Y, C, D, A, P>::GetCh
|
|||||||
uint32_t packed_low = static_cast<uint8_t>(raw.at(start + 4));
|
uint32_t packed_low = static_cast<uint8_t>(raw.at(start + 4));
|
||||||
|
|
||||||
Chunk ret;
|
Chunk ret;
|
||||||
ret.at(0) = ((high0 << 2) | ((packed_low >> 6) & 0b11)) << 6;
|
ret.at(0) = static_cast<int32_t>(((high0 << 2) | ((packed_low >> 6) & 0b11)) << 6);
|
||||||
ret.at(1) = ((high1 << 2) | ((packed_low >> 4) & 0b11)) << 6;
|
ret.at(1) = static_cast<int32_t>(((high1 << 2) | ((packed_low >> 4) & 0b11)) << 6);
|
||||||
ret.at(2) = ((high2 << 2) | ((packed_low >> 2) & 0b11)) << 6;
|
ret.at(2) = static_cast<int32_t>(((high2 << 2) | ((packed_low >> 2) & 0b11)) << 6);
|
||||||
ret.at(3) = ((high3 << 2) | ((packed_low >> 0) & 0b11)) << 6;
|
ret.at(3) = static_cast<int32_t>(((high3 << 2) | ((packed_low >> 0) & 0b11)) << 6);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t X, uint32_t Y, uint32_t C, uint32_t D, uint32_t A, uint32_t P>
|
template <int32_t X, int32_t Y, int32_t C, int32_t D, int32_t A, int32_t P>
|
||||||
constexpr Color<C> PiRaw<X, Y, C, D, A, P>::CombineRaw(uint32_t y0x0, uint32_t y0x1, uint32_t y1x0, uint32_t y1x1) {
|
constexpr Color<C> PiRaw<X, Y, C, D, A, P>::CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1) {
|
||||||
// Function is bit layout specific
|
// Function is bit layout specific
|
||||||
static_assert(C == 3);
|
static_assert(C == 3);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user