From a74b4188bcff92a48f65b1b93b1d333f019a7925 Mon Sep 17 00:00:00 2001 From: Awawa <69086569+awawa-dev@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:03:45 +0200 Subject: [PATCH] Added 3'th LCH layer, increased number of vertices, more CPU needed --- include/lut-calibrator/BestResult.h | 13 +- include/lut-calibrator/CapturedColor.h | 2 +- sources/lut-calibrator/CapturedColor.cpp | 112 +++++++---------- sources/lut-calibrator/LutCalibrator.cpp | 145 +++++++++++++++-------- 4 files changed, 149 insertions(+), 123 deletions(-) diff --git a/include/lut-calibrator/BestResult.h b/include/lut-calibrator/BestResult.h index 9fad2bb61..63b5a0b52 100644 --- a/include/lut-calibrator/BestResult.h +++ b/include/lut-calibrator/BestResult.h @@ -49,6 +49,13 @@ using namespace aliases; using namespace ColorSpaceMath; using namespace BoardUtils; +struct LchLists +{ + std::list low; + std::list mid; + std::list high; +}; + struct BestResult { YuvConverter::YUV_COEFS coef = YuvConverter::YUV_COEFS::BT601; @@ -64,7 +71,7 @@ struct BestResult double gammaHLG = 0; double nits = 0; bool lchEnabled = false; - std::pair, std::list> lchPrimaries; + LchLists lchPrimaries; struct Signal { @@ -79,7 +86,7 @@ struct BestResult void serializePrimaries(std::stringstream& out) const { - for (const auto& p : { lchPrimaries.first, lchPrimaries.second }) + for (const auto& p : { lchPrimaries.low, lchPrimaries.mid, lchPrimaries.high }) { out << std::endl << "\t\t\tstd::list{" << std::endl << "\t\t\t\t"; for (const auto& v : p) @@ -107,7 +114,7 @@ struct BestResult out << "bestResult.gamma = ColorSpaceMath::HDR_GAMMA(" << std::to_string(gamma) << ");" << std::endl; out << "bestResult.gammaHLG = " << std::to_string(gammaHLG) << ";" << std::endl; out << "bestResult.lchEnabled = " << std::to_string(lchEnabled) << ";" << std::endl; - out << "bestResult.lchPrimaries = std::pair, std::list>{"; serializePrimaries(out); out << "\t\t};" << std::endl; + out << "bestResult.lchPrimaries = LchLists{"; serializePrimaries(out); out << "\t\t};" << std::endl; out << "bestResult.nits = " << std::to_string(nits) << ";" << std::endl; out << "bestResult.signal.range = YuvConverter::COLOR_RANGE(" << std::to_string(signal.range) << ");" << std::endl; out << "bestResult.signal.yRange = " << std::to_string(signal.yRange) << ";" << std::endl; diff --git a/include/lut-calibrator/CapturedColor.h b/include/lut-calibrator/CapturedColor.h index 09eebb5ba..4ba97b4bc 100644 --- a/include/lut-calibrator/CapturedColor.h +++ b/include/lut-calibrator/CapturedColor.h @@ -43,7 +43,7 @@ class CapturedColor { public: - enum LchPrimaries { NONE, LOW, HIGH }; + enum LchPrimaries { NONE, LOW, MID, HIGH }; private: int totalSamples = 0; diff --git a/sources/lut-calibrator/CapturedColor.cpp b/sources/lut-calibrator/CapturedColor.cpp index ee57bb809..e2a078115 100644 --- a/sources/lut-calibrator/CapturedColor.cpp +++ b/sources/lut-calibrator/CapturedColor.cpp @@ -204,7 +204,21 @@ void CapturedColor::setCoords(const byte3& index) } else { - lchPrimary = LchPrimaries::NONE; + MAX_IND = (BoardUtils::MAX_INDEX * 3) / 4; + if (std::max(std::max(index.x, index.y), index.z) == MAX_IND && + ((std::min(index.x, index.z) == 0 && std::max(index.x, index.z) == MAX_IND && (index.y % (MAX_IND / 2) == 0)) || + (std::min(index.x, index.y) == 0 && std::max(index.x, index.y) == MAX_IND && (index.z % (MAX_IND / 2) == 0)) || + (std::min(index.y, index.z) == 0 && std::max(index.y, index.z) == MAX_IND && (index.x % (MAX_IND / 2) == 0)) || + (index.x == MAX_IND && index.y == MAX_IND && index.z == MAX_IND / 2) || + (index.x == MAX_IND && index.y == MAX_IND / 2 && index.z == MAX_IND) + )) + { + lchPrimary = LchPrimaries::MID; + } + else + { + lchPrimary = LchPrimaries::NONE; + } } } } @@ -262,55 +276,6 @@ std::list> CapturedColor::getInputYuvColors() const int CapturedColor::getSourceError(const int3& _color) const { - constexpr int LIMIT_MAX_UP = 248; - constexpr int LIMIT_MAX_DOWN = 232; - constexpr int LIMIT_MIDDLE_UP = 228; - constexpr int LIMIT_MIDDLE_DOWN = 220; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 1 && arrayCoords.x == arrayCoords.y && arrayCoords.y == arrayCoords.z && - (_color.x > LIMIT_MAX_UP || _color.x < LIMIT_MAX_DOWN))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 2 && arrayCoords.x == arrayCoords.y && arrayCoords.y == arrayCoords.z && - (_color.x > LIMIT_MIDDLE_UP || _color.x < LIMIT_MIDDLE_DOWN))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if (arrayCoords.x == BoardUtils::MAX_INDEX && arrayCoords.y == 0 && arrayCoords.z == 0 && - _color.x < LIMIT_MIDDLE_DOWN) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if (arrayCoords.y == BoardUtils::MAX_INDEX && arrayCoords.x == 0 && arrayCoords.z == 0 && - _color.y < LIMIT_MIDDLE_DOWN) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if (arrayCoords.z == BoardUtils::MAX_INDEX && arrayCoords.y == 0 && arrayCoords.x == 0 && - _color.z < LIMIT_MIDDLE_DOWN) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 2 && arrayCoords.x == arrayCoords.y && arrayCoords.z == 0 && - ((_color.x + _color.y) > LIMIT_MIDDLE_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 2 && arrayCoords.x == arrayCoords.z && arrayCoords.y == 0 && - ((_color.x + _color.z) > LIMIT_MIDDLE_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.y == BoardUtils::MAX_INDEX - 2 && arrayCoords.y == arrayCoords.z && arrayCoords.x == 0 && - ((_color.y + _color.z) > LIMIT_MIDDLE_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 1 && arrayCoords.x == arrayCoords.y && arrayCoords.z == 0 && - ((_color.x + _color.y) > LIMIT_MAX_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.x == BoardUtils::MAX_INDEX - 1 && arrayCoords.x == arrayCoords.z && arrayCoords.y == 0 && - ((_color.x + _color.z) > LIMIT_MAX_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - - if ((arrayCoords.y == BoardUtils::MAX_INDEX - 1 && arrayCoords.y == arrayCoords.z && arrayCoords.x == 0 && - ((_color.y + _color.z) > LIMIT_MAX_UP * 2))) - return BoardUtils::MAX_CALIBRATION_ERROR; - auto delta = linalg::abs( sourceRGB - _color); @@ -318,48 +283,53 @@ int CapturedColor::getSourceError(const int3& _color) const { return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 100; } - else if (sourceRGB.x == sourceRGB.y) + else if ( + (arrayCoords.x == 0 || arrayCoords.x == BoardUtils::MAX_INDEX) && + (arrayCoords.y == 0 || arrayCoords.y == BoardUtils::MAX_INDEX) && + (arrayCoords.z == 0 || arrayCoords.z == BoardUtils::MAX_INDEX)) { - auto diff = std::abs(_color.x - _color.y); - if (_color.x > _color.y) + if (arrayCoords.x != BoardUtils::MAX_INDEX) + delta.x = (delta.x * 3) / 4; + + if (arrayCoords.y != BoardUtils::MAX_INDEX) + delta.y = (delta.y * 3) / 4; + + if (arrayCoords.z != BoardUtils::MAX_INDEX) + delta.z = (delta.z * 3) / 4; + + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 50; + } + else if (sourceRGB.x == sourceRGB.y) + { + if (_color.x >= _color.y) { - delta.x = std::min(delta.x, diff); - delta.y = std::min(delta.y, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 3 / 4; } else { - delta.x = std::max(delta.x, diff); - delta.y = std::max(delta.y, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 5 / 4; } } else if (sourceRGB.x == sourceRGB.z) { - auto diff = std::abs(_color.x - _color.z); - - if (_color.z > _color.x) + if (_color.z >= _color.x) { - delta.x = std::min(delta.x, diff); - delta.z = std::min(delta.z, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 3 / 4; } else { - delta.x = std::max(delta.x, diff); - delta.z = std::max(delta.z, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 5 / 4; } } else if (sourceRGB.y == sourceRGB.z) { - auto diff = std::abs(_color.y - _color.z); - - if (_color.z > _color.y) + if (_color.z >= _color.y) { - delta.y = std::min(delta.y, diff); - delta.z = std::min(delta.z, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 3 / 4; } else { - delta.y = std::max(delta.y, diff); - delta.z = std::max(delta.z, diff); + return (delta.x * delta.x * delta.x + delta.y * delta.y * delta.y + delta.z * delta.z * delta.z) * 5 / 4; } } diff --git a/sources/lut-calibrator/LutCalibrator.cpp b/sources/lut-calibrator/LutCalibrator.cpp index 1eebb42c6..3d3c1715d 100644 --- a/sources/lut-calibrator/LutCalibrator.cpp +++ b/sources/lut-calibrator/LutCalibrator.cpp @@ -492,7 +492,7 @@ double3 uncharted2_filmic(double3 v) return curr * white_scale; }*/ -void doToneMapping(const std::pair, std::list>& m, double3& p) +static void doToneMapping(const LchLists& m, double3& p) { auto a = xyz_to_lch(from_sRGB_to_XYZ(p) * 100.0); @@ -501,9 +501,9 @@ void doToneMapping(const std::pair, std::list>& m, d double3 correctionHigh{}; - auto iterHigh = m.first.begin(); + auto iterHigh = m.high.begin(); auto lastHigh = *(iterHigh++); - for (; iterHigh != m.first.end(); lastHigh = *(iterHigh++)) + for (; iterHigh != m.high.end(); lastHigh = *(iterHigh++)) if ((lastHigh.w >= a.z && a.z >= (*iterHigh).w)) { auto& current = (*iterHigh); @@ -519,10 +519,29 @@ void doToneMapping(const std::pair, std::list>& m, d break; } + double3 correctionMid{}; + auto iterMid = m.mid.begin(); + auto lastMid = *(iterMid++); + for (; iterMid != m.mid.end(); lastMid = *(iterMid++)) + if ((lastMid.w >= a.z && a.z >= (*iterMid).w)) + { + auto& current = (*iterMid); + double lastAsp = lastMid.w - a.z; + double curAsp = a.z - current.w; + double prop = 1 - (lastAsp / (lastAsp + curAsp)); + + if (lastMid.x > 0 && current.x > 0) + correctionMid.x = prop * lastMid.x + (1 - prop) * current.x; + if (lastMid.y > 0 && current.y > 0) + correctionMid.y = prop * lastMid.y + (1 - prop) * current.y; + correctionMid.z += prop * lastMid.z + (1 - prop) * current.z; + break; + } + double3 correctionLow{}; - auto iterLow = m.second.begin(); + auto iterLow = m.low.begin(); auto lastLow = *(iterLow++); - for (; iterLow != m.second.end(); lastLow = *(iterLow++)) + for (; iterLow != m.low.end(); lastLow = *(iterLow++)) if ((lastLow.w >= a.z && a.z >= (*iterLow).w)) { auto& current = (*iterLow); @@ -556,22 +575,53 @@ void doToneMapping(const std::pair, std::list>& m, d aLow.z += correctionLow.z; double3 pLow = from_XYZ_to_sRGB(lch_to_xyz(aLow) / 100.0); - - double max = std::max(linalg::maxelem(pLow), linalg::maxelem(pHigh)); - double lenLow = std::abs((128.0/255.0) - max); - double lenHigh = std::abs(1.0 - max); - double aspectHigh = (1.0 - lenHigh / (lenLow + lenHigh)); - if (correctionLow.x > 0 && correctionHigh.x > 0) + if (128.0 / 255.0 >= max) { - a.x *= correctionHigh.x * aspectHigh + correctionLow.x * (1.0 - aspectHigh); + if (correctionLow.x > 0) + { + a.x *= correctionLow.x; + } + if (correctionLow.y > 0) + { + a.y *= correctionLow.y; + } + a.z += correctionLow.z; } - if (correctionLow.y > 0 && correctionHigh.y > 0) + else if (192.0 / 255.0 >= max) { - a.y *= correctionHigh.y * aspectHigh + correctionLow.y * (1.0 - aspectHigh); + double lenLow = std::abs((128.0 / 255.0) - max); + double lenMid = std::abs((192.0 / 255.0) - max); + double aspectMid = (1.0 - lenMid / (lenLow + lenMid)); + + if (correctionLow.x > 0 && correctionMid.x > 0) + { + a.x *= correctionMid.x * aspectMid + correctionLow.x * (1.0 - aspectMid); + } + if (correctionLow.y > 0 && correctionMid.y > 0) + { + a.y *= correctionMid.y * aspectMid + correctionLow.y * (1.0 - aspectMid); + } + a.z += correctionMid.z * aspectMid + correctionLow.z * (1.0 - aspectMid); } - a.z += correctionHigh.z * aspectHigh + correctionLow.z * (1.0 - aspectHigh); + else + { + double lenMid = std::abs((192.0 / 255.0) - max); + double lenHigh = std::abs(1.0 - max); + double aspectHigh = (1.0 - lenHigh / (lenMid + lenHigh)); + + if (correctionMid.x > 0 && correctionHigh.x > 0) + { + a.x *= correctionHigh.x * aspectHigh + correctionMid.x * (1.0 - aspectHigh); + } + if (correctionMid.y > 0 && correctionHigh.y > 0) + { + a.y *= correctionHigh.y * aspectHigh + correctionMid.y * (1.0 - aspectHigh); + } + a.z += correctionHigh.z * aspectHigh + correctionMid.z * (1.0 - aspectHigh); + } + p = from_XYZ_to_sRGB(lch_to_xyz(a) / 100.0); @@ -729,10 +779,10 @@ static double3 hdr_to_srgb(const YuvConverter* _yuvConverter, double3 yuv, const return srgb; } -static std::pair, std::list> prepareLCH(std::list>> __lchPrimaries) +static LchLists prepareLCH(std::list>> __lchPrimaries) { int index = 0; - std::pair, std::list> ret; + LchLists ret; for (const auto& _lchPrimaries : __lchPrimaries) { @@ -761,10 +811,13 @@ static std::pair, std::list> prepareLCH(std::list colorAspect = std::pair({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }); - std::list> selectedLchHighPrimaries, selectedLchLowPrimaries; + std::list> selectedLchHighPrimaries, selectedLchMidPrimaries, selectedLchLowPrimaries; if (coloredAspectMode) { @@ -876,6 +929,10 @@ void CalibrationWorker::run() { selectedLchHighPrimaries.push_back(std::pair(lchPrimaries, (*v).second)); } + else if (res == CapturedColor::LchPrimaries::MID) + { + selectedLchMidPrimaries.push_back(std::pair(lchPrimaries, (*v).second)); + } else if (res == CapturedColor::LchPrimaries::LOW) { selectedLchLowPrimaries.push_back(std::pair(lchPrimaries, (*v).second)); @@ -887,13 +944,13 @@ void CalibrationWorker::run() bool lchFavour = false; long long int lcHError = MAX_CALIBRATION_ERROR; - std::pair, std::list> selectedLchPrimaries; + LchLists selectedLchPrimaries; if (precise && lchCorrection && currentError < MAX_CALIBRATION_ERROR) { lcHError = 0; lchFavour = true; - selectedLchPrimaries = prepareLCH({ selectedLchHighPrimaries, selectedLchLowPrimaries }); + selectedLchPrimaries = prepareLCH({ selectedLchLowPrimaries, selectedLchMidPrimaries, selectedLchHighPrimaries }); for (auto sample = vertex.begin(); sample != vertex.end(); ++sample) { @@ -901,7 +958,7 @@ void CalibrationWorker::run() doToneMapping(selectedLchPrimaries, correctedRGB); lcHError += (*sample).first->getSourceError((int3)(to_byte3(correctedRGB * 255.0))); - if (lcHError >= (129 * currentError) / 128 || lcHError > weakBestScore) + if (lcHError >= currentError || lcHError > weakBestScore) { lchFavour = false; lcHError = MAX_CALIBRATION_ERROR; @@ -970,33 +1027,23 @@ void LutCalibrator::fineTune(bool precise) std::atomic weakBestScore = MAX_CALIBRATION_ERROR; // prepare vertexes - std::list vertex, masterVertex; + std::list vertex; for (int r = MAX_IND; r >= 0; r--) for (int g = MAX_IND; g >= 0; g--) for (int b = MAX_IND; b >= 0; b--) { - if ((r % 4 == 0 && g % 4 == 0 && b % 4 == 0) || (r == b && b == g) || (r == g && r > 0) || (r == b && r > 0) + if ((r % 4 == 0 && g % 4 == 0 && b % 2 == 0) || (r == b && b == g) || (r == g && r > 0) || (r == b && r > 0) || _capturedColors->all[r][g][b].isLchPrimary(nullptr) != CapturedColor::LchPrimaries::NONE) { - if ((r == MAX_IND - 1 && r == g && g == b) || - - (r == MAX_IND - 2 && r == g && g == b) || - - (r == MAX_IND && g == 0 && b == 0) || - - (g == MAX_IND && r == 0 && b == 0) || - - (b == MAX_IND && g == 0 && r == 0)) - masterVertex.push_back(&_capturedColors->all[r][g][b]); - else - vertex.push_back(&_capturedColors->all[r][g][b]); + vertex.push_back(&_capturedColors->all[r][g][b]); } } - vertex.insert(vertex.begin(), masterVertex.begin(), masterVertex.end()); + vertex.sort([](CapturedColor*& a, CapturedColor*& b) { return ((int)a->coords().x + a->coords().y + a->coords().z) > + ((int)b->coords().x + b->coords().y + b->coords().z); }); if (!precise) { @@ -1229,7 +1276,7 @@ void LutCalibrator::calibration() for (int g = MAX_IND; g >= 0; g--) for (int b = MAX_IND; b >= 0; b--) { - if ((r % 4 == 0 && g % 4 == 0 && b % 4 == 0) || (r == b && b == g) || (r == g && r > 0) || (r == b && r > 0) + if ((r % 4 == 0 && g % 4 == 0 && b % 2 == 0) || (r == b && b == g) || (r == g && r > 0) || (r == b && r > 0) || _capturedColors->all[r][g][b].isLchPrimary(nullptr) != CapturedColor::LchPrimaries::NONE) { auto sample = _capturedColors->all[r][g][b]; @@ -1265,6 +1312,7 @@ static void reportLCH(Logger* _log, std::vector mHigh; + std::list mMid; std::list mLow; @@ -1275,20 +1323,22 @@ static void reportLCH(Logger* _log, std::vector*& m : std::list*>{ &mHigh, &mLow }) + for (std::list*& m : std::list*>{ &mHigh, &mMid, &mLow }) { for (MappingPrime& c : *m) { @@ -1311,19 +1361,18 @@ static void reportLCH(Logger* _log, std::vector*& m : std::list*>{ &mHigh, &mLow }) + for (std::list*& m : std::list*>{ &mHigh, &mMid, &mLow }) { for (MappingPrime& c : *m) { auto& sample = (*all)[c.prime.x][c.prime.y][c.prime.z]; auto aa = from_XYZ_to_sRGB(lch_to_xyz(c.org) / 100.0) * 255; auto bb = from_XYZ_to_sRGB(lch_to_xyz(c.real) / 100.0) * 255; - info.append(QString("%1 %2 %3 | %4 %5 | %6 | %7").arg(vecToString(sample.getSourceRGB()), 12). + info.append(QString("%1 | %2 | %3 | %4 | %5 %6").arg(vecToString(sample.getSourceRGB()), 12). arg(vecToString(c.org)). - arg(vecToString(c.real)). - arg(vecToString(sample.getSourceRGB()), 12). + arg(vecToString(c.real)). arg(vecToString(c.delta)). arg(vecToString(to_byte3(aa))). arg(vecToString(to_byte3(bb))));