diff --git a/color.h b/color.h index 4bd057c..e4d7e16 100644 --- a/color.h +++ b/color.h @@ -7,28 +7,30 @@ #include "intmath.h" -constexpr uint32_t kMaxColor = UINT16_MAX; +constexpr int32_t kMinColor = 0; +constexpr int32_t kMaxColor = UINT16_MAX; // 32-bit for compiler convenience, but values are 16-bit template -struct Color : public std::array { - constexpr uint32_t Difference(const Color& other) const; - constexpr Color Interpolate(const Color& other, uint32_t mul, uint32_t div) const; +struct Color : public std::array { + constexpr uint32_t AbsDiff(const Color& other) const; + constexpr Color Interpolate(const Color& other, int32_t mul, int32_t div) const; + constexpr Color Crop() const; }; struct RgbColor : public Color<3> {}; template -constexpr uint32_t Color::Difference(const Color& other) const { +constexpr uint32_t Color::AbsDiff(const Color& other) const { uint32_t diff = 0; for (uint32_t c = 0; c < C; ++c) { - diff += AbsDiff(this->at(c), other.at(c)); + diff += static_cast(::AbsDiff(this->at(c), other.at(c))); } return diff; } template -constexpr Color Color::Interpolate(const Color& other, uint32_t mul, uint32_t div) const { +constexpr Color Color::Interpolate(const Color& other, int32_t mul, int32_t div) const { Color ret; for (uint32_t c = 0; c < C; ++c) { ret.at(c) = ::Interpolate(this->at(c), other.at(c), mul, div); @@ -36,6 +38,15 @@ constexpr Color Color::Interpolate(const Color& other, uint32_t mul, ui return ret; } +template +constexpr Color Color::Crop() const { + Color ret; + for (uint32_t c = 0; c < C; ++c) { + ret.at(c) = std::max(kMinColor, std::min(kMaxColor, this->at(c))); + } + return ret; +} + template std::ostream& operator<<(std::ostream& os, const Color& color) { os << std::hex << std::setfill('0') << "Color("; diff --git a/colorchecker.h b/colorchecker.h index 17da045..e61b3b2 100644 --- a/colorchecker.h +++ b/colorchecker.h @@ -56,7 +56,7 @@ std::array, kColorCheckerSrgb.size()> FindClosest(const Image& const auto& pixel = row.at(x); for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) { - auto pixel_diff = pixel.Difference(kColorCheckerSrgb.at(cc)); + auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc)); if (pixel_diff < diff.at(cc)) { diff.at(cc) = pixel_diff; closest.at(cc) = {{{x, y}}}; @@ -82,7 +82,7 @@ uint32_t ScoreImage(const Image& image) { const auto& pixel = row.at(x); for (uint32_t cc = 0; cc < kColorCheckerSrgb.size(); ++cc) { - auto pixel_diff = pixel.Difference(kColorCheckerSrgb.at(cc)); + auto pixel_diff = pixel.AbsDiff(kColorCheckerSrgb.at(cc)); if (pixel_diff < diff.at(cc)) { diff.at(cc) = pixel_diff; } @@ -133,18 +133,18 @@ uint32_t OptimizeLut(const Image& image, Lut3d( - 0, UINT16_MAX, - [&image, &snapshot, x, y, z, c](uint32_t val) { + auto min = FindPossibleMinimum( + -UINT16_MAX, UINT16_MAX * 2, + [&image, &snapshot, x, y, z, c](int32_t val) { auto test_lut = snapshot; test_lut.at(x).at(y).at(z).at(c) = val; return ScoreImage(*test_lut.MapImage(image)); }); // Magic value of 8 is the number of points making up a square, so the number // of points that control any given given LUT mapping. - auto new_value = Interpolate(channel, min, UINT32_C(1), UINT32_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; - diff += AbsDiff(channel, new_value); + diff += static_cast(AbsDiff(channel, new_value)); channel = new_value; } } diff --git a/intmath.h b/intmath.h index 77c49f5..921f4f8 100644 --- a/intmath.h +++ b/intmath.h @@ -2,14 +2,10 @@ template constexpr T AbsDiff(T a, T b) { - return (a > b) ? (a - b) : (b - a); + return std::abs(b - a); } template constexpr T Interpolate(T val0, T val1, T mul, T div) { - if (val1 > val0) { - return val0 + ((mul * (val1 - val0)) / div); - } else { - return val0 - ((mul * (val0 - val1)) / div); - } + return val0 + ((mul * (val1 - val0)) / div); } diff --git a/lut.h b/lut.h index ee6c48c..0a9d223 100644 --- a/lut.h +++ b/lut.h @@ -32,14 +32,14 @@ Lut3d Lut3d::Identity() { 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); + color.at(0) = std::min(kMaxColor, static_cast(BlockSize(X) * x)); for (uint32_t y = 0; y < Y; ++y) { auto& row = rect.at(y); - color.at(1) = std::min(kMaxColor, BlockSize(Y) * y); + color.at(1) = std::min(kMaxColor, static_cast(BlockSize(Y) * y)); for (uint32_t z = 0; z < Z; ++z) { - color.at(2) = std::min(kMaxColor, BlockSize(Z) * z); + color.at(2) = std::min(kMaxColor, static_cast(BlockSize(Z) * z)); row.at(z) = color; } } @@ -58,31 +58,31 @@ Color<3> Lut3d::MapColor(const Color<3>& in) const { 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), + static_cast(rem.at(0)), BlockSize(X)); 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), + static_cast(rem.at(0)), BlockSize(X)); 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), + static_cast(rem.at(0)), BlockSize(X)); 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), + static_cast(rem.at(0)), BlockSize(X)); - auto inter0 = inter00.Interpolate(inter10, rem.at(1), BlockSize(Y)); - auto inter1 = inter01.Interpolate(inter11, rem.at(1), BlockSize(Y)); + auto inter0 = inter00.Interpolate(inter10, static_cast(rem.at(1)), BlockSize(Y)); + auto inter1 = inter01.Interpolate(inter11, static_cast(rem.at(1)), BlockSize(Y)); - return inter0.Interpolate(inter1, rem.at(2), BlockSize(Z)); + return inter0.Interpolate(inter1, static_cast(rem.at(2)), BlockSize(Z)).Crop(); } template @@ -102,9 +102,9 @@ std::unique_ptr> Lut3d::MapImage(const Image constexpr std::pair, Coord<3>> Lut3d::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); + auto root_x = FindChannelRoot(static_cast(in.at(0)), X); + auto root_y = FindChannelRoot(static_cast(in.at(1)), Y); + auto root_z = FindChannelRoot(static_cast(in.at(2)), Z); return { {{{root_x.first, root_y.first, root_z.first}}}, {{{root_x.second, root_y.second, root_z.second}}}, diff --git a/minimum.h b/minimum.h index c1fe181..eecf6e7 100644 --- a/minimum.h +++ b/minimum.h @@ -15,7 +15,7 @@ struct Range { // Since it does a non-exhaustive search, can be fooled by distributions with // multiple peaks, especially those with the minimum in a narrow valley and // other wider valleys. -template +template I FindPossibleMinimum(I min, I max, std::function callback) { if (min == max) { return min; @@ -26,8 +26,8 @@ I FindPossibleMinimum(I min, I max, std::function callback) { const I step = ((max - min) / P) + 1; const I offset = step / 2; for (uint32_t i = 0; i < P; ++i) { - auto& range = ranges[i]; - range.start = std::min(max, min + i * step); + auto& range = ranges.at(i); + range.start = std::min(max, min + static_cast(i) * step); range.end = std::min(max, range.start + (step - 1)); range.testpoint = range.start + offset; } diff --git a/piraw.h b/piraw.h index 706306c..dd494c8 100644 --- a/piraw.h +++ b/piraw.h @@ -124,8 +124,8 @@ constexpr Color PiRaw::CombineRaw(uint32_t y0x0, uint32_t y static_assert(C == 3); Color ret; - ret.at(0) = y1x1; - ret.at(1) = (y0x1 + y1x0) / 2; - ret.at(2) = y0x0; + ret.at(0) = static_cast(y1x1); + ret.at(1) = static_cast((y0x1 + y1x0) / 2); + ret.at(2) = static_cast(y0x0); return ret; }