Skip to content

Commit

Permalink
Added a new nice web wizard for LUT calibration
Browse files Browse the repository at this point in the history
  • Loading branch information
awawa-dev committed Sep 6, 2024
1 parent 5c95eac commit 7130cd0
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 46 deletions.
3 changes: 2 additions & 1 deletion include/lut-calibrator/LutCalibrator.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,21 @@ public slots:
void setVideoImage(const QString& name, const Image<ColorRgb>& image);
void setSystemImage(const QString& name, const Image<ColorRgb>& image);
void signalSetGlobalImageHandler(int priority, const Image<ColorRgb>& image, int timeout_ms, hyperhdr::Components origin);
void calibrate();

private:
void toneMapping();
QString generateReport(bool full);
void sendReport(QString report);
bool set1to1LUT();
void notifyCalibrationFinished();
void notifyCalibrationMessage(QString message, bool started = false);
void error(QString message);
void handleImage(const Image<ColorRgb>& image);
linalg::vec<double, 3> hdr_to_srgb(linalg::vec<double, 3> yuv, const linalg::vec<uint8_t, 2>& UV, const linalg::vec<double, 3>& aspect, const linalg::mat<double, 4, 4>& coefMatrix, int nits, bool altConvert, const linalg::mat<double, 3, 3>& bt2020_to_sRgb, bool tryBt2020Range);
void scoreBoard(bool testOnly, const linalg::mat<double, 4, 4>& coefMatrix, int nits, linalg::vec<double, 3> aspect, bool tryBt2020Range, bool altConvert, const linalg::mat<double, 3, 3>& bt2020_to_sRgb, const double& minError, double& currentError);
void tryHDR10();
void setupWhitePointCorrection();
void calibrate();
bool finalize(bool fastTrack = false);

inline int clampInt(int val, int min, int max) { return qMin(qMax(val, min), max);}
Expand Down
35 changes: 26 additions & 9 deletions sources/lut-calibrator/LutCalibrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ void LutCalibrator::error(QString message)
QJsonObject report;
stopHandler();
Error(_log, QSTRING_CSTR(message));
report["status"] = 1;
report["error"] = message;
SignalLutCalibrationUpdated(report);
}
Expand Down Expand Up @@ -224,8 +223,18 @@ QString LutCalibrator::generateReport(bool full)
void LutCalibrator::notifyCalibrationFinished()
{
QJsonObject report;
report["status"] = 0;
report["validate"] = -1;
report["finished"] = true;
SignalLutCalibrationUpdated(report);
}

void LutCalibrator::notifyCalibrationMessage(QString message, bool started)
{
QJsonObject report;
report["message"] = message;
if (started)
{
report["start"] = true;
}
SignalLutCalibrationUpdated(report);
}

Expand Down Expand Up @@ -299,17 +308,23 @@ void LutCalibrator::incomingCommand(QString rootpath, GrabberWrapper* grabberWra

if (defaultComp == hyperhdr::COMP_VIDEOGRABBER)
{
Debug(_log, "Using video grabber as a source");
auto message = "Using video grabber as a source<br/>Waiting for first captured test board..";
notifyCalibrationMessage(message);
Debug(_log, message);
connect(GlobalSignals::getInstance(), &GlobalSignals::SignalNewVideoImage, this, &LutCalibrator::setVideoImage, Qt::ConnectionType::UniqueConnection);
}
else if (defaultComp == hyperhdr::COMP_SYSTEMGRABBER)
{
Debug(_log, "Using system grabber as a source");
auto message = "Using system grabber as a source<br/>Waiting for first captured test board..";
notifyCalibrationMessage(message);
Debug(_log, message);
connect(GlobalSignals::getInstance(), &GlobalSignals::SignalNewSystemImage, this, &LutCalibrator::setSystemImage, Qt::ConnectionType::UniqueConnection);
}
else
{
Debug(_log, "Using flatbuffers/protobuffers as a source");
auto message = "Using flatbuffers/protobuffers as a source<br/>Waiting for first captured test board..";
notifyCalibrationMessage(message);
Debug(_log, message);
connect(GlobalSignals::getInstance(), &GlobalSignals::SignalSetGlobalImage, this, &LutCalibrator::signalSetGlobalImageHandler, Qt::ConnectionType::UniqueConnection);
}
}
Expand Down Expand Up @@ -365,20 +380,22 @@ void LutCalibrator::handleImage(const Image<ColorRgb>& image)

int boardIndex = -1;

if (!parseBoard(_log, image, boardIndex, (*_capturedColors.get())))
if (!parseBoard(_log, image, boardIndex, (*_capturedColors.get())) || _capturedColors->isCaptured(boardIndex))
{
return;
}


_capturedColors->setCaptured(boardIndex);

notifyCalibrationMessage(QString("Captured test board: %1<br/>Waiting for the next one...").arg(boardIndex));


if (_capturedColors->areAllCaptured())
{
Info(_log, "All boards are captured. Starting calibration...");
stopHandler();
calibrate();
notifyCalibrationMessage(QString("All boards are captured<br/>Processing...<br/>This will take a lot of time"), true);
QTimer::singleShot(200, this, &LutCalibrator::calibrate);
}
}

Expand Down
79 changes: 57 additions & 22 deletions www/content/grabber_calibration.html
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
<div id="hyper-subpage" class="container-fluid">
<div class="col-12 col-xl-11 col-xxl-10 mb-4">
<h3 class="page-header text-start"><svg data-src="svg/lut_calibration.svg" width="28" height="28" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="main_menu_grabber_calibration_token"></span></h3>
<div class="callout callout-info text-start">
<h4 id="grabber_calibration_intro" style="font-size:16px"></h4>
</div>
<h3 class="page-header text-start"><svg data-src="svg/lut_calibration.svg" width="28" height="28" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="main_menu_grabber_calibration_token"></span></h3>
</div>
</div>
<div class="d-flex justify-content-center pt-2 mb-4">
<canvas width="1280px" height="720px" id="canvas">
</canvas>
</div>
<div style="text-align:center;" class="w-100 row mb-2">
<div class="col-12 form">
<span data-i18n="edt_conf_stream_control_saturation">Saturation</span> <input class="form-control form-control-inline" style="display: inline; width:80px;" type="number" id="saturation" min="0" max="5" value="1.0" step="0.01" />
<span data-i18n="edt_conf_color_luminanceGain_title">Luminance</span> <input class="form-control form-control-inline" style="display: inline; width:80px;" type="number" id="luminance" min="0" max="5" value="1.0" step="0.01" />



<div class="row w-100">
<div style="display: flex; justify-content: center; mt-6;" width="100%">
<div class="col-lg-6 mt-6" id="conf_imp">
<div id="calibration_select_intro" class="card card-default">
<div class="card-header"><svg data-src="svg/lut_calibration.svg" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="option_calibration_intro"></span></div>
<div class="card-body">
<div class="form-check mt-3">
<input class="form-check-input" type="radio" id="select_video_calibration" name="select_calibration_type" />
<label class="form-check-label" for="select_video_calibration" id="select_video_calibration_label">
</label>
</div>
<div class="form-check mt-4 mb-3">
<input class="form-check-input" type="radio" id="select_classic_calibration" name="select_calibration_type" />
<label class="form-check-label" for="select_classic_calibration" id="select_classic_calibration_label">
</label>
</div>
</div>
<div class="card-footer" style="text-align: right;">
<button class="btn btn-primary" id="btn_select_calibration" data-i18n="general_btn_next">Next</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="text-align:center;" class="w-100 row mb-4">
<div class="col-12 form">
<span data-i18n="edt_conf_color_gammaRed_title">Gamma Red</span> <input class="form-control form-control-inline" style="display: inline; width:80px;" type="number" id="gammaR" min="0" max="5" value="1.0" step="0.01" />
<span data-i18n="edt_conf_color_gammaGreen_title">Gamma Green</span> <input class="form-control form-control-inline" style="display: inline; width:80px;" type="number" id="gammaG" min="0" max="5" value="1.0" step="0.01" />
<span data-i18n="edt_conf_color_gammaBlue_title">Gamma Blue</span> <input class="form-control form-control-inline" style="display: inline; width:80px;" type="number" id="gammaB" min="0" max="5" value="1.0" step="0.01" />


<div class="row w-100">
<div style="display: flex; justify-content: center; mt-6;" width="100%">
<div class="col-lg-6 mt-6" id="video_calibration" style="display: none;">
<div id="calibration_select_intro" class="card card-default">
<div class="card-header"><svg data-src="svg/lut_calibration.svg" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="option_calibration_intro"></span></div>
<div class="card-body">
<span id="video_calibration_overview">
</span>
</div>
<div class="card-footer" style="text-align: right;">
<button class="btn btn-primary" id="btn_start_video_calibration"><svg data-src="svg/button_play.svg" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="general_btn_start">Start</span></button>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="text-align:center;" class="w-100 h-100">
<button id="startCalibration" type="button" style="width: 320px;" class="btn btn-success"><svg data-src="svg/button_play.svg" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="general_btn_start">Start</span></button>
</div>

<div id="classic_calibration" style="display: none;">
<div class="callout callout-info text-start ms-3 me-3">
<h4 id="grabber_calibration_intro" style="font-size:16px"></h4>
</div>
<div class="d-flex justify-content-center pt-2 mb-4">
<canvas width="1280px" height="720px" id="canvas">
</canvas>
</div>
<div style="text-align:center;" class="w-100 h-100">
<button id="startCalibration" type="button" style="width: 320px;" class="btn btn-success"><svg data-src="svg/button_play.svg" fill="currentColor" class="svg4hyperhdr"></svg><span data-i18n="general_btn_start">Start</span></button>
</div>
<div>
<script>
$.getScript("/js/grabber_calibration.js");
</script>
8 changes: 6 additions & 2 deletions www/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@
"general_comp_RAWUDPSERVER" : "UDP raw receiver",
"edt_udp_raw_server" : "A lightweight server for remote synchronization of HyperHDR instances using UDP and raw RGB LED colors. Can also be controlled from another applications (similar to Boblight server) in a very simple way. For HyperHDR synchronization use the 'udpraw' light source in the sender.<br/>Important: both instances should have the same number of LEDs (max 490) and same geometry for this to work. <b>Smoothing should only be enabled on one instance, not both!</b>",
"main_menu_grabber_calibration_token" : "LUT calibration",
"grabber_calibration_expl": "This tool allows you to create a new calibrated HDR LUT for your grabber (or external flatbuffers source) as close to the actual input colors as possible.<br/>You need an HDR10 video source that can display this web page, for example: Windows 10 with HDR enabled in the properties of the graphics driver.<br/>The screen may flicker during calibration. The process typically takes about few minutes on a Intel 7 Windows PC (depending on the host CPU resources and the video capturing framerate).<br/><b>The calculations are intensive and put a strain on your equipment.</b><br/>You can monitor the progress in HyperHDR logs using the browser from other device.<br/><br/><br/><b>1</b> If everything is properly connected, this page should be displayed on the TV screen (as HDR content) and live preview in HyperHDR (captured by the grabber).</br><b>2</b> You need to disable HDR tone mapping in the grabber configuration (we will verify this).<br/><b>3</b> Absolute minimum capturing resolution is 384x216 (we will verify this). Recommended are: 1920x1080 at least 1280x720. Aspect 1920/1080 must be preserved.<br/><b>4</b> It's preffered to disable 'Quarter of frame mode' in your grabber properties.<br/><b>5</b> You should set the video format you usually use. This is extremely important especially for the NV12/YUV as we need to check if the color gamut is full or limited.<br/><b>6</b> Before you run the process please put your WWW browser in the full-screen mode (F11 key, we will verify this).<br/><br/>After completing the calibration, your new LUT table file (lut_lin_tables.3d) will be created in the user's HyperHDR home directory and is immediately ready to use when you just enable HDR tone mapping. Please verify HyperHDR logs for details.",
"grabber_calibration_expl": "This tool allows you to create a new calibrated HDR LUT for your grabber (or external flatbuffers source) as close to the actual input colors as possible.<br/>You need an HDR10 video source that can display this web page, for example: Windows 10 with HDR enabled in the properties of the graphics driver.<br/>The screen may flicker during calibration. The process typically takes about few minutes on a Intel 7 Windows PC (depending on the host CPU resources and the video capturing framerate).<br/><b>The calculations are intensive and put a strain on your equipment.</b><br/>You can monitor the progress in HyperHDR logs using the browser from other device.<br/><br/><br/><b>1</b> If everything is properly connected, this page should be displayed on the TV screen (as HDR content) and live preview in HyperHDR (captured by the grabber).</br><b>2</b> Absolute minimum capturing resolution is 384x216 (we will verify this). Recommended are: 1920x1080 at least 1280x720. Aspect 1920/1080 must be preserved.<br/><b>3</b> It's preffered to disable 'Quarter of frame mode' in your grabber properties.<br/><b>4</b> You must set the grabber's video format to MJPEG/NV12/YUV.<br/><b>5</b> Before you run the process please put your WWW browser in the full-screen mode (F11 key, we will verify this).<br/><br/>After completing the calibration, your new LUT table file (lut_lin_tables.3d) will be created in the user's HyperHDR home directory and is immediately ready to use when you just enable HDR tone mapping. Please verify HyperHDR logs for details.",
"grabber_calibration_force": "Force auto-detection:",
"edt_dev_max_retry" : "Maximum number of retries",
"edt_rgbw_calibration_enable" : "White channel calibration (RGBW only)",
Expand Down Expand Up @@ -1243,5 +1243,9 @@
"edt_conf_gen_disableLedsStartup_title" : "Turn off LEDs at startup",
"edt_conf_gen_disableLedsStartup_expl" : "Disable LEDs and all components on startup, you must re-enable them manually on the main page or via the JSON API (COMP_ALL component).",
"edt_conf_sound_device_smoothing_title" : "Enable smoothing",
"edt_conf_sound_device_smoothing_expl" : "Enable special smoothing for sound effects. Requires an LED device with an output frequency of 60 Hz. When smoothing is disabled, the output frequency is 20 Hz."
"edt_conf_sound_device_smoothing_expl" : "Enable special smoothing for sound effects. Requires an LED device with an output frequency of 60 Hz. When smoothing is disabled, the output frequency is 20 Hz.",
"option_calibration_intro" : "Please select calibration type",
"option_calibration_video" : "Calibration using a test video played by your favorite video player.<br/>We calibrate LUT taking into account the grabber, player and your TV.",
"option_calibration_classic" : "Calibration using Windows with HDR mode enabled and a web browser.<br/>We calibrate LUT taking into account the grabber and your TV.",
"video_calibration_overview" : "<b>1</b> You need to set the video format of your grabber to MJPEG/YUYV/NV12. Other formats are not supported.<br/><br/><b>2</b> If you calibrate using Flatbuffers, you need to enable tone mapping in its settings. Only the NV12 video format is supported.</br><br/><b>3</b> You can download test files here: <a href='https://github.com/awawa-dev/awawa-dev.github.io/tree/master/calibration'>link</a>. In your player, start playing the test file. You should see it in the HyperHDR video preview. The test screen must take up the entire screen and no extraneous elements, such as the player menu, can be visible.</br><br/><b>4</b> For calibration, you should choose a file with 'hdr' in the name unless your system or player automatically uses SDR to HDR tone mapping. In that case, to adapt to such a scenario, choose a file with 'sdr' in the name.</br><br/><b>5</b> The YUV420 format provides the greatest compatibility with average quality and is the most common. The YUV444 format provides the best quality but it is rare to find materials encoded in this form."
}
Loading

0 comments on commit 7130cd0

Please sign in to comment.