View Full Version : Plugin HDRTools for Avisynth


jpsdr
30th May 2018, 11:11
This is a plugin with functions made to work on HDR videos, but can also eventualy work to do some color conversions.

Current version: 1.2.3

Sources are here (https://github.com/jpsdr/HDRTools).
Binaries are here (https://github.com/jpsdr/HDRTools/releases/download/1.2.3/HDRTools_v1_2_3.7z).

Change list:
29/11/2025 v1.2.3 : Minor changes (more code refactory).
19/07/2025 v1.2.0 : Add more AVX512 code path.
19/07/2025 v1.1.0 : Add AVX512 code path.
19/11/2023 v1.0.5 : Update to new AVS+ headers.
25/02/2023 v1.0.4 : Update to new AVS+ headers.
21/11/2022 v1.0.3 : Fix the value of a BT.1886 parameter (2.404 -> 2.40).
20/11/2022 v1.0.2 : Update on threadpool, no user limit (except memory).
21/06/2022 v1.0.1 : Some fixes and add Exposure parameter to ACES tonemap.
15/06/2022 v1.0.0 : Add ACES tonemap.
22/02/2022 v0.6.4 : Fix on threadpool, using prefetch parameter created hang. Add negative prefetch for triming, read Multithreading.txt.
20/07/2021 v0.6.3 : Fix on threadpool.
30/04/2021 v0.6.2 : Update to new avisynth headers.
28/04/2020 v0.6.1 : Update to new avisynth headers.
14/12/2019 v0.6.0 : Add BT2446 A & C methods for HDR to SDR convert.
15/09/2019 v0.5.3 : Add Crosstalk parameter, add EOTF path for SDR, fix in 16 bits lookup XYZ.
06/06/2019 v0.5.2 : Minor code change after threadpool update, fix in the number of threads.
30/05/2019 v0.5.0 : Update of the threadpool, add ThreadLevel parameter.
14/08/2018 v0.4.2 : Update ReadMe, minor changes.
10/08/2018 v0.4.1 : Minor changes.
09/08/2018 v0.4.0 : Some fix on HLG, rename and change of HDRtoSDR/SDRtoHDR functions, add Hable, Mobius and Reinhard tonemap (formula from Vapoursynth). Reinhard uses the "exposure" parameter.
03/08/2018 v0.3.1 : Fix some crash issues.
31/07/2018 v0.3.0 : Add HLG support, update PDF document.
08/06/2018 v0.2.0 : Add support of float planar RGB input/ouput on ConvertXYZtoRGB and ConvertRGBtoXYZ. Add document.
30/05/2018 v0.1.0 : Initial release.

Note about HDR HLG:
For speed-up:
8 bits input use 3D lookup (startup is slow).
10 and 12 bits use 2D lookup (startup is slow), but there is a resolution loss noticeable effect on low values.

Note about YV12/YV16/YV24 input/ouput:
For ConvertYUVtoxxx functions, convertion to YV24 if input is not YV24 is "quick".
If you want a true correct precise/perfect convertion, i would avise you to use a resampler and feed directly to YV24.
For ConvertxxxtoYUV functions, if you choose an ouput different from YV24, same remark, convertion is "quick".
If you want a true correct precise/perfect convertion, i would avise you to ouput to YV24, and use a resampler to achieve the real output format you want.

The functions avaible in this plugin are:

ConvertYUVtoLinearRGB(int Color,int OutputMode,int HDRMode,float HLGLb,float HLGLw,int HLGColor,bool OOTF,bool EOTF,bool fullrange,bool mpeg2c,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertLinearRGBtoYUV(int Color,int OutputMode,int HDRMode,float HLGLb,float HLGLw,int HLGColor,bool OOTF,bool EOTF,bool fullrange,bool mpeg2c,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertYUVtoXYZ(int Color,int OutputMode,int HDRMode,float HLGLb,float HLGLw,float Crosstalk,int HLGColor,bool OOTF,bool EOTF,bool fullrange,bool mpeg2c,float Rx,float Ry,float Gx,float Gy,float Bx,float By,float Wx,float Wy,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertXYZtoYUV(int Color,int OutputMode,int HDRMode,float HLGLb, float HLGLw,float Crosstalk,int HLGColor,bool OOTF,bool EOTF,bool fullrange,bool mpeg2c,bool fastmode,float Rx,float Ry,float Gx,float Gy,float Bx,float By,float Wx,float Wy,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertRGBtoXYZ(int Color,int OutputMode,int HDRMode,float HLGLb,float HLGLw,float Crosstalk,int HLGColor,bool OOTF,bool EOTF,bool fastmode,float Rx,float Ry,float Gx,float Gy,float Bx,float By,float Wx,float Wy,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertXYZtoRGB(int Color,int OutputMode,int HDRMode,float HLGLb,float HLGLw,float Crosstalk,int HLGColor,bool OOTF,bool EOTF,bool fastmode,float Rx,float Ry,float Gx,float Gy,float Bx,float By,float Wx,float Wy,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertXYZ_Scale_HDRtoSDR(float Coeff_X,float Coeff_Y,float Coeff_Z,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertXYZ_Scale_SDRtoHDR(float Coeff_X,float Coeff_Y,float Coeff_Z,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertXYZ_Hable_HDRtoSDR(float exposure_X,float whitescale_X,float a_X,float b_X,float c_X,float d_X,float e_X,float f_X,float exposure_Y,float whitescale_Y,float a_Y,float b_Y,float c_Y,float d_Y,float e_Y,float f_Y,float exposure_Z,float whitescale_Z,float a_Z,float b_Z,float c_Z,float d_Z,float e_Z,float f_Z,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertRGB_Hable_HDRtoSDR(float exposure_R,float whitescale_R,float a_R,float b_R,float c_R,float d_R,float e_R,float f_R,float exposure_G,float whitescale_G,float a_G,float b_G,float c_G,float d_G,float e_G,float f_G,float exposure_B,float whitescale_B,float a_B,float b_B,float c_B,float d_B,float e_B,float f_B,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertXYZ_Mobius_HDRtoSDR(float exposure_X,float transition_X,float peak_X,float exposure_Y,float transition_Y,float peak_Y,float exposure_Z,float transition_Z,float peak_Z,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertRGB_Mobius_HDRtoSDR(float exposure_R,float transition_R,float peak_R,float exposure_G,float transition_G,float peak_G,float exposure_B,float transition_B,float peak_B,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertXYZ_Reinhard_HDRtoSDR(float exposure_X,float contrast_X,float peak_X,float exposure_Y,float contrast_Y,float peak_Y,float exposure_Z,float contrast_Z,float peak_Z,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertRGB_Reinhard_HDRtoSDR(float exposure_R,float contrast_R,float peak_R,float exposure_G,float contrast_G,float peak_G,float exposure_B,float contrast_B,float peak_B,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertLinearRGBtoYUV_BT2446_A_HDRtoSDR(float Lhdr,float Lsdr,float CoeffAdj,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConverXYZ_BT2446_C_HDRtoSDR(bool ChromaC,bool PQMode,float Lhdr,float Lsdr,float pct_ref,float pct_ip,float pct_wp,float pct_sdr_skin,float pct_hdr_skin,float WhiteShift,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

ConvertXYZ_ACES_HDRtoSDR(float a_X,float b_X,float c_X,float d_X,float e_X,float a_Y,float b_Y,float c_Y,float d_Y,float e_Y,float a_Z,float b_Z,float c_Z,float d_Z,float e_Z,float exposure_X,float exposure_Y,float exposure_Z,int pColor,float pRx,float pRy,float pGx,float pGy,float pBx,float pBy,float pWx,float pWy,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)
ConvertRGB_ACES_HDRtoSDR(float a_R,float b_R,float c_R,float d_R,float e_R,float a_G,float b_G,float c_G,float d_G,float e_G,float a_B,float b_B,float c_B,float d_B,float e_B,float exposure_R,float exposure_G,float exposure_B,bool fastmode,int threads,bool logicalCores,bool MaxPhysCore,bool SetAffinity,bool sleep,int prefetch,int ThreadLevel)

Brief description of most important parameters:
Color: Set the colorspace mode of the data.
OutputMode: Set the output data mode.
HDRMode: Set the HDR mode (PQ or HLG).
OOTF: Allow the output of linear displayed data instead of linear scene data.

See the ReadMe file for more informations and descriptions of the functions and their parameters.

Note about linear values:
For ConvertYUVtoxxx functions, the output is :
For HDR data (Color=0), HDRMode=(0 or 1), the output (R,G,B stage) is normalized for 1.0=10000 cd/mē (or 255 or 65535).
For SDR data (Color<>0),the output (R,G,B stage) is normalized for 1.0=100 cd/mē (or 255 or 65535).
For ConvertxxxtoYUV functions, the input is :
For HDR data (Color=0), HDRMode=(0 or 1),the input (R,G,B stage) is normalized for 1.0=10000 cd/mē (or 255 or 65535).
For SDR data (Color<>0),the input (R,G,B stage) is normalized for 1.0=100 cd/mē (or 255 or 65535).

Note: ConvertXYZ_Scale_HDRtoSDR is a simple scalar function, i've made just to see what result it produces. Don't have expectations on this plugin, but if by luck it works for you...

In the Document directory i've put a pdf file describing how things work, with detailled explainations and formula.

Some exemples:
BT.2020 to BT.709 convertion, do the following:

ConvertYUVtoXYZ(Color=1)
ConvertXYZtoYUV(pColor=1)


BT.709 to BT.2020 convertion, do the following:

ConvertYUVtoXYZ()
ConvertXYZtoYUV(Color=1,pColor=2)


HDR HLG (with mastering Lw at 1500 and HLG mastering display colorspace BT.2020) to HDR PQ convertion:

ConvertYUVtoLinearRGB(Color=0,HDRMode=1,HLGLw=1500,OOTF=false)
ConvertLinearRGBtoYUV(Color=0,OOTF=false)


HDR PQ to HDR HLG (with mastering Lw at 1200 and HLG mastering display colorspace BT.709) convertion:

ConvertYUVtoLinearRGB(Color=0,OOTF=false)
ConvertLinearRGBtoYUV(Color=0,HDRMode=1,HLGLw=1200,HLGColor=2,OOTF=false)

jpsdr
30th May 2018, 11:17
Some pre-release, for people to try and make feedback.
Don't get hope yet, these are tools for me for working on a real HDR to SDR. I have something i want to try. It will take a long time, and i don't even know if it will work, but i'm curious to try.
For now, the HDRtoSDR is not working, it's a simple linear scalling i just made for simple testing. But all the others functions are supposed to work (unless bug found).

I'll probably add a little later the simple standard tonemap commonly used.

Feel free to comment, feedback, and correct me if i have misunderstood how things work.

jpsdr
4th June 2018, 10:07
Note on use : If your chromaticity parameters are the same of the BT.xxxxx defined by the Color parameter, there is no need to specify them.
I'm working on a pdf document, which will explain and detail all of the formulas used, and the process and how i'm doing things, i hope i'll be able to put it with next release, but will not be before a week or two.
You'll be welcome at the time to read it, and most of it, correct me if there was things i've misunderstood.
Stay tuned... ;)

Otherwise, about perfomance, as i'm purely soft, even multi-threaded and vectorized ASM, DGHDRtoSDR will always beats this plugin, a lot !!! :D
Also, i didn't thought the simple linear scaling would realy produce interesting result, as i just made quick it in the meantime, focussing for now on my real needs, the YUV/XYZ/YUV converters.

jpsdr
4th June 2018, 17:57
Some quick benchmark on my system :

Coeff=50.0
Colorbars(width=1920,height=804,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,999)
ConvertYUVtoXYZ(Color=0,OutputMode=1,Rx=0.680,Ry=0.320,Gx=0.265,Gy=0.690,Bx=0.150,By=0.060)
ConvertXYZ_HDRtoSDR(Coeff_X=Coeff,Coeff_Y=Coeff,Coeff_Z=Coeff)
ConvertXYZtoYUV()

288.9fps


Coeff=50.0
Colorbars(width=3840,height=1608,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,999)
ConvertYUVtoXYZ(Color=0,OutputMode=1,Rx=0.680,Ry=0.320,Gx=0.265,Gy=0.690,Bx=0.150,By=0.060)
ConvertXYZ_HDRtoSDR(Coeff_X=Coeff,Coeff_Y=Coeff,Coeff_Z=Coeff)
ConvertXYZtoYUV()

47.66 fps

And real life 4k file bench :

Coeff=50.0
DGSource("DCrystal.dgi",i420=false,deinterlace=0,fieldop=0,fulldepth=true).crop(0,276,0,-276).trim(12632,12731)
ConvertYUVtoXYZ(Color=0,OutputMode=1,Rx=0.680,Ry=0.320,Gx=0.265,Gy=0.690,Bx=0.150,By=0.060)
ConvertXYZ_HDRtoSDR(Coeff_X=Coeff,Coeff_Y=Coeff,Coeff_Z=Coeff)
ConvertXYZtoYUV()

29.0fps

videoh
4th June 2018, 18:56
And what is your system please?

jpsdr
4th June 2018, 19:36
A Broadwell 10 cores (i7-6950X) overclocked @4.1GHz.

videoh
4th June 2018, 21:19
Thanks.

FranceBB
4th June 2018, 22:12
You have no idea how long I've been waiting for this.
Very appreciated! Thank you very much indeed! :D

jpsdr
5th June 2018, 09:06
Happy to see it's usefull to some people. But i warn again, unless bug found, everything is expected to work properly, except the HDR to SDR wich is just a multiply scaling, i've just made it out of curiosity to see what result a very simple thing would produce, without expectation of course, because if it would have been so simple, it would have been done a long time ago.
I'll had for 0.2 input RGBPS on ConvertRGBtoXYZ and ConvertLinearRGBtoYUV.
With also a document explaining things more precisely.
After, for 0.3, i'll try to add the standard tonemap. They are "simple" functions (multiply, div, add, sub), so, they can be vectorized.
And then, i'll "slowly" or "quietly" work on the real HDR to SDR process i want to try, but don't know if it will produce results...

jpsdr
8th June 2018, 15:03
New version, and i've added a document with the release.
So, feel free to read it, and provide feedback in case i was doing things wrong, and/or misunderstood things.

jpsdr
10th June 2018, 09:06
I've updated the 0.2 file (no changes in the binaries) with a new version of the document, a few very minor corrections on it.

Yanak
14th June 2018, 13:57
Hello jpsdr,

It's the first time i have a HDR file and try to do something with it so please forgive me if I'm asking silly things but after spending a couple of hours on this i didn't manage to get things working correctly.

This if the file mediaInfo from the mkv container :
Video
ID : 1
Format : HEVC
Format/Info : High Efficiency Video Coding
Commercial name : HDR10
Format profile : Main 10@L5.1@High
Codec ID : V_MPEGH/ISO/HEVC
Duration : 2 h 1 min
Bit rate : 45.2 Mb/s
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0 (Type 2)
Bit depth : 10 bits
Bits/(Pixel*Frame) : 0.227
Stream size : 40.6 GiB (85%)
Default : Yes
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Mastering display color primaries : Display P3
Mastering display luminance : min: 0.0000 cd/m2, max: 1100 cd/m2

I first open the file with DSS2 or FFVideoSource ( of course the colors are off here), i don't have and not yet tried with DGSource like in your real life 4k file bench script, I'm not sure if i need this or if DSS2 or FFms2/ffvideosource are enough.

I then tried to add like in your first post
ConvertYUVtoXYZ(Color=1)
ConvertXYZtoYUV(pColor=1)
plus tried a few other variations, i get the colors shifting but not getting the right colors out in avisynth, It's my first time messing with HDR stuff and i'm not sure if i am doing something wrong with your plugin or if the HEVC video is the problem, so if you have any hints to share please.

Thanks a lot ( and thanks for your very useful Avisynth plugins pack while i'm at it :p )

jpsdr
14th June 2018, 16:36
First, again, as i've explained several times, the plugin do only XYZ/RGBLinear conversion, but the HDR to SDR part is not realy properly implemented, there is only a simple quick linear scaling which may produce results on some case, but that's all.
If you want try something like this :

Coeff=20.0
ConvertYUVtoXYZ(Color=0,OutputMode=1)
ConvertXYZ_HDRtoSDR(Coeff_X=Coeff,Coeff_Y=Coeff,Coeff_Z=Coeff)
ConvertXYZtoYUV()

Your mediainfo information doesn't provide the chromaticity parameters metadata, so the script assume default for BT.2100.
Try different values of Coeff.
But again, for now, the HDR to SDR part is not realy implemented.

Yanak
14th June 2018, 16:57
Thanks a lot for the reply,

Will give more tries later at night and dig a bit more into this, never had to deal with HDR content before and i am still discovering all this.

Thank you very much for the hint.

Edit :
Got it working and displaying the right colors now, might need a little tweak with levels or hue/sat but it's good already, thanks again for the help.
I looked to see if i could get more infos about the chromacity on it but the only thing mediainfo is giving me that i forgot to post is "Writing library: ATEME Titan KFE 3.7.3 (4.7.3.1001)" and i don't think this will help anyways.

It's the first time i have to deal with such material and probably won't have to do this a lot in the near future so thank your very much for the help and patience with a nooby in this domain.

jpsdr
19th June 2018, 08:56
Message to Narkyy (from another realm). Can you tell me what is your issue between 0.1 and 0.2 version ?

Edit :
Ok, reproduce and found. Will be fixed in next release.

videoh
19th June 2018, 15:13
With the AVX2 build disabled, this test is being hit with b2[i] equal to zero.

if (fabs(b2[i])<=_zero) return(-2);

I guess you already found it.

jpsdr
19th June 2018, 16:44
I'll push soon (time for me to get back home) the fix on github, you'll be able to make a build if you want.

videoh
19th June 2018, 17:34
Great, thank you.

videoh
20th June 2018, 22:27
I wonder if you should consider renaming your package to avoid confusion with this:

https://gitlab.com/standards/HDRTools/

StainlessS
20th June 2018, 23:34
I wonder if you should consider renaming your package to avoid confusion with this:

Good idea, there have been such confilcts before on D9 [even if linked one aint on D9], HdrToolKit, or something, perhaps.
I once was attending a computer show where one of my lumps of s/w was only in demo form (could not manage to complete in time),
and a game with identical name was released at same show, I had to make a quick name change [which turned out to be better I think],
and avoided what could have been a few legal wrangles, and lots of user confusion.

jpsdr
21st June 2018, 08:45
... I'll see... in the future...

kolak
21st June 2018, 09:55
What bout HDR PQ to HLG conversion based on this paper:

http://downloads.bbc.co.uk/rd/pubs/papers/HDR/BBC_HDRTV_PQ_HLG_Transcode_v2.pdf

which suggests it should be pure math (no tone mapping, etc at leats for 1000 nits masters).

jpsdr
21st June 2018, 13:50
I'll take a look later, but will not this just shift the issue from converting [PQ-HDR -> SDR] to converting [HLG-HDR -> SDR] ?

kolak
21st June 2018, 15:46
Well, HDR to SDR is different story as it's difficult conversion and ideally should be done per scene, not global.
HDR PQ to HLG should be way easier (more like Rec.709 to Rec.601).

jpsdr
21st June 2018, 16:15
My final purpose (the reason i've made these tools) is to work on HDR to SDR.

kolak
21st June 2018, 23:02
Starting with something easier (which is still useful) is no harm :)

jpsdr
22nd June 2018, 09:03
I have no needs for PQ to HLG for now. But technicaly, once i'll implement the HLG in the plugins (because for now there is only PQ, my plugins have a HLGMode parameter, not implemented yet), doing something like :

ConvertYUVtoLinearRGB(Color=0,HLGMode=true)
ConvertLinearRGBtoYUV(Color=0)

will do the convertion.
I didn't implement HLG yet, because i've trouble to understand properly how it works. There is several range mode (so i'm a little loss).
But...! Maybe the doc you provided will help me to understand things. But, HLG is not my prority for now.
Ah... Just take a look. The french version and english version of the same release version document don't say the same thing.
French version (R-REC-BT.2100-1-201706-I!!PDF-F) talk of [0:12] range and possibility of [0:1], when english (R-REC-BT.2100-1-201706-I!!PDF-E) talk only of [0:1]...
Nice !

Edit :
Quick look, it seems that PQ has fixed parameters functions, for luminance range up to 10000 cd/mē. It seems that for HLG, the parameters changes according (Lw/Lb) values, when they are fixed for PQ. Meaning i'll have to add these parameters on my plugins, for when i'll implement HLG. I'll also have to add some "WhitePeak" value (at least on plugins using linear data on input), if i want to properly handle both HLG and PQ, because it seems that i can't assume (like i thought), that in linear value, 1.0 = 10000 cd/mē.
Well... I'll see this for later... when i'll do the 0.3 release ;)

kolak
22nd June 2018, 10:40
There are many references to [0,1] or [0,12] in English version.
Is there anything useful in link to HDRTools project provided in the document?

jpsdr
22nd June 2018, 11:38
Didn't read properly yet (but retrieved), i'm on something else for now, but there is a big chance it may help me to understand better HLG and this eventualy "whitepeak" information.

Edit :
Read a little more, it will help me. From what i understood (if properly), PQ is "fixed" -> 1 = 10000cd/mē, but HLG is adaptative.
Stop investigating for now, will continue in second time.

jpsdr
26th June 2018, 14:50
I've read doc more carefully, kolak doc helped... HLG is a pain in the ass !!!
I'll implement what i've understood, i just hope i have undersood properly... :D

FranceBB
26th June 2018, 17:42
I've read doc more carefully, kolak doc helped... HLG is a pain in the ass !!!
I'll implement what i've understood, i just hope i have undersood properly... :D

That would be amazing, 'cause last time I used Davinci Resolve to convert HDR10 to HLG, but it would indeed be very useful to have HLG working in your plugin.

jpsdr
26th June 2018, 19:28
And having someone to test/verify also ;)

Otherwise, does anyone know if it's possible to make a script which display, in the frame, the max value of Y for the curent frame (for an YUV video) ?
If yes, what would it be ?

StainlessS
26th June 2018, 20:44
Something like this maybe [EDIT: Below intended for 8 bit only]


Function TestFunc(clip c,Float Thresh_Min, Float Thresh_Max,Bool Debug,String LogFile) {
c
Yave=AverageLuma YMin=YPLaneMin(Thresh_Min) YMax=YPLaneMax(Thresh_Max)
Subtitle(String(YAve,"YAve=%7.3f : ")+String(YMin,"YMin=%3.0f : ")+String(YMax,"YMax=%3.0f"),Align=8) # Added
RT_Subtitle("%d] YAve=%7.3f YMin=%3d YMax=%3d",current_frame,YAve,YMin,YMax,Align=5)
(Debug) ? RT_DebugF("%d] YAve=%7.3f YMin=%3d YMax=%3d",current_frame,YAve,YMin,YMax,name="TestFunc: ") : NOP
(LogFile!="") ? RT_Writefile(LogFile,"%d] YAve=%7.3f YMin=%3d YMax=%3d",current_frame,YAve,YMin,YMax,Append=True) : NOP
Return last
}


FN = "D:\TestClip.avi"
LOGFILE = "D:\TestClip.Log"
DEBUG = True
Thresh_Min = 0.0
Thresh_Max = 0.0

(LOGFILE!="") ? RT_FileDelete(LOGFILE) : NOP # We Will Append

SSS = "TestFunc(" +
\ String(Thresh_Min,"%f") +
\ String(Thresh_Max,",%f,") +
\ String(DEBUG) +
\ "," + Chr(34) + LogFile + Chr(34) +
\ ")"

#SSS=RT_String("""TestFunc(%f,%f,%s,"%s")""",Thresh_Min,Thresh_Max,DEBUG,LogFile) # Alternative
#RT_DebugF("SSS=%s",SSS)

AviSource(FN)
Return Last.Scriptclip(SSS)


EDITED:

EDIT: Alternative to RT_string, StrFmt(Small dll):- https://forum.doom9.org/showthread.php?t=174649&highlight=StrFmt

EDIT: Or RT_Stats for 'RT_xxx' funcs:- https://forum.doom9.org/showthread.php?t=165479&highlight=RT_Stats

jpsdr
27th June 2018, 09:08
Tested, and seems there is a problem. I've used your 2.00 beta version.
The message is telling me that Average Plane can only be used within run-time filters.
No log file is created.

StainlessS
27th June 2018, 09:40
That is why its called from ScriptClip() in given code.
AverageLuma can only be called from within runtime environment,
or alternatively, cheat a bit, simulate within runtime filter, must eg current_frame=n, before the call to AverageLuma. (Scriptclip et al, set current_frame at every frame so it is known what frame is current).
For RT_AverageLuma(n=n).will also suffice, where n is accepted as current_frame, but MUST be done for every frame, thats is why Scriptclip is a good idea, unless using eg GScript for next to access frames.

"No log file is created", thats because its already caused an error and exited.
Try the script as given.

MOBILE:

EDIT: Post your failing script.

EDIT: do frame 42 only (untested)

Function TestFunc(clip c,Float Thresh_Min, Float Thresh_Max,Bool Debug,String LogFile) {
c

n=current_frame
trim(n,-1)
current_frame=0
Yave=AverageLuma YMin=YPLaneMin(Thresh_Min) YMax=YPLaneMax(Thresh_Max)
Subtitle(String(YAve,"YAve=%7.3f : ")+String(YMin,"YMin=%3.0f : ")+String(YMax,"YMax=%3.0f"),Align=8) # Added
RT_Subtitle("%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,Align=5)
(Debug) ? RT_DebugF("%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,name="TestFunc: ") : NOP
(LogFile!="") ? RT_Writefile(LogFile,"%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,Append=True) : NOP
Return last
}


FN = "D:\TestClip.avi"
LOGFILE = "D:\TestClip.Log"
DEBUG = True
Thresh_Min = 0.0
Thresh_Max = 0.0

(LOGFILE!="") ? RT_FileDelete(LOGFILE) : NOP # We Will Append

AviSource(FN)
current_frame=42 /* Simulate runtime */
TestClip(Thresh_Min,Thresh_Max,DEBUG,LOGFILE)
Return Last


EDIT: Oops, would print stats from frame 42 on frame zero, i think(not sure), edited in blue, should work.
EDIT: Oops again, will print frame 0] in stats, well you get the idea anyways I hope.

Alternative, MUST call with n=frame number, or n=current_frame from within ScriptClip.
Function TestFunc(clip c,int n,Float Thresh_Min, Float Thresh_Max,Bool Debug,String LogFile) {
c
trim(n,-1)
current_frame=0
Yave=AverageLuma YMin=YPLaneMin(Thresh_Min) YMax=YPLaneMax(Thresh_Max)
Subtitle(String(YAve,"YAve=%7.3f : ")+String(YMin,"YMin=%3.0f : ")+String(YMax,"YMax=%3.0f"),Align=8) # Added
RT_Subtitle("%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,Align=5)
(Debug) ? RT_DebugF("%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,name="TestFunc: ") : NOP
(LogFile!="") ? RT_Writefile(LogFile,"%d] YAve=%7.3f YMin=%3d YMax=%3d",n,YAve,YMin,YMax,Append=True) : NOP
Return last
}

jpsdr
27th June 2018, 12:26
Thanks, i finaly been able to get what i want.

jpsdr
28th June 2018, 15:33
That would be amazing, 'cause last time I used Davinci Resolve to convert HDR10 to HLG, but it would indeed be very useful to have HLG working in your plugin.

Do you have, by any chance, an HLG encoded stream you could share ?

videoh
28th June 2018, 17:57
http://4kmedia.org/travelxp-4k-hdr-hlg-sample/

Or google for "hdr hlg sample files". You'll find a lot of them.

Not all have the SEI denoting HLG, but some do.

jpsdr
28th June 2018, 18:18
It didn't even cross my mind to google search... :(
Thanks.

What are exactly HLG SEI information ? Is there some other mastering informations in the H265 spec ? I've tried a search for "HLG" in the T-REC-H.265-201612-I!!PDF-E document, but found no information about such a thing.

videoh
28th June 2018, 18:49
You can google "HLG SEI message". BTW, DGIndexNV notifies this SEI in the DGI file.

jpsdr
28th June 2018, 20:12
Ok, i see (at least, i hope...).
... Hum... If i understand properly, it seems i have to add again another parameter for HLG, which specifies what transfer color matrix use within the OOTF function, because it's not necessary BT.2020... Argh....

jpsdr
30th July 2018, 16:30
After a long fight (HLG is realy a pain in the ass if you want to optimize things), i'm near the end. But i have two choices, for a specific point. For speed-up i've implemented lookup. 8 bit is 3D lookup, so it's fine, but for 10 and 12 bit i've tried 2D lookup. It's faster than 16 bits, but... there is a noticeable resolution loss on low values (visible on some colors of ColorBars when testing YUVtoRGB followed by RGBtoYUV).
Choice 1 : Keep actual status, with 2D lookup for 10/12 bits.
As most of source filters produce 16bits ouput, if you don't want speed, you keep 16 bits, it you want speed-up, you add ConvertBits to reduce the bitdepth to the actual true bitdepth of the source. With this option, you keep the possibility to choose.
Choice 2 : No 2D lookup, 10 to 16 bit, same speed.
For now, i'm more on "Choice 1", allowing users to keep the possibility to choose, but i want to know what others users thinks what would be better.

BTW :I personnaly have nothing to display HDR video, no reader, no screen, nothing. The only tests i can do is checking ouput is not obvious garbage, no crash or things like this, that an operation followed by its reverse produce output indentical to input, but i have no way to check if output is realy proper.

jpsdr
31st July 2018, 17:52
Finaly, the Hell Log Gamma is done. New version, add HLG support, see first post.
I've also updated the PDF document, there was some still some mistake (things i've not totaly properly understood) on the last one.
I've made a lot of tests, but there's still the possibilty that i've missed something, but i hope not... ;)

FranceBB
1st August 2018, 03:58
Thank you very much indeed.

By the way there's a typo in the Readme "Outpout RGB64." instead of "Output" in "ConvertXYZtoRGB".

Anyway, I tried this:

FFMpegSource2("test.mov", atrack=-1)

ConvertYUVtoXYZ(Color=2, OutputMode=2, fullrange=false)

ConvertXYZtoRGB(OutputMode=0)

ConvertXYZ_SDRtoHDR()

But ConvertXYZ_SDRtoHDR keeps complaining that input format must be RGB64 or RGBPS.

So I tried with:

ConvertYUVtoLinearRGB(Color=2, OutputMode=2, fullrange=false)

ConvertXYZ_SDRtoHDR()

But again ConvertXYZ_SDRtoHDR keeps complaining that input format must be RGB64 or RGBPS.

I'm trying to convert a normal 8bit yv12() footage to XYZ Planar float RGB 8bit and then use ConvertXYZ_SDRtoHDR() to get an HDR BT2020 PQ 8bit output.


Windows XP x86 Build, Avisynth 2.6.1.

Am I doing something wrong?

Thank you in advance.

Oh, by the way, are you considering to integrate this into your jpsdr_plugin.dll?

jpsdr
1st August 2018, 08:34
Yes, there is "something wrong" : standard avisynth doesn't support RGB64 neither RGBPS, so, you need avs+.

8 bits creates too much precision loss on linear data on HDR video. You can easely see it just by doing, on 8 bit video (even if it's not an HDR video) the following (it will use for this test the PQ HDR path) :
ConvertYUVtoLinearRGB(Color=0)
ConvertLinearRGBtoYUV(Color=0)
Theoricaly, the ouput should be identical to the input, but you'll see effect of precision loss. So, doing HDRtoSDR functions on 8 bits data is a total nonsense (when your data are the linear sensor data).
This could be possible if you're doing a function which will do the 3 functions in one (YUV -> RGB -> HDRtoSDR -> RGB -> YUV) and working internaly with 16 bits data, but it's not the path i've choosen. I choose modular functions option.
So if you stay with standard avisynth, you'll not be able to use the specific HDR/SDR functions.

I've re-read again, and there is nothing wrong in the description of "ConvertXYZtoRGB" in the readme.

Yes, i'll integrate it later, after the 0.4.0, where i'll add Hable, Mobius and Reinhard (but again, they'll be usable only with avs+).
Expect 6 new functions like ConvertXYZ_Mobius_HDRtoSDR, ConvertRGB_Mobius_HDRtoSDR, etc...

FranceBB
1st August 2018, 10:07
avisynth doesn't support RGB64 neither RGBPS


I see...


8 bits creates too much precision loss on linear data on HDR video.


Well... yes...
But 16bit stacked conversion to RGB48y would probably provide enough precision, I think and Avisynth supports that thanks to Dither Tool, but I don't think I'll ever see it supported as you said that you didn't like the stacked 16bit format 'cause you considered it an "hack" back when I asked you about NNEDI... :'(

jpsdr
1st August 2018, 10:14
Yes, as it exists avs+ which supports 16 bits, i don't intend to spend/waste time to add stacked version on my plugins.

Is it XP which prevents you from using avs+ ? avs+ can't be installed or don't work on XP ?

FranceBB
1st August 2018, 10:52
Is it XP which prevents you from using avs+ ? avs+ can't be installed or don't work on XP ?

I don't know whether it's officially supported or not, but it installs on XP. It automatically detected my Avisynth installation and offered to "migrate my plugins to AVS+". I clicked "yes" and it only copied some of the plugins I had in my plugin folder. Then, when I tried to run it with a simple command, it loaded them all together automatically ('cause they are .avsi) and it crashed.
I've been using Avisynth since 2006 and I have many plugins in my plugins directory. I gotta find out which one/ones are causing the problem, why they are causing the problem and a workaround to solve it. I'm gonna open up a new thread about this in "Avisynth usage" though.

StainlessS
1st August 2018, 13:09
FranceBB,
Just get Groucho2004 AvsMeter

AvsMeter Avsinfo

Avs+ officially supports XP and is much better than avs standard.

jpsdr
3rd August 2018, 21:06
New version, see first post.

jpsdr
9th August 2018, 18:51
New version with tonemap, see first post.

jpsdr
10th August 2018, 17:09
New version, minor change.

jpsdr
11th August 2018, 14:29
As i've explained in post #42, i don't know if finaly it's working properly. So, users who have HDR display and stuff, can you provide feedback ? Are the formula i use/implement good ? Are things working properly ?

FranceBB
14th August 2018, 03:58
As i've explained in post #42, i don't know if finaly it's working properly. So, users who have HDR display and stuff, can you provide feedback ? Are the formula i use/implement good ? Are things working properly ?

I tested them with their default values, so I didn't change parameters out of curiosity.

From the test results, it seems that HDR to SDR is working as expected, with Reinhard getting closest to the original compared to the others.

Source: 4K HDR 10bit BT2100 PQ
Scene: Sunset, a very dark scene, with a bit of contrast between the objects (dark) and the sky (not so bright, yet brighter than the objects).

- ConvertXYZ_Scale_HDRtoSDR

Grade: F

Insufficient, totally unreliable, colors completely messed up, out of range, unwatchable. On top of that, it turned a sunset into a sunrise.
It's a simple scalar function, so it's not expected to be reliable, but still, the output was completely wrong.

- ConvertXYZ_Hable_HDRtoSDR

Grade: C+

Way better than the scalar function, however, it was brighter than the original HDR version. I had the feeling that it tried to "exasperate" the colors, trying to reproduce a very strong fake HDR effect in SDR. Although some people might love very strong colors, it doesn't quite resemble the original HDR version which is way darker. As result, the colors that were already kinda "bright" in the HDR version, became too bright in the Hable SDR version, compromising details (like the edges of the clouds) with the white point set too high.
Still, I think that it's tweakable, you can play around with the settings to make it look better and some people might like it, even though this "colorful" tone-mapping approach is not my favorite.

- ConvertXYZ_Mobius_HDRtoSDR

Grade: B

This is more like it.
With the default settings it got close to the original and the content is actually watchable and many people wouldn't complain with the result, to be fair.
However... I'm not one of these people.
The result is actually slightly darker than the original HDR in some areas and slightly brighter in some other, which is interesting... Odd, but interesting.
The grass became slightly darker than the original as well as few other objects, while the sky became slightly brighter.
Almost no details were lost in the sky and in the clouds, but they were still slightly brighter. As to the grass and other objects, they indeed lost details because they were slightly too dark, but I'm pretty confident that playing around with the settings a good balance can be found.
Mobius has slightly too contrast because it tries to reproduce the HDR one in the best possible way; sometimes it gets it wrong, but it can be tweaked and the result is gonna look acceptable.

- ConvertXYZ_Reinhard_HDRtoSDR

Grade: A

With the default settings, Reinhard seems to be the best one.
I'm very impressed, it almost looks like the original HDR and it gives a really good, conservative feeling when you watch it on an SDR screen. I mean, if you are not an encoder and you don't deal with these stuff (like the normal user watching TV) you probably wouldn't even notice that the content was graded in PQ and then tone-mapped to SDR via Reinhard.
Compared to Mobius, the sky is slightly darker (closer to the original) and the grass and other objects are brighter (again, closer to the original). The sky looks pretty legit and natural and there are more details in the grass and other objects compared to Mobius, however, it's still not like the original, even though it's pretty close. It can be tweaked as well and I think it can be improved even more by fine-tuning parameters and I believe it has the potential to look really close to the original. I really like it and it's definitely gonna be my choice if I gotta make HDR to SDR conversion.



Screenshot:

I compared the SDR footages with the HDR one using my TV, because my computer is obviously SDR (a normal LCD 1920x1080 60Hz, nothing special).
Besides, trying to screenshot an HDR material doesn't really make much sense, but in order to give you something to compare the tone-mapped SDR versions, I'm gonna give you... well... "something".

- "Original" HDR (well, sort of):
Link (https://i.imgur.com/yel0v1a.jpg)

- Simple Scalar Function:
Link (https://i.imgur.com/dEZVCaR.jpg)

- Hable:
Link (https://i.imgur.com/hx5Kf1J.jpg)

- Mobius:
Link (https://i.imgur.com/Qt6d2x5.jpg)

- Reinhard:
Link (https://i.imgur.com/9u95DjI.jpg)


I don't see anything wrong in the implementation of Jean-Philippe: it works and I find it very useful.
I didn't try SDR to HDR, PQ to HLG and HLG to PQ, though.

It would be interesting to test PQ to HLG and vice-versa using HDRTools and Davinci Resolve, then compare the results and check whether there are differences or not, but I don't have time for this right now.

Anyway, a big fat thank you to Jean-Philippe for this amazing plugin, once again.

On a very side note: I got this error the very first time I tried to run Hable, when I was seeking the video, but after seeking frame-by-frame without jumping "frenetically", it disappeared.

https://i.imgur.com/MO3o98v.png

jpsdr
14th August 2018, 09:17
Scale seems to provide "appropriate" results with a coeff between 35 - 40. On the other side, as i've said, it was just "out of curiosity" to see what a simple scalar can do on XYZ colorspace, i never expect great result from it. If it was so simple, it would have been done a long time ago ;)

About detail loss, out of curiosity : Does it change if you use OutputMode=2 on the first ConvertYUVtoXYZ (or similar) ?

I'll take a look on Hable just in case, can you provide the exact script ? But, the 3 tonemap are all "indetical". I mean, the code is just a copy/paste on all 3, just the formula on the lookup table creation on the constructor changes.

I'll integrate it on the "all" plugins package version.

After, i don't know what you're seeking with, but i've noticed that according the tool used, there is 2 working ways :
- Constructor is run only once, and when seeking, only getframe is called (this is what you have in Virtualdub).
- Constructor/destructor is called each time a new frame is required. As filter has a "long" setup time (creating lookups), if you freneticaly seek, it's not impossible that you hit a "time out" issue, requesting 5 frames when the 1rst is still not out. This is how tools like avspmod seems to work. My guess is that you are in this case.

Otherwise, thanks for your post.

Now, i'll slowly work on my original idea, and the real "why" i've created these tools : Try a neural network approch on HDR to SDR. No idea if it will even work, but without trying, who knows...
To bad tritical is not here anymore, i would have asked some question about neural network. I've made my neural network class, i think i have the learning retropropagation algorithm correct, but i need convergence tweaking and feedback from neural networl expert. Well, i'll see later.

StainlessS
14th August 2018, 10:42
To bad tritical is not here anymore, i would have asked some question about neural network.

V.C.Mohan still visits quite regularly, and wrote NeuralNet plugin, no idea if he can assist.
http://www.avisynth.nl/users/vcmohan/NeuralNet/NeuralNet.html

jpsdr
14th August 2018, 17:50
New version, minor change, see first post.

jpsdr
14th August 2018, 18:56
For Scale tonemap, the following is not too bad, at least on my small video part of Dark Crystal :
Coeff_X=37,Coeff_Y=36,Coeff_Z=36

FranceBB
15th August 2018, 14:21
I don't know what you're seeking with, but i've noticed that according the tool used, there is 2 working ways :
- Constructor is run only once, and when seeking, only getframe is called (this is what you have in Virtualdub).
- Constructor/destructor is called each time a new frame is required. As filter has a "long" setup time (creating lookups), if you freneticaly seek, it's not impossible that you hit a "time out" issue, requesting 5 frames when the 1rst is still not out. This is how tools like avspmod seems to work. My guess is that you are in this case.


Yes, you are right, it was AVSPmod.
I'm downloading the new version of plugin_JPSDR, so thank you for including this new filter there.
As to the other tests, I'll eventually make a few more when I'll have time, but right now I'm really focused on something else due to work-related problems.

jpsdr
16th August 2018, 09:36
HLG mode can have a very long (like in seconds) setup time according the input/ouput and configuration. Warning, it will be a nightmare with tools working calling constructor/destructor each time you seek a frame.

FranceBB
30th September 2018, 05:12
New test and new comparisons! :D

Original HDR Source: Link (https://i.imgur.com/trL32ka.jpg)
Normal HDR to SDR: Link (https://i.imgur.com/L4AxbWn.jpg)
Scale default: Link (https://i.imgur.com/DpgmMWX.jpg)

Hable: Link (https://i.imgur.com/V2xLkwU.jpg)


ConvertBits(16)

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

ConvertXYZ_Hable_HDRtoSDR(exposure_X=7.0)

ConvertXYZtoYUV(pColor=0)


Not bad at all, very close to the original.
Too bad for the object that Loki is holding: I got it too bright and details are lost.
I tried to play a bit with the white point, but I didn't manage to get it correct:

Hable v2: Link (https://i.imgur.com/PxF1AsE.jpg)


ConvertBits(16)

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

ConvertXYZ_Hable_HDRtoSDR(exposure_X=7.0, whitescale_X=8.0)

ConvertXYZtoYUV(pColor=0)


Mobius: https://i.imgur.com/tg8V3iF.jpg


ConvertBits(16)

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

ConvertXYZ_Mobius_HDRtoSDR(exposure_X=17.0, peak_X=1.1)

ConvertXYZtoYUV(pColor=0)

Close, but I've got the same problem: the object is too bright and therefore I lose details...

And... here comes the star... here comes the good one... here comes the one that keeps details... here comes my favorite one:
Reinhard: Link (https://i.imgur.com/yXJkcjo.jpg)


ConvertBits(16)

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)

ConvertXYZtoYUV(pColor=0)


Just perfect, as I expected from Reinhard.
The exposure is exactly the same that I have on the HDR content and details of the object are not lost as I'm able to adjust the contrast accordingly. In my former chart I gave Reinhard an "A" and I'm gonna confirm my grade again.

Updated chart:

- ConvertXYZ_Scale_HDRtoSDR:

Grade: F

I gave it an F before because it didn't give me the correct values at all and I still gotta say that it's not fit for the job. Yes, it can be useful to test values and see how much you can scale down, but the result will be unwatchable anyway.

- ConvertXYZ_Hable_HDRtoSDR

Grade: C+

It's better than the "Scale" function, but I still think that it tries to "exasperate" the colors and give a sort of explosive fake HDR effect to the viewer at the expense of details which, for me, it's an absolute "no go".

- ConvertXYZ_Mobius_HDRtoSDR

Grade: B

It still tries to accentuate the "fake HDR feeling" by bringing colours a bit too saturated, but some people may like it. Overall, it's watchable for many people, but unfortunately, it loses some highlights. The kind of people that like these kind of grading probably doesn't care and actually prefers something like this, but it's simply not me.

- ConvertXYZ_Reinhard_HDRtoSDR

Grade: A

Reinhard gets the job done and it does it well, period.
It was my favorite one and it still is as today confirmed my thoughts once again.
Thanks to the contrast parameter and the exposure parameter it's possible to tweak it to get a very good result.
Yes, it's not gonna have extremely saturated colors and they will be perfectly legit for the BT709 range, the black level is gonna be pretty much perfect, details are gonna be kept and highlights are gonna be preserved.
Overall, it's my recommended way to do HDR to SDR.

jpsdr
30th September 2018, 09:50
In the readme :

pColor -
Color mode used in YUV/RGBtoXYZ.
0 : BT2100
1 : BT2020
2 : BT709
3 : BT601_525
4 : BT601_625

Default: 2 if Color=0, 0 otherwise.


So, as you've used :

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

You have to use :

ConvertXYZtoYUV(pColor=0)


Otherwise, thanks for your tests and report.

FranceBB
30th September 2018, 16:57
@jpsdr... yes, of course. Tests are legit with pColor=0, but I forgot to include the script while I was testing, so I did it later while I was already writing the post here and I pasted the wrong one. xD

jpsdr
1st October 2018, 08:46
You can eventualy try/test to be more accurate if you have the SEI mastering parameters of your HDR stream. You don't have them by any chance ?

Soulnight
13th October 2018, 20:16
Hello!

thank you for creating this tool. :)

I am trying to do a small experiment with hdr rec2020 content to display in a certain color the pixels having colors outside REC709 colorspace.

I thought I would have to:

1) first convert from YUV to RGB.
2) Then convert non linear RGB to Linear RGB
3) Multiply by the matrix to go from REC2020 to REC709 colorspace

At 3), I though, I should then tell what to do with RGB values outsides the legal range and specify their value.

Like:

= decodeTransferFunction(sourcePixel); float3 rgb709 = mul(rgb2020, float3x3(...)); float3 result; if ((rgb709.r < 0.0) || (rgb709.r > 1.0) || (rgb709.g < 0.0) || (rgb709.g > 1.0) || (rgb709.b < 0.0) || (rgb709.b > 1.0)) result = 1.0; else result = 0.0;

But I don't know how to do that in Avisynth.

I currently have that code:

loadplugin("C:\Users\flole\Downloads\ManualColorMatrix\ManualColorMatrix_26.dll")
loadplugin("C:\Users\flole\Videos\AviSynth\HDRTools\x86\Release_W7\HDRTools.dll")
Directshowsource("F:\Kodi\Demo 4k HDR\The World In HDR 4K Demo.mkv")
ConvertYUVtoLinearRGB(Color=1)
#isRGB()
ManualColorMatrix(1, 1.66049, -0.58764, -0.07285, -0.12455, 1.13290, -0.00835, -0.01815, -0.10058, 1.11873)

Does the function you have written directly combined step 1 and 2?
ConvertYUVtoLinearRGB(Color=1)

Thank you, Merci beaucoup.
Florian

ps:
Final goal will be to visualize what color are "extended" and outside the REC709 color space.
And then analyse a full movie to get a % of pixels and frames showing colors outside the REC709 range.
And then if possible, even say how far and saturated are those colors for different Hue (RED, green, etc).

jpsdr
14th October 2018, 09:29
If you check the some example code provided in the first post (and/or in the Readme), you'll see exactly the script needed for what you want to do.
Indeed it's possible to do this from linear RGB step with a transformation matrix combining the two RGB -> XYZ / XYZ -> RGB matrix, but as you can see in the examples, you can directly do that with my tools, but going by the XYZ step, and not the LinearRGB step.
Also, read the pdf document i've provided with the plugin, i've tried to explain things, so maybe it will help you to understand exactly what you have in each step of the process of transformation signal from the natural real world light to the YUV data we are working on on our PC.

Soulnight
14th October 2018, 11:24
Thanks for the answer.
I did did read and I tried to understand the examples as well.

The thing is, I need to sort the "good" from the "bad" pixels afterwards.

And I understand how to define what is an illegal pixel in RGB (in 8bits, bigger than 256 or smaller than 0). With XTZ, it seems more complicated.

Can you confirm that:

ConvertYUVtoLinearRGB(Color=1)

not only convert YUV to RGB but then also convert non linear RGB to linear RGB?:thanks:

jpsdr
15th October 2018, 10:12
My bad, i didn't notice your PS. I thought you wanted to make convertion, didn't see you wanted to make some analysis...
Yes, i confirm.
All the functions are indeed made to not produce bad pixels, so any value outside range will be clipped, so the functions for the second conversion step can't be used for your analysis.

Soulnight
15th October 2018, 10:22
Thanks! I want to preserve the illegal values for the color outside rec709 so I can color them to black or white for example (using something like a if statement. If pixel r or g or b value outside the 0 to 255 range, then r=g=b=0)

Do you know how to do that?

jpsdr
15th October 2018, 10:40
Unfortunately, not.
But for sure, you'll need filters working on float values to do this.
So, first, set OutputMode=2 on the ConvertYUVtoLinearRGB.
If ManualColorMatrix worked on float values, it would have been exactly what you need just after.
Your coeff matrix on your previous post, you get them reverting the following 709 -> 2020 matrix provided in rec2087 ?
0.6274 0.3293 0.0433
0.0691 0.9195 0.0114
0.0164 0.0880 0.8956

Soulnight
15th October 2018, 10:57
Ok. Too bad.

I will attach this evening my excel spreadsheet where I gave I came up with all the conversion matrix.

It's a multi step process and you have to know your colorspace coordinates.

In the future, I will also do those studies for specific "triangle gamut " that I will have measured for display measuring like 90% dci.

Goal is to see how often do we have information outside of the rec709 colorspace, or outside the real colorspace covered by a tv/projector.

Any idea to do matrix multiplication in float?

-QfG-
20th October 2018, 10:58
First, this an awesome filter for avisynth, and second , sorry for my bad english, i'm German :stupid: . Ok i have a small Problem, i will show it here. I post the previe pictures in previemode, click for fullsize...

Beginning, this is the picture with MPC-BE madVR 150 Nits. I will this result in my target file:

Original 4K with madVR 150 Nits @1080p
http://fs1.directupload.net/images/181020/temp/5u88sgd7.jpg (http://www.directupload.net/file/d/5246/5u88sgd7_jpg.htm)

Try with HLG
Exposure=2
Whitescale=11.2
ConvertYUVtoXYZ(Color=0, OutputMode=0, HDRMode=2, fullrange=false)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=Exposure, exposure_Y=Exposure, exposure_Z=Exposure, whitescale_X=Whitescale, whitescale_Y=Whitescale, whitescale_Z=Whitescale)
ConvertXYZtoYUV(pColor=0, OutputMode=2)
http://fs1.directupload.net/images/181020/temp/iebp2nqv.jpg (http://www.directupload.net/file/d/5246/iebp2nqv_jpg.htm)

Ok i like the Details of the HLG , but the problem is, where are my Colors? I need more Colors...

Try with PQ
Exposure=2
Whitescale=66
ConvertYUVtoXYZ(Color=0, OutputMode=0, HDRMode=0, fullrange=false)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=Exposure, exposure_Y=Exposure, exposure_Z=Exposure, whitescale_X=Whitescale, whitescale_Y=Whitescale, whitescale_Z=Whitescale)
ConvertXYZtoYUV(pColor=0, OutputMode=2)
http://fs1.directupload.net/images/181020/temp/wb5mahse.jpg (http://www.directupload.net/file/d/5246/wb5mahse_jpg.htm)

The result with the standard whitescale=11.2 to dark. With Whitescale=66 the brightness and colors perfect, but too much white (show the skyline in the upper left corner).

Conclusion:

I need more colors in HLG, because i love this detailed picture. For PQ conversion i can use DGTonemap, this is ok. Is there any Solution for more colors and fewer brightness in HLG mode?

jpsdr
20th October 2018, 12:37
First, you have to use the proper mode. If your file is HDR PQ, use PQ, if your file is HDR HLG, use HLG, so, my first question would be : what mode is your file ? Can you post mediainfo result of it ?
According tests made by FranceBB (post #61), for him reinhard produde the best results. Have you tried it ?

-QfG-
20th October 2018, 13:21
thanks for response, file transfer is PQ.

Video
ID : 1
Format : HEVC
Format/Info : High Efficiency Video Coding
Format_Commercial_IfAny : HDR10
Format-Profil : Main 10@L5.1@High
Codec-ID : V_MPEGH/ISO/HEVC
Dauer : 2 h 2 min
Bitrate : 35,0 Mb/s
Breite : 3 840 Pixel
Höhe : 2 160 Pixel
Bildseitenverhältnis : 16:9
Modus der Bildwiederholungsrate : konstant
Bildwiederholungsrate : 23,976 (24000/1001) FPS
ColorSpace : YUV
ChromaSubsampling/String : 4:2:0 (Type 2)
BitDepth/String : 10 bits
Bits/(Pixel*Frame) : 0.176
Stream-Größe : 29,8 GiB (79%)
verwendete Encoder-Bibliothek : ATEME Titan File 3.8.3 (4.8.3.0)
Default : Nein
Forced : Nein
colour_range : Limited
colour_primaries : BT.2020
transfer_characteristics : PQ
matrix_coefficients : BT.2020 non-constant
MasteringDisplay_ColorPrimaries : Display P3
MasteringDisplay_Luminance : min: 0.0050 cd/m2, max: 1000 cd/m2


I tried Reinhard, but Reinhard has "warmer" colors as Hable. Hable is perfect, without this white Bloom effect. But now, it's looks much better then before, playing with the switches :) ...

http://fs1.directupload.net/images/181020/temp/cc7hf3i7.jpg (http://www.directupload.net/file/d/5246/cc7hf3i7_jpg.htm)

jpsdr
21st October 2018, 10:11
... "Display P3" is not of big help, i need the values (not your fault)... :(
Do you use DGIndexNV by any chance ? If yes, what are the SEI parameters value ?

sneaker_ger
21st October 2018, 10:25
MasteringDisplay_ColorPrimaries : Display P3
is the same as
Mastering display color primar : R: x=0.680000 y=0.320000, G: x=0.265000 y=0.690000, B: x=0.150000 y=0.060000, White point: x=0.312700 y=0.329000

Also called "P3 D65".
https://en.wikipedia.org/wiki/DCI-P3#System_colorimetry

jpsdr
21st October 2018, 11:52
Thanks.
In that case, to have correct result, you should do :

ConvertYUVtoXYZ(Color=0,Rx=0.680,Ry=0.320,Gx=0.265,Gy=0.690,Bx=0.150,By=0.060)
#Whatever XYZ HDR to SDR (pColor=0,pRx=0.680,pRy=0.320,pGx=0.265,pGy=0.690,pBx=0.150,pBy=0.060)
ConvertXYZtoYUV(Color=2,pColor=0,pRx=0.680,pRy=0.320,pGx=0.265,pGy=0.690,pBx=0.150,pBy=0.060)

-QfG-
21st October 2018, 12:34
Thanks.
In that case, to have correct result, you should do :

ConvertYUVtoXYZ(Color=0,Rx=0.680,Ry=0.320,Gx=0.265,Gy=0.690,Bx=0.150,By=0.060)
#Whatever XYZ HDR to SDR (pColor=0,pRx=0.680,pRy=0.320,pGx=0.265,pGy=0.690,pBx=0.150,pBy=0.060)
ConvertXYZtoYUV(Color=2,pColor=0,pRx=0.680,pRy=0.320,pGx=0.265,pGy=0.690,pBx=0.150,pBy=0.060)


thx, i will try it :). Here my DGIndex Log:

DGHEVCIndexFileNV20 DGIndexNV 2053.0.0.159 X64

DEVICE 0
DECODE_MODES 0,0,0,0,0
STREAM 2 0
CLIP 0 0 0 0
RANGE 0 0 18446744073709551615 0
DEMUX 2,3,4,5,6,7
DEPTH 10
ASPECT 16 9
COLORIMETRY 9 16 9

MASTERING 13250 34500 7500 3000 34000 16000 15635 16450 10000000 50

But i'm to stupid to check, how i must calculate the MASTERING values for HDRTools :(.

jpsdr
21st October 2018, 12:53
It's explained in the ReadMe :

Another way to get them, it's if you're using DGIndexNV, on HEVC HDR stream.
In that case, you'll have in the DGI file this line (for exemple) :

MASTERING 13250 34500 7500 3000 34000 16000 15635 16450 40000000 50

The values are the following:

MASTERING GreenX GreenY BlueX BlueY RedX RedY WhiteX WhiteY MaxMasteringLevel MinMasteringLevel

The GreenX GreenY BlueX BlueY RedX RedY WhiteX WhiteY are by 0.00002 steps.
The MaxMasteringLevel MinMasteringLevel are by 0.0001 steps.

In our exemple, it will result :
Gx: 0.265
Gy: 0.690
Bx: 0.150
By: 0.060
Rx: 0.680
Ry: 0.320
Wx: 0.3127
Wy: 0.3290
Max: 4000
Min: 0.05

-QfG-
21st October 2018, 13:40
Yes i have seen it, but don't understand.

But know i think i find my mistake:

GreenX in DGIndex = 13250. Steps = 0.00002

So 13250/0.00002 = 662500000 :stupid::stupid::stupid:

I must: 13250x0.00002 = 0,265 :readfaq::readfaq::thanks:

Now, i check it ;)

EDIT:

So i'm happy and i like it :) Changed PQ to HLG
http://screenshotcomparison.com/comparison/122892

thx for this awasome plugin :)

SpasV
10th December 2018, 21:35
This is a plugin with functions made to work on HDR videos, but can also eventualy work to do some color conversions.

Note: ConvertXYZ_Scale_HDRtoSDR is a simple scalar function, i've made just to see what result it produces. Don't have expectations on this plugin, but if by luck it works for you...


Hi, I think you have succeeded. Great.
I haven't tried your work. I have some interest in programming video filters and I could do some work for you if you need.

Actually, I'm interesting in formal evaluating of color space transformations. In particularly, I've tried a simple transformation - truncating the color codes' two LSB, maybe analogous to ConvertXYZ_Scale_HDRtoSDR with this script:

DGSource("F:\Gladiator-2160p\Gladiator.hevc.dgi",i420=true,fulldepth=true)
z_ConvertFormat(width=1920,height=1080,pixel_type="YV12",dither_type="none"

to get an 2160p HDR (10-bit color) BluRay video conveted to 1080p SDR (8-bit) color retaining the Rec.2020/PQ color space.
Using Sony Catalyst Browse I've seen
Source: Rec.2020/PQ, Working Rec.709, Preview: Rec.709.
and video in the working space visually undistinguished from the source with waveform under 67 %.

So, I'm interested in programming a waveform/histogram generating Avisynth function.

jpsdr
1st June 2019, 12:03
New version, see first post.

jpsdr
7th June 2019, 11:44
New version, see first post.

StvG
16th August 2019, 00:39
Conversion 2020->709:
ConvertYUVtoXYZ(Color=1).ConvertXYZtoYUV(Color=2, pColor=1, OutputMode=2)
ConvertYUVtoXYZ(Color=1).ConvertXYZtoYUV(Color=2, pColor=2, OutputMode=2)
Both conversions give identical result. Is it expected? Is it not wrong for the pColor=2 variant? avsresize gives different results - https://forum.doom9.org/showthread.php?p=1881971#post1881971

jpsdr
16th August 2019, 22:06
pColor and also pRx,pRy,pGx,pGy,pBx,pBy,pWx,pWy are used only to compute the Min/Max values of XYZ, which are not a stable [0,1] in all situations like RGB, but are White Point and R,G,B point chromaticity dependent.

With this, with integer format, 16 bit for exemple, i can affect [0]=Min(X,Y,Z) [65535]=Max(X,Y,Z) in the inputs. These previous parameters have no effect in float format. The parameter is here for optimal theorical performance, but i don't know if it will produce real visible effect between the standard BT. It will if you use different White Point (his has the biggest effect), or realy very different R,G,B point.

Roughly, range is Y [0,1.00], X[0,0.96], Z[0,1.10]. Didn't check more decimal, but maybe for BT.709 max Z is 1.1001 and for BT.2020, max Z is 1.002. I think it's something like that, realy no more.
Well, the previous parameters are here to be sure you have input proper range value used in integer mode.

And again, of course, no effect in float mode because no needs.

Described also in the Warning page 3 of ColorConversion.pdf document i've provided within the binaries package.

hello_hello
17th August 2019, 00:56
jpsdr,
I'm still not clear as to why I'm getting such bizarre results for XYZ conversions here (https://forum.doom9.org/showthread.php?p=1881952#post1881952). Am I doing something wrong?

I read your reply in the other thread and looked at the PDF, and I can see rec.601_525 line and rec.601_625 line are different, but the question I'm trying to get a simple answer to is... why do other programs such as ColorMatrix & DitherTools only have/require one version of rec.601?
I assume my understanding is wrong, but I thought once analogue PAL and NTSC are converted to digital, the colorimetry is the same, and therefore there's only one flavour of rec.601 required for colorimetry conversions. When I play an NTSC DVD encode, is the same colorimetry being used by MPC-HC to convert to RGB on playback as for a PAL DVD encode?

StvG said in the other thread I should be using rec.601_625 to convert between HD and SD etc in digital-land, and I don't doubt him, but once again I'm just after a simple explanation as to why.

Cheers.

jpsdr
17th August 2019, 02:14
Neither my dictionnary, google trad or me understand "borked"...

There is no XYZ colorspace in avisynth, so, it's tagged RGB. So, the system (avs, Windows, Video card drivers, monitor) diplays (linear) XYZ data, thinking it's non-linear RGB. Not so suprise result is odd... But basicaly, you'll see darker colors than original. Effect even worse (a lot darker) with HDR data.
If you haven't, read the pdf document i've put with the filter, i've tried to explain how things work (at least, what i've understood). ;)
Maybe it will help you.

I've put the two rec.601 because there was two in the spec, so, i made them both avaible.
After, colorimetry is not realy my best field, so, i would suggest you to follow StvG advice.

After, i'm not sure there is realy need to go through XYZ (neither Linear RGB) for 601 <-> 709. Colorimetry parameters are almost identical, this is why people always do the convertion staying in the standard non-linear space, so, just by a simple matrix translation.
After, if you want perfect accuracy...

For 2020 <-> 709/601, you need to go through XYZ, because colorimetry parameters are different, and so it's only through XYZ that you can do it. Only Linear RGB is not enough and will produce improper results. Described in R-REC-BT.2087-0-201510-I!!PDF-E.

So, it's 3 am for me, time to bed...

poisondeathray
17th August 2019, 03:24
I read your reply in the other thread and looked at the PDF, and I can see rec.601_525 line and rec.601_625 line are different, but the question I'm trying to get a simple answer to is... why do other programs such as ColorMatrix & DitherTools only have/require one version of rec.601?
I assume my understanding is wrong, but I thought once analogue PAL and NTSC are converted to digital, the colorimetry is the same, and therefore there's only one flavour of rec.601 required for colorimetry conversions. When I play an NTSC DVD encode, is the same colorimetry being used by MPC-HC to convert to RGB on playback as for a PAL DVD encode?

StvG said in the other thread I should be using rec.601_625 to convert between HD and SD etc in digital-land, and I don't doubt him, but once again I'm just after a simple explanation as to why.

Cheers.


Simple answer is convention. It's the way everyone does it


1) Matrix for bt470bg (pal, or 601-6_625), smpte170m (ntsc, or 601-6_525) are the same, 709 different
2) Transfer for bt470bg, smpte170m, and 709 are the same
3) Primaries are different for all 3, but look at footnote 2


It is recognized that a practice is now sometimes used by which, when programs produced in HDTV are
release in SDTV, their HDTV pixel map is re-mapped onto the SDTV pixel map without changing the
colorimetry of the original program.


In practice, only matrix is usually accounted for, not primaries. You see this in professional HD to SD conversions, broadcast NLE's too . Technically you should adjust for the primaries too, but it's rarely done.

ie. So technically it's a HD => SD conversion with uncorrected 709 primaries .

But you can do whatever you want - you control matrix, transfer, or primaries for source/destination with tools like zimg/zlib (resize in vapoursynth, avsresize in avisynth)

dither tools' "newer brother" fron the same author, the vapoursynth's fmtc also give you control over these

hello_hello
17th August 2019, 04:03
poisondeathray,
Thanks for the reply.
Maybe I'm being thick, but I'm still not 100% clear on this.

Even the section you quoted only refers to HD and SD colorimetry, implying SD is a single colorimetry.
The pdf appears to me to explain the method for converting analogue to digital. Below figure 2.6 it says:

Chromaticity coordinates specified are those currently used by 625-line and 525-line conventional
systems.

I doubt any of us are using 625 or 525 line displays any more, and it seems the colorimetry co-ordinates convert "from" those systems. Even if they're different in analogue form, it seems bizarre to use two formulas to convert them to different digital SD colorimetries rather than them ending up the same. If they're not intended to convert to the same colorimetry, why use different formulas?

I must be missing the obvious here, and I won't get a chance till tomorrow, but I'll do some more reading to see if I can work out what I'm missing. In the mean time though, if there's two rec.601 colorimetries in digital form, which one do programs with only a single rec.601 option normally use?

Cheers.

PS. I've had the table in the ColorMatrix help file in my head, which is one reason I'm confused about it now. To me it implies there's only a single rec.601 in digital form but maybe I've been mis-interpreting it.

This is a list of all possibilities according to the MPEG-2 specs and DGDecode.
0 forbidden
1 ITU-R BT.709
2 Unspecified Video (unknown)
3 reserved
4 FCC
5 ITU-R BT.470-2 (exactly the same as ITU-R BT.601)
6 SMPTE 170M (exactly the same as ITU-R BT.601)
7 SMPTE 240M
8-255 reserved

poisondeathray
17th August 2019, 04:40
Even the section you quoted only refers to HD and SD colorimetry, implying SD is a single colorimetry.
The pdf appears to me to explain the method for converting analogue to digital. Below figure 2.6 it says:

Chromaticity coordinates specified are those currently used by 625-line and 525-line conventional
systems.

I doubt any of us are using 625 or 525 line displays any more, and it seems the colorimetry co-ordinates convert "from" those systems. Even if they're different in analogue form, it seems bizarre to use two formulas to convert them to different digital SD colorimetries rather than them ending up the same. If they're not intended to convert to the same colorimetry, why use different formulas?



There is a 625 and 525 chart. Notice their primaries for Red, Green, Blue are different

As mentioned earlier, in practice, the primaries are not adjusted for HD to SD conversion. You ignore it

You need to define matrix, transfer , primaries when converting from something to another. Input and output. Thats 6 values in and out. It becomes more important when you have other formats used in production like linear exr , then the transfer becomes important . The HD <=> SD case is covered by by 1,2,3 in my post above. 1) matrix is used 2) Transfer is cancelled out 3) primaries are usually ignored



I must be missing the obvious here, and I won't get a chance till tomorrow, but I'll do some more reading to see if I can work out what I'm missing. In the mean time though, if there's two rec.601 colorimetries in digital form, which one do programs with only a single rec.601 option normally use?


Use in what way ?

If you mean "primaries" it's usually unspecified or ignored. But some do specify it in metadata, even if it's actually ignored in conversions. (and you can verify these things , since you have control over matrix, transfer and primaries with vapoursynth resize or fmtc, or avsresize in avisynth)



The way you test it, is take known colors and values such as colorbars, run it through your HD conversions to SD (or SD to HD if you want)

You can specify the matrix/transfer/primaries in/out .

Keep in mind - the way you or whatever program converts back to RGB is important if you are "viewing" it

Keep in mind that sometimes there are conversions done in the GPU, sometimes in the renderer

You can do this for different programs, editors, media players to check behaviour


It takes alot of time to do these tests, but I did this a while back and my findings were primaries are mostly ignored in most programs. If you corrected for primaries (709 primaries in, 601-6_625 or 601-6_525 out) the conversion looked different than the known values you started out with in HD .

The exception is vapoursynth. It reads metadata, and that metadata affects conversions. Often, you have to override the "props" or various properties if you want it to behave like other programs, very tricky if you forget (e.g. something might be flagged interlaced, though progressive content, like a PAL DVD, but vapoursynth will treat it interlaced for all operations unless you override the props)






PS. I've had the table in the ColorMatrix help file in my head, which is one reason I'm confused about it now. To me it implies there's only a single rec.601 in digital form but maybe I've been mis-interpreting it.



That Colormatrix table you posted only specifies matrix, not the transfer or primaries.

The matrix values for 601-6_525 and 601-6_625 end up being the same - KR = 0.299; KB = 0.114 . But 709 is different. That's why we use matrix=blah when doing those conversions HD<=>SD conversions . But no matrix conversion between "PAL" and "NTSC" because they are the same

Better tables are in the more modern Rec. ITU-T H.265 standards document, which include 2020 and a bunch others along with their values and equations

E3 Color Primaries
E4 Transfer Characteristics
E5 Matrix Coefficients

Common tools like popular media players, only use matrix when converting back to RGB for display. The primaries are are not accounted for. You will get different colors than expected if you start adjusting primaries in that HD to SD or SD to HD case. Same with video editors and other tools

hello_hello
18th August 2019, 20:46
poisondeathray,
Thanks for the info. I also did some more reading and I think I'm now closer to an understanding.

First we have this table showing the difference between NTSC and PAL color primaries (from Wikipedia).

RGB color space parameters for Rec. 601 Color space White point (D65) Primary color
xW yW xR yR xG yG xB yB
625 line 0.3127 0.3290 0.640 0.330 0.290 0.600 0.150 0.060
525 line 0.3127 0.3290 0.630 0.340 0.310 0.595 0.155 0.070

Which I compared with the pic below showing how they correspond to RGB. Now I properly understand what those numbers mean.
Red and blue for NTSC and PAL are so close they can probably be considered the same, while green is a little different. For Rec.709 the red and blue primaries are exactly the same as 625 line Rec.601, while green is roughly halfway between the two Rec.601 versions.

https://www.image-engineering.de/content/library/technotes/2012_06_16/xy-Locus.jpg

Maybe now I understand why I've seen PAL DVDs that appear to have a slight green tinge. I assume they were encoded using NTSC primaries, or something....
I posted an example of that (https://forum.videohelp.com/threads/379383-QTGMC-with-interlaced-PAL#post2452886) during a discussion quite a while back.

Transfer Characteristics = gamma, which is the same for rec.601 and rec.709.

Color Matrix is the formula for converting YUV back to RGB (or more correctly converting YCbCr to RGB).
From what I understand now, there's only one formula for each, but there's constant(s) in each formula that are different for 525 line, 625 line (and rec.709) to account for the different primaries. If the wrong "constants" are used you don't convert back to exactly the same RGB you started with. Is that a correct assumption?

So the formula for converting between the rec.601 and rec.709 matrices is a standard formula used by most programs, that should take into account the different "constants" for red, blue and green, but doesn't because that makes stuff-all difference compared to using the wrong matrix, and I assume in many cases the original RGB primaries might be unknown anyway. I think I finally understand what "ignoring the primaries" means....

I assume HDRTools does account for those primaries... hence the two flavours of rec.601.... so to be technically accurate, assuming I'm encoding with x264 for example, if I converted HD to SD using the rec.601_625 formula, I should specify bt470bg for the color primaries and for the color matrix (rather than rec.709 for primaries and bt470bg for matrix), and if I'm upscaling from PAL to HD it'd be bt709 for the primaries and matrix (rather than bt470bg and rec.709)? Not that I've bothered setting the color primaries for a long time, just the matrix.

How am I doing?

Thanks again!

hello_hello
18th August 2019, 21:32
Neither my dictionnary, google trad or me understand "borked"...

There is no XYZ colorspace in avisynth, so, it's tagged RGB. So, the system (avs, Windows, Video card drivers, monitor) diplays (linear) XYZ data, thinking it's non-linear RGB. Not so suprise result is odd... But basicaly, you'll see darker colors than original. Effect even worse (a lot darker) with HDR data.
If you haven't, read the pdf document i've put with the filter, i've tried to explain how things work (at least, what i've understood). ;)
Maybe it will help you.

"Borked" effectively means "broken". It's probably slang.
These definitions (https://www.urbandictionary.com/define.php?term=borked) possibly come across as being somewhat insulting, but that definitely wasn't my intention.

What I'm failing to understand (I seem to be doing a bit of that lately) is how the intermittent XYZ colorspace matters when I shouldn't be seeing it. The screenshots were taken from the output of a script using this (2020 to 601).

ConvertYUVtoXYZ(Color=1).ConvertXYZtoYUV(Color=3, pColor=1, OutputMode=2)

Shouldn't I be seeing a fairly similar result to this (the expected result)?

ConvertYUVtoLinearRGB(Color=1).ConvertLinearRGBtoYUV(Color=3, OutputMode=2)

Thanks.

poisondeathray
19th August 2019, 00:10
First we have this table showing the difference between NTSC and PAL color primaries (from Wikipedia).


A quick glance and it appears those values are different than the official specs, not sure what's up with that . I think the ones in wikipedia are older, I think it was revised again later. I'd probably trust the official ITU document - that's what zimg/zlib uses and I'm pretty sure jpsdr goes by it too. Anyways, the point is they have different primaries.


Color Matrix is the formula for converting YUV back to RGB (or more correctly converting YCbCr to RGB).
From what I understand now, there's only one formula for each, but there's constant(s) in each formula that are different for 525 line, 625 line (and rec.709) to account for the different primaries. If the wrong "constants" are used you don't convert back to exactly the same RGB you started with. Is that a correct assumption?

So the formula for converting between the rec.601 and rec.709 matrices is a standard formula used by most programs, that should take into account the different "constants" for red, blue and green, but doesn't because that makes stuff-all difference compared to using the wrong matrix, and I assume in many cases the original RGB primaries might be unknown anyway. I think I finally understand what "ignoring the primaries" means....



Yes, if you use the wrong assumption or value you get different colors than expected. Remember - 6 values total - for matrix, transfer, primaries. Input and output . Transfer cancels out for both 601(525 and 625) and 709 . Primaries are usually ignored for the 709/601 case (input and output are calculated as "unspecified" so there is no net effect of primaries) . So the only thing that affects the conversion is matrix in most software for the 709/601 case




I assume HDRTools does account for those primaries... hence the two flavours of rec.601.... so to be technically accurate, assuming I'm encoding with x264 for example, if I converted HD to SD using the rec.601_625 formula, I should specify bt470bg for the color primaries and for the color matrix (rather than rec.709 for primaries and bt470bg for matrix), and if I'm upscaling from PAL to HD it'd be bt709 for the primaries and matrix (rather than bt470bg and rec.709)? Not that I've bothered setting the color primaries for a long time, just the matrix.



I'm not sure what it does; I haven't really used it much. But if it accounts for the primaries difference (ie. primaries_input was 709, primaries_output is 601_625) - you'll usually get shifted colors in typical programs, because when they convert back to RGB for display, they usually only use the matrix the way most people have programs configured.

Note that in x264, those --colorprim xxx --transfer xxx --colormatrix xxx switches are just VUI metadata. They don't actually do anything. It's up to the other recieving software how it's handled . Some pay attention to that metadata. e.g vapoursynth. So if you do that actual primaries adjustment, and flag it accordingly, you end up getting the expected colors.

StvG
19th August 2019, 06:40
A quick glance and it appears those values are different than the official specs, not sure what's up with that . I think the ones in wikipedia are older, I think it was revised again later. I'd probably trust the official ITU document - that's what zimg/zlib uses and I'm pretty sure jpsdr goes by it too. Anyways, the point is they have different primaries.

zimg uses those values from wikipedia - https://github.com/sekrit-twc/zimg/blob/master/src/zimg/colorspace/colorspace_param.h#L28 REC_470_BG (625 lines) and SMPTE_C (525 lines/170m/240m).

Edit: I'm not sure what it does; I haven't really used it much. But if it accounts for the primaries difference (ie. primaries_input was 709, primaries_output is 601_625) - you'll usually get shifted colors in typical programs, because when they convert back to RGB for display, they usually only use the matrix the way most people have programs configured.

It seems that behavior is only when XYZ is used for 709<->601 (or 2020)? Using LinearRGB for those conversions doesn't touch primaries?

jpsdr
19th August 2019, 09:29
ConvertYUVtoXYZ(Color=1).ConvertXYZtoYUV(Color=3, pColor=1, OutputMode=2)
Shouldn't I be seeing a fairly similar result to this (the expected result)?
ConvertYUVtoLinearRGB(Color=1).ConvertLinearRGBtoYUV(Color=3, OutputMode=2)
Thanks.
No, because 2020 has significant primary colors differences than 709/601.
So, when going through XYZ, you adjust primary colors, you don't when going only through linear RGB, as linear RGB integrate the primary colors of the sensor. And primary colors are different enough to produce a noticeable different result.

According R-REC-BT.2087 the proper way is through XYZ for 2020 <-> 709.

As i describe in my pdf doc, you have for SDR :
[Scene] => [Camera sensor] => [Linear RGB] -> (Gama or OETF) -> [Non Linear RGB] -> (matrix) -> [YCbCr]

The primary colors are in the [Camera sensor], so, it's only on this step that 525/625 lines has effect, not in the (matrix).
Is my PDF provided with the tools so unclear ? I hoped it was clear enough to explain things, but unfortunately it seems not... :(

(R,G,B) 2020 : (0.708,0.292) (0.170,0.797) (0.131,0.046)
(R,G,B) 709 : (0.640,0.330) (0.300,0.600) (0.150,0.060)
(R,G,B) 601/625 : (0.640,0.330) (0.290,0.600) (0.150,0.060)
(R,G,B) 601/525 : (0.640,0.330) (0.310,0.595) (0.155,0.070)

Values for 709/601 even if not identicals, are close enough to assume that only doing the [Non Linear RGB] <-> (matrix) <-> [YCbCr] is enough.
OETF is identical for 2020 and 709, so, going to Linear RGB, or staying at non-linear RGB will produce the same result.

hello_hello
19th August 2019, 11:35
Is my PDF provided with the tools so unclear ? I hoped it was clear enough to explain things, but unfortunately it seems not... :(

I read the pdf and took some of it in, but ultimately I copied and pasted the example in your help file and expected the result to be what the help file said it'd be.

LOL. I used the PHP button instead of the Code button, but why not... it looks a bit pretty. :)

Some example use
================

BT.2020 to BT.709 conversion, do the following:
ConvertYUVtoXYZ(Color=1)
ConvertXYZtoYUV(pColor=1)

Had this been the example, I wouldn't have wandered so far off the main path (I assume it's correct given it appears to produce the same result as a DitherTools 2020 to 709 conversion).

ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(pColor=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

Intuitively, and aided by the help file example, the Color and pColor options appear to be an automatic way of specifying the correct primaries, and to be honest, the one thing that's allowing me to not feel like a complete idiot just yet, is this topic has been discussed in two threads over several days now and I've posted examples in both, and so far nobody else has said "no, you do it like this". That's a lot of typing every time you want to do a rec.2020 conversion. ;)

Now back to reading Mr. Help File again to see if I can discover what "color mode of the data" means as I'm not clear on that now. :(
Does "color mode of the data" mean "matrix"?

** ConvertYUVtoLinearRGB **
Color -
Set the color mode of the data.
0: BT2100
1: BT2020
2: BT709
3: BT601_525
4: BT601_625

Oh well, at least I appear to be making some progress now.
Thanks for your help.

jpsdr
19th August 2019, 11:50
Something is wrong here :

ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(pColor=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

You put the exact same colorimetry in both, meaning for the XYZ to Linear convertion in ConvertXYZtoYUV, meaning you've said : Color is 709 (default value 2 of Color), but colorimetry parameters are those of 2020.
I think it will produce the same result as

ConvertYUVtoLinearRGB(Color=1).ConvertLinearRGBtoYUV()

pColor is juste used to define the Min/Max(ZYZ) value in 8-16 bits modes (warning page 3 of pdf). It has no other effect.
I think i'll have to update the doc of the plugin, because it's clearly obvious that i didn't explain properly the effect of the "p"(previous) parameters, and people misunderstand the purpose of it.

hello_hello
19th August 2019, 12:21
Something is wrong here :

ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(pColor=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

You put the exact same colorimetry in both, meaning for the XYZ to Linear convertion in ConvertXYZtoYUV, meaning you've said : Color is 709 (default value 2 of Color), but colorimetry parameters are those of 2020.

Sorry, I did a silly. I'll try again and report back.

hello_hello
19th August 2019, 13:16
Okay... time to accept that fact I'm just too stupid to use this program.....
I don't mind being an idiot. It's just frustrating when you're smart enough to know you're idiot. I'm off to drink alcohol until I'm too stupid to know...

This was my previous silly. Is it some sort of mathematical co-incidence it produces the same result as a DitherTools rec.2020 to 709 conversion (which is why I thought I finally had it right)?

Silly
ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(pColor=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

https://i.ibb.co/NTDdWjh/Me-Silly.png (https://ibb.co/NTDdWjh)

2020 - 601

ConvertToYV24()
Dither_convert_yuv_to_rgb(matrix="2020", slice=false)
Dither_convert_rgb_to_yuv(matrix="601", output="YV12")
ConvertToYV12()

https://i.ibb.co/nsMScmp/DT-2020-601.png (https://ibb.co/nsMScmp)

ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(Color=4, pColor=1, Rx=0.640,Ry=0.330,Gx=0.290,Gy=0.600,Bx=0.150,By=0.060,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

https://i.ibb.co/k8HdtmX/xyz-2020-601.png (https://ibb.co/k8HdtmX)

2020-709

ConvertToYV24()
Dither_convert_yuv_to_rgb(matrix="2020", slice=false)
Dither_convert_rgb_to_yuv(matrix="709", output="YV12")
ConvertToYV12()

https://i.ibb.co/wwyYQKB/DT-2020-709.png (https://ibb.co/wwyYQKB)

ConvertToYV24()
ConvertYUVtoXYZ(Color=1, Rx=0.708,Ry=0.292,Gx=0.170,Gy=0.797,Bx=0.131,By=0.046,Wx=0.3127,Wy=0.3290)
ConvertXYZtoYUV(Color=2, pColor=1, Rx=0.640,Ry=0.330,Gx=0.300,Gy=0.600,Bx=0.150,By=0.060,Wx=0.3127,Wy=0.3290)
ConvertToYV12()

https://i.ibb.co/QDHZPBb/xyz-2020-709.png (https://ibb.co/QDHZPBb)

jpsdr
19th August 2019, 14:03
No needs to set the colorimetry parameters if it's for setting the same value that are in the according rec.
As you can see, "silly" provide the same result than dither.
It means that dither is only doing a matrix convertion, and doesn't change the colorimetry parameters.
As they, in final, do only simple matrix convertion, these 3 should produce the same result (pinterf added rec2020 recently) :
"silly"

ConvertToRGB(matrix="Rec2020")
ConvertToYV12(matrix="Rec709")


ConvertYUVToLinearRGB(Color=1)
ConvertLinearRGBToYUV()


I don't know dither_tools, but it seems it's doing only matrix convertion. Going through XYZ is doing also Colorimetry convertion.
I don't see any issue or surprise with these results.
What is exactly your issue ?
If it's difference between dither and ConvertXYZ, it's expected, as dither is only doing matrix convertion.

hello_hello
19th August 2019, 14:30
What is exactly your issue ?
If it's difference between dither and ConvertXYZ, it's expected, as dither is only doing matrix convertion.

My only issue was expecting that when I do the same color conversion with programs X, Y & Z (pun intended), the result should be the same. I'm not sure that's unexpected. ;)

Even when using the same program, I don't think many people would expect completely different results from the same kind of conversion. ie XYZtoYUV vs LinearRGBtoYUV.
Don't get me wrong, I finally understand why they're so different.

So rec.2020 conversions with DitherTools are effectively wrong?

As a side question, do you know how the average TV handles rec.2020? Amongst all the reading I did yesterday I stumbled on some posts in another forum somewhere, and they were discussing how at the moment the rec.2020 colorspace is something of a "future proof" colorspace, in that no TVs today are capable of displaying much more than the rec.709 range of colors. If that's true, I guess I'm asking if I upscale a HD video to UHD and convert the colors, for it to display correctly in an UHD TV's media player, should I be using the "matrix only" method or do it "properly" with the XYZ method. I don't have a UHD TV so I have no idea, but it seems silly to be up-converting the colors with a "matrix only" method if it won't display correctly.

Edit: It also makes me wonder what the point of ConvertToRGB(matrix="Rec2020") would be if it's only doing a matrix conversion which is technically wrong.

Just trying to get this whole thing straight in my head.

Cheers.

jpsdr
19th August 2019, 15:39
ConvertToRGB(matrix="Rec2020") is not technicaly wrong, you have RGB, but with colorimetry of BT.2020.
After, if you made all your process in RGB, and finalise with
ConvertToYV12(matrix="Rec2020"), you have nothing wrong.
(According of course your input is YUV BT.2020).

What is technicaly wrong, according R-REC-BT.2087 it's that :
ConvertToRGB(matrix="Rec2020")
ConvertToYV12(matrix="Rec709")
This also apply to dither_tools, so, also, they are not wrong.
While you stay within the same colorimetry space (all your data and your video are on the same colorimtry space), nothing is wrong with only matrix.

But when you have different colorimetry spaces :
- Either you convert everyone to the same colorimetry if you're working with datas affected by colorimetry space (or are inside a colorimetry space) (RGB, YUV).
- Either you work with datas which are unafected (or make abstraction or are outside a colorimetry space) by colorimetry (XYZ and probably others i don't know).

According your question :

If that's true, I guess I'm asking if I upscale a HD video to UHD and convert the colors, for it to display correctly in an UHD TV's media player, should I be using the "matrix only" method or do it "properly" with the XYZ method.


I must said that i have no knowledge of broadcast or professional environment, and i'm sorry, but i don't know what to answer.
Just that, personnaly, i would follow the R-REC-BT.2087, so with XYZ method, which should, theoricaly, be the proper way.

Unfortunately, this is not helping the mess.

In practice, only matrix is usually accounted for, not primaries. You see this in professional HD to SD conversions, broadcast NLE's too . Technically you should adjust for the primaries too, but it's rarely done.

poisondeathray
19th August 2019, 15:55
zimg uses those values from wikipedia - https://github.com/sekrit-twc/zimg/blob/master/src/zimg/colorspace/colorspace_param.h#L28 REC_470_BG (625 lines) and SMPTE_C (525 lines/170m/240m).


My bad; I got confused by hello_hello's chart reproduction . The headings are shifted in his post

They are aligned here
https://en.wikipedia.org/wiki/Rec._601#Primary_chromaticities

And they match the ITU HEVC document and wikipedia, so false alarm







In practice, only matrix is usually accounted for, not primaries. You see this in professional HD to SD conversions, broadcast NLE's too . Technically you should adjust for the primaries too, but it's rarely done.


Unfortunately, this is not helping the mess.




Primaries aren't usually adjusted for in the 709/601 case, or you get shifted colors . The underlying premise is you should get the same colors in HD as SD when viewing

I verified this with a bunch of things, software players, NLE's, professional tools, hardware players - DVD, BD, both authored discs connected to TV , and as files, devices phones, set top media players . Also retail discs (BD and the DVD from the same studio; the same "movie" but released by different studio can have different colors), and TV broadcasts . It's entirely possible that I messed up some observations or made a mistake somewhere, but the findings are 99.9% consistent - really only the matrix is used in practice.

Note I didn't check 2020 or UHD equipment for this - it has to be rechecked

jpsdr
19th August 2019, 16:44
For 709<->601 i understand primaries are not adjusted, values are close enough to consider not necessary, and indeed, "everyone" does only matrix convertion, me also.
I though your comment was for 2020 <->709/601. Apparently i was wrong. So, for now, according the informations i have, my answer for 2020 <-> 709 is to adjust primaries.

hello_hello
19th August 2019, 18:11
Thanks jpsdr and everyone else for the answers and the help.

I think I have something approaching an understanding now.

Thanks again.

jpsdr
16th September 2019, 08:42
New version, see first post.

FranceBB
16th September 2019, 09:28
New version, see first post.

Thank you!

Crosstalk -
Coeff for the crosstalk R,G,B matrix (for Method C of BT2446). Value 0.0 to 0.33.
Will apply a crosstalk matrix on RGB before XYZ matrix convertion.
Avoid value over 0.3 in 8 bits mode. 0.0 means no crosstalk between R,G,B.

Very useful! :D
I'm gonna post the link here to the relative documentation so that others can see what this is for: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2446-2019-PDF-E.pdf (go to page 19 if you are curious).

In particular, the crosstalk matrix is applied such that saturations of linear signals are reduced to achromatic to avoid hue changes caused by clipping of compressed highlight parts.

jpsdr
22nd September 2019, 10:22
Does anyone know where i can get some kind of "reference" video in HLG mode at 1000 cd/mē ?

FranceBB
22nd September 2019, 16:15
Does anyone know where i can get some kind of "reference" video in HLG mode at 1000 cd/mē ?

You mean a sample?
Can you send me your email in PM? I could set up an FTP account for you and send you a tiny chunks original of our productions but of course you don't have to share it with anyone for whatever reason.

hello_hello
19th October 2019, 07:53
Could somebody please show me how to do a simple color conversion with HDRTools, minus the banding extravaganza?
The source is blocky and on the edge of banding already, so it makes the problem hard to miss.

Spline36Resize(1280,720)
https://i.postimg.cc/64psxdnG/upscale-only.png (https://postimg.cc/64psxdnG)

ConvertToYV24().ConvertYUVtoXYZ(Color=3).ConvertXYZtoYUV(Color=2, PColor=3).ConvertToYV12()
Spline36Resize(1280,720)
https://i.postimg.cc/G4sWR38z/colorconvert.png (https://postimg.cc/G4sWR38z)

source.mkv (https://ufile.io/h3sswnxx) (382kB)

Thanks.

jpsdr
19th October 2019, 10:36
For simple REC601 to REC709 no need to use HDRTools, the simple integrated avs functions are enough.
Otherwise, this is the proper script line.
Maybe you can try to add Output=1 in ConvertYUVtoXYZ, or, convert to 16 bits before ConvertYUVtoXYZ (and after convert down to 8 bits).

hello_hello
21st October 2019, 07:27
For simple REC601 to REC709 no need to use HDRTools, the simple integrated avs functions are enough.
Otherwise, this is the proper script line.
Maybe you can try to add Output=1 in ConvertYUVtoXYZ, or, convert to 16 bits before ConvertYUVtoXYZ (and after convert down to 8 bits).

I'll confess I don't understand why it's such a disaster in 8 bit. A 601 to 2020 conversion is the same (just as a test).

If there is a problem it must be the conversion from XYZ to YUV, because when the input is 8 bit, OutputMode=1 produces a fairly similar result to converting to 16 bit first. I used Tweak(Bright=25) after the conversion to make things easier to see.

Cheers.

ConvertToYV24()
ConvertYUVtoXYZ(Color=4)
ConvertXYZtoYUV(Color=1, PColor=4)
ConvertToYV12()
https://i.postimg.cc/8JwDVzjj/8.png (https://postimg.cc/8JwDVzjj)

ConvertToYV24()
ConvertYUVtoXYZ(Color=4, OutputMode=1)
ConvertXYZtoYUV(Color=1, PColor=4)
ConvertBits(8)
ConvertToYV12()
https://i.postimg.cc/hJLcprn8/1.png (https://postimg.cc/hJLcprn8)

ConvertToYUV444()
ConvertBits(16)
ConvertYUVtoXYZ(Color=4)
ConvertXYZtoYUV(Color=1, PColor=4)
ConvertBits(8)
ConvertToYV12()
https://i.postimg.cc/5jn9hnCn/16.png (https://postimg.cc/5jn9hnCn)

jpsdr
21st October 2019, 09:12
You have a resolution loss because of the non-linear to linear (and back after) transfert function.
Basicaly, with 8 bit, if you have something like this.
(YUV) 0 -> 0 (XYZ)
(YUV) 1 -> 0 (XYZ)
(YUV) 2 -> 1 (XYZ)
(YUV) 3 -> 1 (XYZ)
(YUV) 4 -> 1 (XYZ)
(YUV) 5 -> 2 (XYZ)
....
When you convert back XYZ to YUV, you'll have
(XYZ) 0 -> 0 (YUV)
(XYZ) 1 -> 4 (YUV)
etc...
You loose (1,2,3). Nothing can't be done, except... increase the output (XYZ here) bitdepth, to keep 8 bit resolution for the input (YUV here). But if you stay in 8 bits for all the process, you'll loose resolution, and have less than 8 bit in final result.

And effect is even worse with HDR.

hello_hello
21st October 2019, 14:20
Ahhhh.... I get it now.

Would it be a good idea for HDRTools to automatically convert to 16 bit for the conversion process and then convert back to 8 bit if required?
I guess it'd break compatibility with Avisynth 2.6, but that's probably better than "bad" conversions.

Thinking about it, DitherTools does a similar thing, only using the legacy stacked 16 bit format. I'm not suggesting you should support that, but I think it'd be better to make Avisynth+ a requirement for HDRTools than for it to appear to be doing crappy color conversions for 8 bit video. Just a thought...

Thanks.

jpsdr
21st October 2019, 19:23
I'd rather keep actual status, allowing avs 2.6 to use it, but i'll had more warning in the readme (hope i'll dont forget) on next release.

jpsdr
15th December 2019, 00:29
New version (see first post), add BT2446 A and C methods for HDR to SDR.

I didn't optimize the A method because, honestly, results are bad. Maybe i didn't understood properly the method/formula or there is something wrong in my code, but i've checked and re-checked a lot of times without finding anything wrong.

The C method provide on the other hand interesting results. For those who made experiments, i suggest to first play with the "normal" adjustable parameters Crosstalk and Whiteshift, before playing with the others parameters, like pct white/skintone and others i've made avaible and adjustable, but not 100% sure they were intended to be.

If you want to use it, reading BT2446 is... mandatory if you want to understand how things works and are related to.

Atak_Snajpera
22nd December 2019, 20:37
I can't figure out why i'm getting that nasty banding and harsh cut-off in dark colors.

mediainfo
Video
ID : 1
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5.1@High
HDR format : SMPTE ST 2086, HDR10 compatible
Codec ID : V_MPEGH/ISO/HEVC
Duration : 10 min 0 s
Bit rate : 43.2 Mb/s
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0 (Type 2)
Bit depth : 10 bits
Bits/(Pixel*Frame) : 0.217
Stream size : 3.02 GiB (86%)
Writing library : ATEME Titan File 3.9.0 (4.9.0.0)
Default : Yes
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Mastering display color primaries : Display P3
Mastering display luminance : min: 0.0000 cd/m2, max: 1000 cd/m2


video=ConvertYUVtoXYZ(video,Color=0,HDRMode=0,OOTF=false,Crosstalk=0.0,threads=1)
video=ConverXYZ_BT2446_C_HDRtoSDR(video,PQMode=true,Lhdr=30000.0,Lsdr=100.0,pColor=0,threads=1)
video=ConvertXYZtoYUV(video,Color=2,pColor=0,OOTF=false,Crosstalk=0.0,threads=1)
https://i.postimg.cc/xC8fmXQp/job2-preview-avs-snapshot-05-00-2019-12-22-20-09-14.png

for comparison DGHable
video=z_ConvertFormat(video,pixel_type="RGBPS",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:l", dither_type="none").DGHable(exposure=1.0)
video=z_ConvertFormat(video,pixel_type="YV12",colorspace_op="rgb:linear:2020:l=>709:709:709:l",dither_type="ordered")

https://i.postimg.cc/G3ZDcCJn/job2-preview-avs-snapshot-05-00-2019-12-22-20-08-38.png

BTW ConvertXYZ_Hable_HDRtoSDR and others have the same problem.
https://i.postimg.cc/WtLTxSkx/Convert-XYZ-Hable-HDRto-SDR-exposure-x8.png

DGHable
https://i.postimg.cc/tR1PQT6z/DGHable.png

quietvoid
22nd December 2019, 21:35
Looks like the same issue I came across at the very beginning: https://github.com/jpsdr/HDRTools/issues/1
Might have to rearrange to use LinearRGB instead of XYZ though. Or just add OutputMode=2 in the ConvertYUVtoXYZ() call

jpsdr
23rd December 2019, 10:31
Lhdr=30000.0 ???????? According your mediainfo it should be 1000.0. Max is 10000 anyway.
Same advice, add OutputMode=2 to ConvertYUVtoXYZ(), didn't expect 16 bit workflow still produce resolution loss.

Before adding OutputMode=2, for experiment, add Convertbits(16) before ConvertYUVtoXYZ(). I don't know if your source filter provide 10 or 16 bits data, and even if it provides 10 bits data it shouldn't change things, but, if there is something i've missed, it will show it.

Atak_Snajpera
23rd December 2019, 10:37
Lhdr=30000.0 ???????? According your mediainfo it should be 1000.0. Max is 10000 anyway.

With lower value image is totally overexposed!

jpsdr
23rd December 2019, 10:46
In that case, i think it's with others parameters you should first play/adjust (crosstalk,whiteshift, pct values), instead of putting a parameter totaly out of range/spec, but... Afterall, if it produces results you like.

I've edited my other post.

Atak_Snajpera
23rd December 2019, 10:50
Here how frame looks with value=1000
https://i.postimg.cc/Mp132qBH/job2-preview-avs-snapshot-05-00-2019-12-23-10-48-47.png

Before adding OutputMode=2, for experiment, add Convertbits(16)
No difference. Btw. I'm using l-smash as decoder + latest avisynth+ and video is detected as YUV420p10.

UPDATE: Only outputmode=2 fixes this issue.

jpsdr
23rd December 2019, 10:57
If no difference, at least, it means there is "no error". I didn't expect resolution loss at 16 bits... :(
In that case, add OutputMode=2 to ConvertYUVtoZXY().
You shouldn't have resolution loss in that case.

Atak_Snajpera
23rd December 2019, 13:49
Has anybode managed to emulate madvr look using this plugin?

sample -> https://4kmedia.org/sony-camping-in-nature-4k-demo/
No matter which method I use I get either opaque white or oversaturated 4k logo

reference from madvr
https://i.postimg.cc/DZnqZXYt/a-madvr.png

BT2446 30000 (BTW. WhiteShift does nothing)
https://i.postimg.cc/Vv792kg2/a-bt2446-30000.png

Reinhard exposure=12
https://i.postimg.cc/1Xzw0ZSB/a-reinhard12.png

Mobius exposure=15
https://i.postimg.cc/sXm5Zgk1/a-mobius15.png

Atak_Snajpera
23rd December 2019, 15:20
Ok. Mission accomplished! I've managed to emulate madvr tonemapping almost perfectly. Logo however is still slightly oversaturated. Sky gradient is also slightly different.

Emulated using Bt2446
video=ConvertYUVtoXYZ(video,Color=0,HDRMode=0,OOTF=false,OutputMode=2,Crosstalk=0.0,threads=1)
video=ConverXYZ_BT2446_C_HDRtoSDR(video,PQMode=true,Lhdr=50000.0,Lsdr=100.0,pColor=0,pct_ref=0.6,pct_ip=0.6,pct_wp=1.0,pct_sdr_skin=1.0,pct_hdr_skin=0.44,threads=1)
video=ConvertXYZtoYUV(video,Color=2,pColor=0,OOTF=false,Crosstalk=0.0,threads=1)
https://i.postimg.cc/MHBSmQrt/a-bt2446-50000-044-06-06-1-1.png

MadVR
https://i.postimg.cc/DZnqZXYt/a-madvr.png


I have also noticed that emulated method gives more realistic sky color than madvr's tonemapping
emulated
https://i.postimg.cc/05Gf4QRB/Samsung-Wonderland-Demo-ts-snapshot-01-19-944-emulated.png

Madvr
https://i.postimg.cc/KYdN638d/Samsung-Wonderland-Demo-ts-snapshot-01-19-944.png

r4dius
29th December 2019, 01:21
Hi, I've looking for ways to get hdr to sdr done right but still can't find how .. I'd like to get the hdr converted footage to match the existing sdr version but there's always a mismatch,
when bright colors look ok then dark stuff looks way darker and vice versa, madvr and mpv tonemapping look good but there's no method to export their tonemapped output as I understand it,
the only way I found is to exporting frame by frame (with command line options) with mpv but this thing will take ages, so I was wandering would there be a way to use the hdrtools tools to match the mpv output ?
I mean a reproducible way that would always produce the same result (or close to it) as mpv ?

FranceBB
29th December 2019, 01:39
Hi, I've looking for ways to get hdr to sdr done right but still can't find how .. I'd like to get the hdr converted footage to match the existing sdr version but there's always a mismatch

Of course there is! Movies are shot in log and then graded from the raw masterfile to either SDR BT709 or HDR PQ BT2100, so there's always going to be a mismatch as you will be starting from the graded HDR version whereas the SDR bluray disk were made from the original log footage. Anyway, with HDRTools you can use tonemapping algorithms which can give you pretty good results. The one that has always been working for me as a good compromise is Reinhard so you may wanna check it out from my previous posts.
Also please read the documentation and the PDF wrote by Jean-Philippe included in the plugin download which are gonna explain how this plugin works and what it does.




Totally unrelated:

Question for Jean-Philippe: is it different from the last build you sent me via email? 'cause if it isn't, I'm gonna share the images of the last test results, otherwise I'm gonna repeat those tests.

jpsdr
29th December 2019, 12:32
The difference is the implementation of the whiteshift, which wasn't in the version i've send you for pre-test. So, it's different in this way, but, in what was allready implemented, as far i remember there is no change.

r4dius
30th December 2019, 02:02
Of course there is! Movies are shot in log and then graded from the raw masterfile to either SDR BT709 or HDR PQ BT2100, so there's always going to be a mismatch as you will be starting from the graded HDR version whereas the SDR bluray disk were made from the original log footage. Anyway, with HDRTools you can use tonemapping algorithms which can give you pretty good results. The one that has always been working for me as a good compromise is Reinhard so you may wanna check it out from my previous posts.
Also please read the documentation and the PDF wrote by Jean-Philippe included in the plugin download which are gonna explain how this plugin works and what it does.




Totally unrelated:

Question for Jean-Philippe: is it different from the last build you sent me via email? 'cause if it isn't, I'm gonna share the images of the last test results, otherwise I'm gonna repeat those tests.

Merci, I've been testing a bit with your examples on this post, it's getting better but cant seem to find a perfect match yet, I'll be testing some more,
still I wonder is it not possible to extract the required values used from let's say mpv, as its result looks really good for me, and reuse them on the hdrtools ?
I mean such thing would allow more than easy conversion rather than hand picking values for each movie.

-QfG-
8th January 2020, 12:12
A little Test of Tonemapping from me. HDRTools is better then DGTonemap (both curves), the new ripbot x264 have good standard settings in the script. A few pictures from me, but i think DGHDRtoSDR is still the best tonemapper of Avisynth base (the best choice for me is Blackmagic DaVinci Resolve for tonemapping, via ACES). Also you con minimize the "Black Crush" Problems, if you set "fullrange=true" in the ConvertYUVtoXYZ Line.

madVR 100 Nits:
https://s19.directupload.net/images/200108/zrca7z7a.png

madVR 150 Nits:
https://s19.directupload.net/images/200108/3ykxxejb.png

madVR 200 Nits:
https://s19.directupload.net/images/200108/hjez7x52.png

HDRTools Ripbot Settings:
https://s19.directupload.net/images/200108/qqaypbaf.png

HDRTools (QfG Settings ~100 Nits):
https://s19.directupload.net/images/200108/cvvcm3l8.png

DGHDRtoSDR (QfG Setting ~100 Nits)
https://s19.directupload.net/images/200108/a3gixlys.png

DGTonemap (Hable Curve Untouched ~ 100 Nits)
https://s19.directupload.net/images/200108/9ertrccy.png

*The pictures are from a 4K HDR Upscale from me from Star Wars VII

** I Miss the spoiler function here :scared:

jpsdr
29th April 2020, 00:07
New version, see first post.

hellgauss
15th May 2020, 00:11
Thank you for this tool, I used your first example to convert BT.2020 to BT.709, with nice results.

I have some questions

Consider a video with these parameters from mediainfo

Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Mastering display color pri : R: x=0.680000 y=0.320000, G: x=0.265000 y=0.690000, B: x=0.150000 y=0.060000, White point: x=0.312700 y=0.329000
Mastering display luminance : min: 0.0050 cd/m2, max: 4000.0000 cd/m2

From what I understand, when using ConvertYUVto***, I should set Color=1, HDRMode=0. Mastering d. color is the default one.

1) How matrix coefficients enters in the conversion? Is it important?

2) How mastering display luminance is handled in HDRmode=PQ? It seems that these value can be set only in HLG. According to https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-3-2017-PDF-E.pdf the EETF function should enter in the process?

3) I'm trying to understand how the maxcll and maxfall parameters can be calculated. In https://www.smpte.org/sites/default/files/Study%20Group%20On%20High-Dynamic-Range-HDR-Ecosystem.pdf , pag 44, the "linear values (R,G,B)calibrated to cd/m2" are the values from ConvertYUVToLinearRGB() without OOTF-1 (i.e. linear displayed data)? Has EETF any role here?

Thanks
HG

jpsdr
15th May 2020, 17:20
No, you're PQ => HDR => BT.2100 => color=0. In the doc, it's said that HDRMode has effect only if color=0.
From what i've understood, you have BT2020, which is SDR, and you have BT2100, which is HDR version of BT2020.
So if "Transfer characteristics" is PQ or HLG => HDR => BT2100.
I suggest you to read the ColorConversion.pdf i've provided, which explain the path and what formulas/computation this plugin uses.

1)
Matrix coefficients are the one used to convert RGB to XYZ, they are more than important, it's them which defined the convertion matrix. Any change will change the output result.

2)
In PQ, mastering display luminance is not used, as it's always 1=10000.
I didn't implement any EETF function. This is very specific and used only for a display device when it wants to display a value wich is out of his range, from what i've understood. It's not a processing step i've implemented, and for now, didn't intend to.
If i implement it one day, it will be more in an external function (and not in an inside step of a ConvertXXXtoYYY) like the HDRtoSDR functions, because in a way, it's doing something similar.

3)
As there is not the keyword displayed (it says "linear values" and not "linear displayed values"), so from my point of view, they are the (Rs,Gs,Bs) i talk in my pdf, and not (Rd,Gd,Bb), but honestly, i'm not 100% sure.
But it's a value in cd/mē, so if it's PQ, just multiply by 10000, but if it's HLG, you have to know the mastering level.

Boulder
24th May 2020, 09:56
I'm currently experimenting with downscaling HDR sources, otherwise keeping the HDR characteristics intact. I've understood from the x265 thread that processing should be done in linear light if possible.

Is this the proper way of doing things?
ConvertYUVtoLinearRGB(color=0, outputmode=0)
xxxxResize(xxxx, yyyy)
ConvertLinearRGBtoYUV(color=0, outputmode=2)

Is the difference between outputmode=0 and 2 in the first conversion just accuracy (and speed)? I tested a short encode with both values and outputmode=0 produces a slightly larger file. I cannot tell a difference in VDub2 when interleaving the two choices.

jpsdr
24th May 2020, 10:45
AS said in the ReadMe :
OutputMode -
Set the output data mode.
0: No change : Input 8 Bits -> Output : RGB32, Input > 8 Bits -> Output : RGB64
1: The ouput will be RGB64
2: The ouput will be RGBPS (Planar RGB float)

So, if your input is >8bits, outputmode=2 will force output to RGPBS instead of RGB64, better accuracy but slower (didn't make speed test, so can't tell "how much" slower).
There is no other difference.
Some people said that they have banding introduced even in 16 bits when converting from/back in PQ mode (especialy in dark area), but not in float mode. So, i'll suggest outputmode=2 in the first convertion.

real.finder
24th May 2020, 11:07
AS said in the ReadMe :
OutputMode -
Set the output data mode.
0: No change : Input 8 Bits -> Output : RGB32, Input > 8 Bits -> Output : RGB64
1: The ouput will be RGB64
2: The ouput will be RGBPS (Planar RGB float)

So, if your input is >8bits, outputmode=2 will force output to RGPBS instead of RGB64, better accuracy but slower (didn't make speed test, so can't tell "how much" slower).
There is no other difference.
Some people said that they have banding introduced even in 16 bits when converting from/back in PQ mode (especialy in dark area), but not in float mode. So, i'll suggest outputmode=2 in the first convertion.

btw why not accept RGBP! or even RGB48!

jpsdr
24th May 2020, 11:17
I don't see the need of others RGB outputmode, you can add a convertion after if you want something else, it will be lossles if you keep the same bit depth.
Also, it means i have to add input support of these formats in ConvertRGBtoXXX, i don't see the point to ouput something i don't support in input in the reverse convert. Don't want to.
From my point of view, supporting RGB, RGB64 and RGPS is enough to cover all the others cases, which can be easely be done by a simple convertion from the avs core.

real.finder
24th May 2020, 11:24
It's called ConvertYUVtoLinearRGB, so, i only acced YUV input.
As far as i know, there is no source material as float, we are for now, at maximum 12 bits. So, as i'm lazzy, i don't intend for now to add float YUV input support.

I mean ConvertXYZtorgb https://forum.doom9.org/showpost.php?p=1880289&postcount=2

also as the output, RGBP should be faster than RGB48, RGB64

and RGB48 (with no alpha) should be faster than RGB64

jpsdr
24th May 2020, 11:30
Ah...:(
You answered during my post change/edit, after correcting my misunderstanding of your question.

real.finder
24th May 2020, 11:41
Ah...:(
You answered during my post change/edit, after correcting my misunderstanding of your question.

I don't see the need of others RGB outputmode, you can add a convertion after if you want something else, it will be lossles if you keep the same bit depth.
Also, it means i have to add input support of these formats in ConvertRGBtoXXX, i don't see the point to ouput something i don't support in input in the reverse convert. Don't want to.
From my point of view, supporting RGB, RGB64 and RGPS is enough to cover all the others cases, which can be easely be done by a simple convertion from the avs core.

what about make it just RGBP, since RGB64 is slower

0: No change : Input 8 Bits -> Output : RGBPx, Input > 8 Bits -> Output : RGBPx
1: The ouput will be RGBP16
2: The ouput will be RGBPS (Planar RGB float)

jpsdr
24th May 2020, 11:49
Not sure RGB64 is slower, and i don't intend to start a huge work, because as i said, changing/adding output supported formats means also changing/adding supported formats input for the next filter.
This will be a long work, and i don't intend to spend time on something i think unecessary (again, you can convert lossless afterward).

Edit
Again i may have misunderstood... I mean for me not sure RGB64 is slower for the specific case of these plugins.
After, of course, for others plugins, it's another story.

Boulder
24th May 2020, 11:49
I just tested a 1000-frame encode,
outputmode = 0, 2.25 fps, 8825.11 kbps, avg QP 15.11
outputmode = 2, 2.26 fps, 8595.19 kbps, avg QP 14.76

Using outputmode = 2 was a tiny bit faster to encode but probably due to the lower avg bitrate. The difference in avg QP is quite big. But like I said, I cannot tell the difference in frame-by-frame comparison of the source, so it probably just stabilizes things.
What I found odd was that outputmode = 2 produces one keyframe more than outputmode = 0. I need to investigate where it is to see what's happening there :)

FranceBB
3rd September 2020, 13:48
I'd like to convert an SDR video (rec709) to HDR (rec2020)?
I tried feeding this directly into x265:
ConvertYUVtoXYZ()
ConvertXYZtoYUV(Color=1, pColor=2)
Am I missing something?

I don't think that's what you're doing.
Simply using


ConvertYUVtoXYZ()
ConvertXYZtoYUV(Color=1, pColor=2)


will NOT give you any kind of HDR, you're essentially just converting from BT709 SDR to BT2020 SDR, that's it.
And of course, colors should be identical (if seen using an appropriate display) as it's SDR to SDR.
To properly encode it in x265 make sure you're setting: --colorprim bt2020 --transfer bt2020-10 --colormatrix bt2020nc and nothing else as it's not HDR, it's SDR, BT2020 SDR.

If you wanna go to "fake" HDR for any kind of reason and you wanna use HDRTools, the thing you're looking for is: ConvertXYZ_Scale_SDRtoHDR() with the appropriate parameters. Otherwise, there are always my matrices. (https://forum.doom9.org/showthread.php?t=176091) I gotta say, though, that unlike SDR to SDR (like BT709 SDR to BT2020 SDR), if you go to HDR (namely BT2020 + a color curve) you're not gonna get an output that is identical to the input even if displayed with a proper display as you're essentially faking a color curve and HDR Metadata. This should be avoided unless you really need to. A common scenario is when you're producing something in HDR PQ or HDR HLG (like a Documentary) and you have some legacy footages to insert every now and then between interviews (and therefore you need to bring those BT709 SDR footages to HDR PQ or HLG).
Anyway, if this is NOT what you're doing, stick with BT2020 SDR. ;)
if your final result is in PQ, make sure to specify:

--hdr-opt --hrd --colorprim bt2020 --transfer smpte2084 --colormatrix bt2020nc --master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0050)" --max-cll 1000,400

(that's an example, you have to set master display and cll yourself according to your values)

for HDR HLG:

--hdr-opt --hrd --colorprim bt2020 --transfer arib-std-b67 --colormatrix bt2020nc --atc-sei 18 --master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0050)" --max-cll 1000,400

DTL
20th April 2021, 23:30
A question about parameters for ConvertYUVtoLinearRGB : If I need to got inverse-OETF for given input system - which combination of EOTF and OOTF bools must be used ?

As I read from https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-7-2019-PDF-E.pdf the EOTF even for old enough BT.709 is not complete inverse of OETF so resulting OOTF is not completely linear. Leaving System Gamma about 1.2.

Readme says about OOTF param:
OOTF -
Color = 0:

HDRMode = 0, 1, 2:
If set to false, the OOTF-1 step will be skipped during the linear convertion.

Color <> 0:
If EOTF is false, nothing is done whatever OOTF => Output will be standard RGB.
If OOTF is false and EOTF is true, the output will be the linear displayed data (Fd).

Default: true (bool)

For BT.709 input Color=2, so if EOTF=true and OOTF=true and Color=2 - what is output ?

Also for terms:
"Output will be standard RGB." - it mean RGB with OOTF not removed and target for displaying ?
"output will be the linear displayed data (Fd)." - it mean original true-linear RGB (inverse-OETF) ?

Or OOTF only applicable to BT.2100 (Color=0) and not applicable to BT.709 so it can not make real inverse-OETF for BT.709 to get initial true-linear data ?

jpsdr
21st April 2021, 18:03
Don't make the same mistake than me at the begining, believing EOTF is the inverse of OETF. That's not it. Did you read the PDF i've provided with the plugin where i try to explain how it works and the paths with the functions name ?

Es = true original linear (directly from sensor)
E' = non lineard (what we are working with on our PCs).
Ed = linear displayed (what the screen displays/uses).
E' = OETF(Es)
Ed = EOTF(E')
Ed = OOTF(Es)
Again, read the PDF provided.

Standard RGB : Simple matrix conversion YUV <-> RGB, so E'.
It's not that's OOTF is not applicable, it's just that there is no one direct function. For BT.709 to have OOTF you do EOTF(OETF()).

BT.709 EOTF=true & OOTF=true you have inverse OETF, so Es.
BT.709 EOTF=true & OOTF=false you have inverse EOTF, so Ed.

From what i understood reading all the REC i list in the pdf.

DTL
21st April 2021, 19:01
Oh - I found .pdf document only in the release .zip. The github files only have HDRTools - readme.txt. Now it is more sources to read. Thank you.

Dogway
21st April 2021, 21:51
Couldn't find any tool to TM without issues.

madVR
http://i.imgur.com/wjNxXZFm.png (https://i.imgur.com/wjNxXZF.png)

HDRTools

ConvertYUVtoXYZ(Color=0, OutputMode=2, HDRMode=0, fullrange=false, OOTF=false)
# Lhdr at 50000 otherwise overexposed output as pointed by someone before, Lsdr has no effect
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true,Lhdr=50000.0,Lsdr=200.0,pColor=0,pct_ref=0.6,pct_ip=0.6,pct_wp=1.0,pct_sdr_skin=1.0,pct_hdr_skin=0.44)
ConvertXYZtoYUV(Color=2,pColor=0,OOTF=false)
Converttoyuv420(interlaced=false, matrix="Rec.709")
ConvertBits(bits=8, dither=1)
http://i.imgur.com/ZYu39JPm.png (https://i.imgur.com/ZYu39JP.png)
This is with Reinhard
# Reinhard has better TM, but the exposure value is a bit random
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=28.0)
http://i.imgur.com/3hjRPiPm.png (https://i.imgur.com/3hjRPiP.png)

DGHDRtoSDR

# White Point is too cool, maybe a chromatic adaptation issue
DGHDRtoSDR(mode="pq",white=48)
ConvertBits(bits=8, dither=1)
http://i.imgur.com/loadbbQm.png (https://i.imgur.com/loadbbQ.png)


There's also heavy banding with HDRTools (EDIT: nevermind fixed adding OutputMode=2):
http://i.imgur.com/dTd69M1m.png (https://i.imgur.com/dTd69M1.png)


By the way, it would be cool to support .measurement files made with madMeasureHDR so TM could be done dynamically.

jpsdr
30th April 2021, 15:32
New version, see first post.

StainlessS
30th April 2021, 16:23
And thanx for this one too, and the other one [EDIT: two, EDIT: three] I aint comented on. (you've been a busy boy/girl :) )

FranceBB
30th April 2021, 19:06
(you've been a busy boy/girl :) )

I'm pretty sure Jean Philippe is a dude xD

And thanx for this one too

Yep, thank you, Jean ;)

jpsdr
30th April 2021, 20:05
Yes, i'm a dude.

Almost everything was allready done, but i wanted to finish fixing the aWarp4 issue before releasing new builds.
I was waiting to have time to investigage it, and this is my first day of my holydays, so i finaly got the time, and also i wanted to "get rid of it", to be quiet for the rest of my holydays... :D

StainlessS
30th April 2021, 21:59
OK dude, have a nice holiday.

FranceBB
1st May 2021, 10:47
i wanted to "get rid of it", to be quiet for the rest of my holydays... :D

Smart move. Enjoy your vacation ;)

Hotte
30th May 2021, 17:57
I have some more general, simple questions concerning HDR.

My camera allows me to record in Rec.2020 (HLG) or Rec.709 while shooting in 10-bit modes. As far as I understood the idea of colorspaces, BT.2020 also covers colors outside 709 hence a larger visible colorspace if I have the right monitor. Although I have an sRGB-display I might be going for a HDR-Monitor in the near future to participate.

So I thought it is a good idea to start recording everything new in HLG rather than keep on shooting in 709.

But:

Isn't HDR only a mapping of colors rather than a quality push ? Could I e.g. remap rich 10-bit footage captured in 709 to become satifying HDR if needed (maybe using HDR-Tools) ?

Or is the chance for HDR gone if it was not recorded in BT.2020 right from the start ?

Generally I found it hard to get satisfying 709 results from HLG source: The colors, especially red spectrum ist somewhat out of balance and I have not found any approach yet to cure this.

What would you recommend ?

videoh
30th May 2021, 21:12
Isn't HDR only a mapping of colors rather than a quality push ? Could I e.g. remap rich 10-bit footage captured in 709 to become satifying HDR if needed (maybe using HDR-Tools)? "quality push"? "rich"? "satisfying"?

Bit depth is independent from color space, but BT2020 is usually chosen for HBD.

Generally I found it hard to get satisfying 709 results from HLG source: The colors, especially red spectrum ist somewhat out of balance and I have not found any approach yet to cure this.

What would you recommend ? Post a link to the problematic HLG source video.

Hotte
30th May 2021, 22:09
"quality push"? "rich"? "satisfying"?
Bit depth is independent from color space, but BT2020 is usually chosen for HBD.

I am clear about bit depth being independent from colour space.

The essence of my question was if I should always record my 10-bit modes in BT2020 to be future-proof.

Currently I am on Rec709 (monitor, projector...). Recording everything in BT2020 today would mean conversion down to 709 which probably comes with some compromise.

Also the HLG-setting in my cam does not allow me to use a flat log-profile. Or is a flat profile not needed anymore with HDR ?

Or is there a way up from recorded Rec709 to BT2020 ?

Sorry, maybe silly questions. I just want to make sure I am going into the right direction.

FranceBB
31st May 2021, 16:41
The essence of my question was if I should always record my 10-bit modes in BT2020 to be future-proof.


Yes



Currently I am on Rec709 (monitor, projector...). Recording everything in BT2020 today would mean conversion down to 709 which probably comes with some compromise.


Yes, you would have to convert, but I would strongly suggest not to shoot in Linear BT709 SDR 100 nits in 2021 especially if the camera has far more stops than 6 stops which is 100 nits 'cause you would be wasting the sensor capacity otherwise... Also BT2020 alone won't achieve anything, it's just a color matrix, what's important is the color curve, in this case HLG which will allow you to record as many nits as the stops of the sensor.



Also the HLG-setting in my cam does not allow me to use a flat log-profile. Or is a flat profile not needed anymore with HDR ?


Ok, a bit of confusion.
BT709 and BT2020 are just matrices, those are color matrices and both are SDR 100 nits. Sure, BT2020 would give you a better result, but you're still gonna be limited to 6 stops, 100 nits SDR, so, if you shoot a subject with the sky behind and sunlight, either the subject will be lit and the sky clipped out and white averaged out at 940 or the sky is gonna be there and the subject is gonna be totally dark 'cause you still have only 6 stops, 100 nits.
Now, when it comes to color curve, those give you "HDR" aka "High Dynamic Range". Now, I don't know which camera you have and you didn't specify which log you're shooting in, so I'm gonna assume Slog3 for the sake of the argument.
If you compare Slog3 vs HLG, both have their pro and cons. You gotta remember that HLG is not a purely logarithmic color curve, therefore it starts just like a normal linear SDR curve and then it slowly curves and becomes logarithmic, which means that the blacks won't have many details and they're gonna be just like the SDR ones, but the more you "go up" the more logarithmic you get, so the highlights are gonna be preserved and you're gonna get more nits (up to 1000 nits, although I strongly doubt that your camera will reach that and it's gonna sit probably around 600-700). The reason why HLG is an "Hybrid Log Gamma" (emphasis on "hybrid") is that it allows backwards compatibility with SDR monitors and decoders who ignore the color curve and just interpret the color matrix. Of course, this "sacrifices" the details in the black 'cause you won't get anything more than shooting in SDR in the blacks. This is NOT true for Slog3, though. Just like other purely logarithmic curves like Clog3, Log-C, PQ etc, it starts logarithmic and continues as logarithmic, therefore you're gonna have many more nits available and you'll have many more details in the blacks as well. Cameras nowadays (assuming you're not using a Red Monstro or something insanely pricey and bleeding edge) sit around 700 nits anyway, so you won't have more details in the highlights using a purely logarithmic color curve anyway (even if they can go up to 10'000 nits) but you will get more details in the blacks as they start logarithmic and not linear. The "problem" with this is that this way you're literally getting as many frequencies as the sensor can get and many sensors do a fairly BAD JOB with dark/black areas, so the details you're gonna get are very likely going to be full of combing in the chroma and noise in the luma anyway. Nonetheless, if you ask me, from a purely mathematical point of view, it's better to shoot in a purely logarithmic color curve. That being said, I would suggest you to shoot in HLG for your use case and perform a linear transformation with a matrix like a custom made LUT in Davinci or any NLE to bring it to Linear BT709 SDR so that you can pick which frequencies are gonna be kept and which other are gonna be cut or kneed down to SDR. I also suggest you to archive the HDR HLG BT2020 master for future use. The reason why I'm suggesting you this is that *some* cameras that were produced in the middle of a "transition" only allow purely logarithmic curves with the BT709 matrix but not BT2020. This historically has a reason: when PQ and HLG were not yet invented camera manufacturers were already able to shoot with more than 6 stops 100 nits, so they invented their own color curves: Sony invented Slog, Canon invented Clog, Arri invented LogC, Fuji invented FLog etc and they did that with the only color matrix that was available at the time: BT709. Some manufacturers were quick to catch up and allow to record in Log with BT2020 (BT2100) as well, but some others were not, therefore:

- If your camera allows you to shoot log in BT2020 (BT2100), then do that and then apply a matrix to go to BT709 SDR and archive the original master. The SDR you're gonna get is gonna be far better than anything you can get by shooting in SDR directly from the camera.

- If your camera allows you ONLY to shoot log in BT709 but allows you to use BT2020 for HLG, then shoot in HLG BT2020 HDR, archive the original master and then use a matrix to bring it to Linear BT709 SDR. The SDR you're gonna get is STILL gonna be far better than anything you can get by shooting in SDR directly from the camera, at least in the highlights.


p.s also remember that purely logarithmic curves are NOT backwards compatible with SDR.


I hope this cleared the confusion a bit and helped you pick the correct profile.

Cheers,
Frank



Side note: Oh, I almost forgot: HDRTools from Jean Philippe currently only supports PQ and HLG but not other curves, so using it for Slog1, Slog2, Slog3, Clog1, Clog2, Clog3, LogC, FLog, DLog etc is out of question.
Side note 2: A personal appeal to Jean Philippe -> if you wanna introduce support for them as well and you need to work out how they work along with samples I can provide them to you via FTP, just like we've done back when we were testing BT2446 in 2019. You know, I'm always here, buddy ;)

jpsdr
31st May 2021, 17:56
So much................?????????????? Fleeing (with Benny Hill music)...:p

videoh
2nd June 2021, 01:04
Fleeing (with Benny Hill music) Me too.

Hotte
2nd June 2021, 09:15
:thanks: very much, Frank. This makes me learn a lot.

(To be honest: I had seen you being active in this thread and I hoped, that you would contribute with your excellent knowledge and the ability to explain complicated things from scratch in a very understandable manner).

I would like to discuss this a bit further, but I saw too late this is the developer's chatroom (it is where the search engine sent me to), and maybe continuation is inappropriate here. If so, just say and I am happy to move elsewhere. However I think that a broader community benefits a lot more from sophisticated discussions here if some basics are being explained from time to time.

I`ve got a Panasonic G9 which can (latest firmware) record 10-bit YUV422 BT.2020 with HLG-profile available. My Edius-X shows the footage as BT.2020 explicitly with "BT.2100 HLG"-gamma curve. It is HEVC-coded. There is an ultraflat VLOG-L profile available for 100$ extra. They say it increases DR by 2 f-stops to 12 f-stops.

Question 1: As far as I understood you, there is no need to go for a VLOG-L profile: If I am doing it right, I will be able to squeeze all available shadow-DR out of the HLG master too if needed. Correct ?

Question 2: The "Primary Color Correction"-Filter in Edius allows me to apply LUTs and conversions. Leaving Input and Output in HLG results in this well described flat, colorless look on my calibrated Rec709-Monitor. The question is, why then HLG in some way is told to be "Rec709-compatible" if it looks so unnaturally washed out ?

Question 3: If I apply BT2020 / BT.2100 Input and Rec709 output in the PCC-Filter it looks much better. But still the greens and reds are not fully convincing and it is difficult to get the midtones into some harmonic balance. I`d say you achieve acceptable but not really good results. I thought BT2020/BT.2100 as well as rec709 are standard profiles so why are colors and tones getting messed up like this ?

Question 4: Is HDRTools something to improve this or do I have to take the hard track of trying out numerous LUTs until I find sth convincing ?

FranceBB
2nd June 2021, 11:02
:thanks: very much, Frank.


No worries, I like to reply on Doom9 (when I can contribute), it's like my favorite hobby (which is far more useful than posting memes on Facebook as some other people do instead xD).




I would like to discuss this a bit further, but I saw too late this is the developer's chatroom (it is where the search engine sent me to), and maybe continuation is inappropriate here.


I don't think Jean Philippe minds if we stick here. After all it is HDR Tools related, so...
But the final decision is his since it's technically his topic and his plugin xD




Question 1: As far as I understood you, there is no need to go for a VLOG-L profile: If I am doing it right, I will be able to squeeze all available shadow-DR out of the HLG master too if needed. Correct ?


V-Log would probably be better in preserving blacks. Simply put, if you take a look at the waveform in a V-Log file, you're gonna see it exactly in the middle.
This is V-Log plotted in the graph against Stop/IRE:

https://i.imgur.com/6JbaNpK.png

As you can see, it starts "high" and it slowly goes all the way up.
It is a truly logarithmic curve which means that blacks are "high" as they start "high" and hence are preserved:

https://i.imgur.com/0oAiKp0.png

HLG is not a truly logarithmic curve, it starts like a normal curve and then slowly becomes logarithmic.
What this means is that the blacks are just like you would see them in a normal SDR recording, but the more it goes up, the closer it gets to be a Logarithmic curve.
Take a look at the graph:

https://i.imgur.com/uBdkzIF.png

There are two things you should notice:

1) the blue curve (HLG) starts much lower compared to V-Log
2) it goes up much faster than V-Log

The reason for the first point (1) is that HLG starts lower 'cause it's an Hybrid Log Gamma, so it's not logarithmic, hence blacks are not "pushed up" and hence not preserved. The reason for the second point (2) is that by doing this "trick" to be hybrid and not truly logarithmic it doesn't have as many nits as a truly logarithmic curve like V-Log, Slog, Clog, PQ, have and it peaks at 1000 nits max.

They say it increases DR by 2 f-stops to 12 f-stops.


That would be correct, a truly logarithmic curve is better than an hybrid curve like HLG, so the additional stops you get are almost definitely details in the blacks. Technically you would get more in the whites too, but the camera sensor can't record more than 1000 nits anyway so you won't get any benefit in the whites from using V-Log compared to HLG.



The question is, why then HLG in some way is told to be "Rec709-compatible" if it looks so boringly washed out ?


It's not.
This is a very common mistake: when people say "HLG is backwards compatible with SDR monitors" they clearly mean BT2020 SDR monitors, but most people associate SDR with BT709. You see, SDR has nothing to do with color matrices: BT601, BT709, BT2020 can all be SDR 100 nits. Standard Dynamic Range basically means that what you get only has a color matrix with the same gamma and primaries, so no fancy color curve. An SDR file can be an SD BT601 100 nits, an SD BT709 100 nits or a BT2020 100 nits. So, when you get an HLG BT2020 stream, it is backwards compatible with TVs that understand just the color matrix but not the curve and they're gonna ignore the curve. The result will look ok-ish 'cause blacks are just fine 'cause it starts linear just like you would have with a normal BT2020 SDR stream, but as it goes up it becomes logarithmic. This is a compromise that broadcaster decided to adopt 'cause this way with just one channel you can cover 4K BT2020 SDR TVs and 4K BT2020 HDR TVs. You couldn't do that with truly logarithmic curves like PQ 'cause the result would be washed out as levels wouldn't match in a BT2020 SDR TV as blacks would start high. By being "hybrid", though, HLG peaks at 1000 nits and can't go beyond. On top of that, you don't get any additional details in the blacks 'cause they're effectively just like an SDR stream.


So, the HLG compromise is simple: the closer you get to HDR, the worse it looks on SDR BT2020 compatible monitors, the closer you get to SDR BT2020, the less dynamic range you have on those with an HDR compatible TV.
Since HLG is not a purely logarithmic curve, its lower part resembles the one of an SDR curve like the Linear BT2020nc SDR 100 nits, but as it gets to the higher values (whites) it resembles more and more a logarithmic curve and therefore introduces dynamic range, hence it doesn't offer many details in the blacks, but it does offer them in the mid-white and therefore it avoids the sky to be clipped out etc. As I said, the problem is that the TVs that don't understand any color curve, but do understand BT2020 are not gonna interpret those things, hence displaying the lower values correctly but not the highlights. Of course, this is intended and it's what the BBC made it for, in fact we've been airing like this for years now.

Here's a comparison of an HDR HLG BT2020nc 600 nits shot with a Sony A7 III:

On a TV which interprets both the color matrix (BT2020nc) and the color curve (HLG) and displays it as intended:
https://i.imgur.com/T7I2bRK.png

On an SDR TV 100 nits which does interpret the color matrix (BT2020nc) but totally ignores the color curve (the "not so bad" fallback as intended by the BBC specs):
https://i.imgur.com/W9TViA6.png

On an SDR TV 100 nits which has no clue about both the color matrix and the color curve and ignores them both like your BT709 display (totally wrong display, not acceptable, never should happen):
https://i.imgur.com/sXNb8CI.png


The first image is what we see in our monitors and it's how the whole content is graded and how it should be visualized by people at home. It's HDR, it has a dynamic range of 600 nits.
The second image is what people at home who have an old 4K TV which doesn't support HDR are gonna see. Ignoring the color curve and just interpreting the matrix isn't so bad and it's what the BBC guys were thinking about. The fact that the color curve is ignored makes the image look ok in the lower values/blacks ('cause the HLG is essentially like the Linear BT2020 SDR on the lower part) and "dull"/greyish in the higher values/whites ('cause as it goes up it embraces its logarithmic part).
Lastly, we have something that should never happen and that it's not part of the specs as not only it ignores the color curve, but it wrongly translates the values of the BT2020 so it's totally wrong. This is what happens if you try to watch a BT2020nc HLG stream on a BT709 aware only monitor (so don't do it).


Question 3: If I apply BT2020 / BT.2100 Input and Rec709 output in the PCC-Filter it looks much better. But still the greens and reds are not fully convincing and it is difficult to get the midtones into some harmonic balance. I`d say you achieve acceptable but not really good results. I thought BT2020/BT.2100 as well as rec709 are standard profiles so why are colors and tones getting messed up like this ?


I don't know what that filter is doing, so I can't say, but yes, the conversion is the reason why you see "funny" results.


Question 4: Is HDRTools something to improve this or do I have to go the hard track of trying out numerous LUTs until I find sth convincing ?

Definitely. You can use HDRTools to go from HLG BT2020 HDR to Linear BT709 SDR 100 nits in several different ways and it has several different parameters.

There are three different tonemappers: Hable, Mobius and Reinhard + the official BT2446_C implementation to go from HLG to BT709 SDR. I'm not gonna get into which one you should pick and why and what are the pros and cons of each tonemapping algorithm as it has been discussed several times here and also 'cause my reply is already long enough I think xD

Still, this is a start:


ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.1)

ConvertXYZtoYUV(pColor=0)



That conversion takes care of the color matrix + color curve conversion, while this one is just the color matrix without the color curve:

ConvertYUVtoXYZ(Color=1)
ConvertXYZtoYUV(pColor=1)

it's useful to see how people at home who have an SDR monitor would see the BT2020 HLG stream ignoring the color curve. Anyway, for what you have to do, try with the first script I posted and read the documentation and go on from there. Jean Philippe beautifully described what he has done in the filter and you can see it explained in detail in a PDF file that you can find in his repository. ;)

Hotte
2nd June 2021, 13:26
Frank, for a first reaction...

This is an excellent description of the matter and a most precious contribution for alle HDR-Newbies.

It will take me some time to study this in detail and experiment And I might be coming back at a later stage with some need for advice.

Just one quick thought upfront: After what you've said I have a first impression that HLG is not the ideal profile for its compromises and limited DR in the low lights and VLOG-L could be worth while having a closer look into. This is an important question, because workflow optimization could be much different. My basic understanding is that VLOG-L conserves all the DR better and could be graded and matrixed into whatever target is needed. But then I'd need a VLOG-L => SDR 709 and a VLOG-L => HLG 2020/2100 conversion dependant of where I want to watch the content. Is this also sth HDRTools could be helpful for (if it's in the Docs "Yes" is the short answer needed and I am going to check this out for myself).

But some people say: Don't shoot VLOG-L all the time (sunny days...). It demands a minimum of ISO400 (more noise as standard ISO200), DR is not needed... But permanent change of profiles would make the workflow extremely difficult. Never heard this about HLG. So how is that to be taken ?

And what I have not yet quite unterstood is: Will I use a wide color gamut display oder projector to its full capabilities if I grade say a VLOG-L master to HLG2020/2100 later ? The emphasis here is on larger colorspace, because I do not know which matrix I end up with VLOG-L (haven't bought it yet) and if it is, say, 709 the matrix may not be extendable without significant loss in post ?

For my workflow it is a bit difficult to use HDRTools as converter because it would have to be done before the source file arrives in the NLE. But that could may be done someway with mounted avisynth... I will be trying it out.

FranceBB
2nd June 2021, 14:21
This is an excellent description of the matter and a most precious contribution for alle HDR-Newbies.


Thanks. :) I hope it's gonna help other people too. :D



VLOG-L conserves all the DR better and could be graded and matrixed into whatever target is needed. But then I'd need a VLOG-L => SDR 709 and a VLOG-L => HLG 2020/2100 conversion dependant of where I want to watch the content.


That's exactly right. From V-Log you can go both to BT2020 HLG HDR and to Linear BT709 SDR. Here at Sky but also in other professional productions we always shoot log and then grade to other version like PQ for UHD-BD, HLG for linear UHD channels and BT709 SDR for FULL HD channels.
This movie I worked on: https://www.imdb.com/title/tt11462526/ was shot in Clog3 and then graded to HDR, although limited to 400 nits due to the camera limitations I faced with Canon at the time.



Is this also sth HDRTools could be helpful for?


Sadly no, HDRTools only supports HLG and PQ but no other curve... :(



But some people say: Don't shoot VLOG-L all the time (sunny days...). It demands a minimum of ISO400 (more noise as standard ISO200), DR is not needed...


Pff! You can shoot log all the time, totally. Also, if it's a sunny day, you're gonna have the clouds in the sky if you shoot log, however you won't if you shoot like in BT709.
There's NOTHING stopping you from shooting log in this day and age.
About the noise part, that's sadly true, though. Log will introduce more noise all the time, but that's normal and for the reason I explained before. ;)




Never heard this about HLG. So how is that to be taken ?


There will be noise in HLG as well, although much less 'cause the added noise is generally in the blacks and HLG is like an SDR at the beginning (in the blacks) so you won't get noise there which is the most visible and noticeable one. You'll still get more noise in the mid-highlights but the sensors generally do a very good job there, so you won't notice.



Will I use a wide color gamut display oder projector to its full capabilities if I grade say a VLOG-L master to HLG2020/2100 later ? The emphasis here is on larger colorspace, because I do not know which matrix I end up with VLOG-L (haven't bought it yet) and if it is, say, 709 the matrix may not be extendable without significant loss in post ?


Who knows...
As I said, some manufacturers allow people to shoot log with BT2020, so if that's the case you're gonna be fine grading to BT2020 HLG later on and/or to BT709 SDR now. If, for historical reason, it's still with BT709, then you're fuc... ehm no I can't write it in a public forum, let's say you're "screwed" eheheheh
Jokes aside, you could still go to BT2020 HLG, but you would just make use of the color curve nits but not of the wider color gamut. In that case I would suggest you to use HLG BT2020 instead as using V-Log with BT709 wouldn't be worth it. Ask the manufacturer, they'll tell you, hopefully.

Hotte
2nd June 2021, 16:33
...I would suggest you to use HLG BT2020 instead as using V-Log with BT709 wouldn't be worth it.

One of those precious suggestions that really help to take off from sbdy who really knows what he's talking about.

For now I've got enough information. Will develop my workflow further and might be coming back at a later stage. Thanks!

DTL
6th June 2021, 15:12
"There's NOTHING stopping you from shooting log in this day and age."

Actually the whole playing around HDR and more badly HDR shooting for SDR output is not any everyday shooting idea. HDR more looks like 'poor people' exposition fool-proof shooting but getting every time the worst result in color and tone that the only matter for true art shooting. If we look at the curves of long used by pro photographers reversable film curves we will find the standard transfer curve for decates of old pro landscape and other pro shooting. And it really not High-DR process but Low-DR process with not compressing but expanding the nice low DR to standard DR. Typical pro-standard for landscapes Fuji Velvia film have about 6 f-stops of full DR and specially bended transfer curve with expanding DR at some points to 2..3 times of linear input.

If someone will shoot log (v-log) all the time with low bits it will cause the position of the nice to pick range in several bit encoding and result will be degraded by quantization noise and camera noise. To have headroom for HDR highlights camera put really valueable levels to low and noisy levels. The color degraded.

So HDR capture mostly toy for cheap broadcast live TV where the real scene lighting can not be controlled or selected for art purposes and hardware non-clipped highlights saves some work of live broadcast aperture-control engineers and camera knee-control engine (if auto-knee enabled). For serious art work with pro-controlled lighting and very limited DR for really important subjects of the scene using HDR/V-log capture will wastes most of bits in recording and produce low signal to quantization noise result. Because pro-controlled lighted scene have very low DR like 2..3 f-stops for most important subjects.

Keeping the natural DR or more badly compressing natural DR may be boring to viewer - you see this even without paying for process. In compressed DR the viewer lost even natural textures because the contrast sensitivity of viewer is limited and log-based. So to show to the viewer more details of natural subjects we need to expand DR. And expanding DR with pro processing may be new and interesting to viewer because it have natural logariphmic eyesense and can not see subtle levels of lighting changes well. Using log/v-log encoding of pro-lit scene with very low DR and intended for expanding DR at processing and displaying will leave only several bits for encoding the required levels of brigtness and may cause to lost subtle brightness details (due to more high quantization noise).

"But some people say: Don't shoot VLOG-L all the time "

If your scene is pro-lit and the lighting artist of good educated and understand what he doing and shooting operator is artist (not just camera pointing guy to there director says to point) you need to measure the actual scene linear DR and use the camera shooting mode to put this DR to as many recored useful bits as possible. For camera histogram it may mean not only 'Exposure To The Right' but more important 'Exposure to Fill Full Histogram'.

Also the release footage _displaying_ format may be HDR because of DR-expanding technique at post processing described above and _shooting_ format may be SDR to capture as many light levels of low DR scene as possible without degrading by quantization noise and later with comparession (if used).

HDR/log (compressing-DR) shooting is mainly when your lighting director do not understand what he is doing, scene illumination is bad and non-controllable and the content and lighting of the scene contrast is awfully high, you can not re-shoot the scene in better lighting and better arrangement of contrast items like live one-time event, etc. HDR/log shooting tool will let to show badly lit and bad contrast scene not as bad as with SDR shooting but will damage high-art low-DR and low-contrast scene with quantization noise and lost of fine texture details, and so on.

May be in short form: Camera's DR must follow scene's DR and typical high-art scenes are of low DR and designed for future expansion of DR for displaying.

FranceBB
7th June 2021, 10:11
HDR/log (compressing-DR) shooting is mainly when [...] scene illumination is [...] non-controllable and the content and lighting of the scene contrast is awfully high, you can not re-shoot the scene in better lighting and better arrangement of contrast items like live one-time event, etc.


Which covers 99.9% of the events I deal with, as I work mainly on sports. You know, you can't tell a player to take a free kick twice 'cause I didn't like the lighting xD
Besides, sporting events are played outside and you have the direct light coming from the sun to the pitch and it might change out of the blue due to a cloud or whatever. It would be a nightmare...



HDR/log shooting tool will let to show badly lit and bad contrast scene not as bad as with SDR shooting but will damage high-art low-DR and low-contrast scene with quantization noise and lost of fine texture details, and so on.


Of course compressing a waveform in the middle like it happens in this case and pushing the low values high means that we're gonna use the very same bits to code "more" values which is gonna lead to quantization noise, indeed, granted, but log footages are generally easier to encode so that the difference is gonna be attenuated.




May be in short form: Camera's DR must follow scene's DR and typical high-art scenes are of low DR and designed for future expansion of DR for displaying.

I know what you mean here and indeed it's a tough case in the sense that his final result is always gonna be SDR, so, in a controlled environment with controlled lights and if he can take several takes at a scene, he might (just might) be better off with SDR, but honestly, it's summer 2021, if it was me I would love to have all my shots future-proof and I wouldn't really feel comfortable into expanding DR from SDR even in a controlled environment 'cause if one day I really want to display those, I won't be able to and I'm gonna regret it forever 'cause the camera was able to and I choose not to, you know what I mean...?

jpsdr
20th July 2021, 18:03
New version, see first post.

Atlantis
6th August 2021, 09:51
First thank you for your tools. I use it for HDR to SDR and it gives the best results that I have seen. I try to go simple. I use this

ConvertYUVtoXYZ(Color=0, HDRMode=0, OOTF=false, OutputMode=2)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true, Lhdr=10000, Lsdr=100.0, pColor=0)
ConvertXYZtoYUV(Color=2, pColor=0, OOTF=false, OutputMode=2)
ConvertBits(10)

It looks great. However I need a little extra tweak. I want to add a little higher contrast. A little deeper blacks. How can I achieve this?

jpsdr
6th August 2021, 17:40
Sorry, i don't know... You have to eventualy check the BT2446 spec (R-REP-BT.2446-2019-PDF-E p17-20, figure 10 p20), check the curves/parameters (the pct_xxx parameters) and eventualy whiteshift and "play" with them.
I know i've made the filter, but i don't use them.
I've done these as basic tool set for trying to do a neural network HDRtoSDR converter, but unnfortunately without sucess.
I've implemented the common know HDRtoSDR method, but i'm not using them...

FranceBB
6th August 2021, 18:45
I've done these as basic tool set for trying to do a neural network HDRtoSDR converter, but unnfortunately without sucess.

but there's room for improvement and I'll take the chance to write my request.

Since all the tonemapping algorithms are already there, what if:

1) A user-defined lookahead is introduced

2) A threshold parameter is introduced

2) A bool is introduced so that the user can choose "static" true or false. If true, then it behaves as it has been behaving so far, if false, then the user can specify the two parameters above.

What those parameters do is simple: take a bunch of frames into consideration, analyze the peak luminance of these frames and pick the best possible values for the tonemapping for that scene. The threshold parameter would define how different luma should be for the filter to consider that being a "scene change".


Quoting myself from some time ago:


Hi there,
in MPV tonemapping is applied using Hable, Mobius or Reinhard on a scene by scene basis by using the HDR Compute Peak, the HDR Peak Decay Rate and the HDR Scene Threshold.

Those three parameters are what are really doing the trick to the very good SDR representation of MPV:

--hdr-compute-peak=<auto|yes|no>
Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping.


--hdr-peak-decay-rate=<1.0..1000.0>
The decay rate used for the HDR peak detection algorithm (default: 100.0). This is only relevant when --hdr-compute-peak is enabled. Higher values make the peak decay more slowly, leading to more stable values at the cost of more "eye adaptation"-like effects (although this is mitigated somewhat by --hdr-scene-threshold). A value of 1.0 (the lowest possible) disables all averaging, meaning each frame's value is used directly as measured, but doing this is not recommended for "noisy" sources since it may lead to excessive flicker. (In signal theory terms, this controls the time constant "tau" of an IIR low pass filter)


--hdr-scene-threshold-low=<0.0..100.0>, --hdr-scene-threshold-high=<0.0..100.0>
The lower and upper thresholds (in dB) for a brightness difference to be considered a scene change (default: 5.5 low, 10.0 high). This is only relevant when --hdr-compute-peak is enabled. Normally, small fluctuations in the frame brightness are compensated for by the peak averaging mechanism, but for large jumps in the brightness this can result in the frame remaining too bright or too dark for up to several seconds, depending on the value of --hdr-peak-decay-rate.



I know that tonemapping is something we've been talking about a LOT in the last... well... 5 years (or more) and that there are different open source tonemapping implementation both in FFMpeg and in Avisynth like HDRTools and DGTonemap and I've been using HDRTools inside Avisynth for quite some time but what I wonder is: is there a way to tweak it to make it act on a scene by scene basis like in MPV? And is there a way to set how many frames have to be used for the scene-by-scene detection and a threshold to tweak how much change there has to be for a "scene change" to be considered as such?
In other words, can a dynamic scene by scene tonemapping be done in Avisynth?

jpsdr
7th August 2021, 13:19
I'll try to remember this for the days i'll be going back to work on new filters.
I've made, using 3 movies where i know SDR/HDR masters where done on the same time (this way i'm almost sure both use the same source film material and also maybe the same... i don't know how to translate... scan/digitalise film source material), 3 "database" with HDR <-> SDR information in XYZ format (get HDR pixel from HDR 4k BluRay, and get the same pixel on the SDR Bluray), try to "brutaly" feed them on neural network, but... need to be less "brutal" to be able to do somethig with them...
This was around 2 years ago, didn't work on it since, but, probably one day i'll try to work again on it.

joearmstrong
29th December 2021, 18:22
For optimal results I convert my videos to YV24 16-bit first using Avsresize ("YUV444P16").
In the description of HDRTools it says that converting to YV24 is done "quick" and for perfect results a resampler is recommended.
At the end of my script I convert to YV12 with dithered output. Are my settings correct or can you do the YUV conversion even better?

My example script:
Loadplugin("%startup_dir%\Apps\Plugins\AVS\avsresize.dll")
z_ConvertFormat(pixel_type="YUV444P16",dither_type="none")
ConvertYUVtoXYZ(Color=0,HDRMode=0,OOTF=false,OutputMode=2,threads=1)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true,Lhdr=50000.0,Lsdr=100.0,pColor=0,pct_ref=0.6,pct_ip=0.6,pct_wp=1.0,pct_sdr_skin=1.0,pct_hdr_skin=0.44,threads=1)
ConvertXYZtoYUV(Color=2,pColor=0,OOTF=false,threads=1)
z_ConvertFormat(pixel_type="YV12",dither_type="ordered")

jpsdr
30th December 2021, 10:38
No, i can't do better YV24<->YV12 convertion, for this, your settings are correct. But... Is there any reason you limits threads to 1 ? It will be the slowest.

joearmstrong
30th December 2021, 12:46
There is no specific reason - I just used the HDRTools-Settings from Ripbot264.

FranceBB
31st December 2021, 00:38
There is no specific reason - I just used the HDRTools-Settings from Ripbot264.

If you don't use Prefetch(), you can easily use the Jean Philippe threadpool which will be faster, so you can avoid to specify threads=1 and get a speed performance increase with no downside (other than an increase in RAM probably).

joearmstrong
31st December 2021, 13:06
Thanks for your tips! I wish you all a happy new year.

MeteorRain
22nd January 2022, 04:29
https://github.com/msg7086-forks/HDRTools

Ported to Linux64. Not sure if anyone did anything similar, but I recently need to work with Rec2020->Rec709 and wanted this to work under Linux, so I patched the code to make it work.

Deleted all thread pool stuff, so it's single threaded now.

Deleted 32-bit ASM.

Didn't touch much on the ASM code. I compiled it with UASM but you can find your favorite MASM tool if there's any other.

I had no idea what I was doing on the MS_ABI, but examining the stack space, all arguments are 1 QW deeper than they should be, so I let everything +8 and it magically works.

Most code paths are untested, so use at your own risk. PR welcome but I'm not going to spend time and efforts on it. Feel free to take the patch and polish on your own.

EDIT: Had issues on AVX2 CPUs, PR sent to fix a CPU flag condition check.

jpsdr
23rd February 2022, 18:40
Finaly sooner than expected, new version, see first post.

joearmstrong
1st June 2022, 08:35
Is it possible to implement ACES tonemapping in HDRTools? I see no way to use this curve in Avisynth even though it's now the current standard in tonemapping.

jpsdr
1st June 2022, 16:19
Maybe, but don't expect things soon. I'll have to search for informations about it.

joearmstrong
3rd June 2022, 11:59
I found the best overview of all the tonemappers with further links here:
https://github.com/tizian/tonemapper

Dogway
3rd June 2022, 12:36
Is it possible to implement ACES tonemapping in HDRTools? I see no way to use this curve in Avisynth even though it's now the current standard in tonemapping.

I plan to add it to TransformsPack, but not only the TM but the whole implementation. It's on the roadmap since the beginning since I already made a few tonemappers for Substance Painter a few years ago. The ACES I did then was the Stephen Hill version which is far from the real deal.

jpsdr
3rd June 2022, 15:57
The ACES function transfert is "simple" (using only one parameters, not alls), also it seems to be XYZ specific, so i'll do only an XYZ version, and i can use allready existing code function as base template, so a "maybe" with a good chance... ;)

jpsdr
14th June 2022, 18:48
Begin slowly to add ACES...

jpsdr
15th June 2022, 21:50
New version, see first post.
WARNING : Not tested ! (But chances of working properly are good)
Will not be able to test before a week at least, but make a release anyway in case others want to test.

StainlessS
16th June 2022, 00:01
Confidence is hi,
Love that !

Rock On Tommy, :)

-QfG-
16th June 2022, 10:35
Hi there,

using for testing this values:

Loadplugin("%startup_dir%\Apps\Plugins\AVS\HDRTools\hdrtools.dll")
ConvertYUVtoXYZ(Color=1, HDRMode=0)
ConvertXYZ_ACES_HDRtoSDR()
ConvertXYZtoYUV(pColor=1)
ConvertBits(8)

Colors are awesome, but the Brightness of the picture is to low. Any Ideas which Parameters i must set by ConvertXYZ_ACES_HDRtoSDR() ?

jpsdr
17th June 2022, 12:57
Everyone will say "Why the developper is asking this question....????" :scared:

But in fact, i've programmed the standard tonemap, but never used them (don't remember how i tested them).

Then, when i wanted to see, out of curiosity the results of ACES (and no, no testing yet, don't have access to PC with AVX & AVX2, which trigged me an issue never seen, but it's another story) result was black...
Tested Mobius, Hable, black... (well not totaly black, but very black).

Maybe the HDR -> SDR tonemap is not working as i thought...? :confused:

I thought, with my functions, if your input is standard PQ Blu-Ray, you do :

ConvertYUVtoXYZ(Color=0)
tonemapXYZ(pColor=0)
ConvertXYZtoYUV(pColor=0,Color=2)

For me, the XYZ input of a tonemap is HDR (so basicaly BT2100), and output is SDR (so basicaly BT709).

Except, as i said, when i tested, is was, almost, black.
So, what these tonemaps finaly realy do ?

Still don't give up on my first idea (maybe use Neural Network different way) of trying something with the 3 databases i've build.

FranceBB
17th June 2022, 23:46
But in fact, i've programmed the standard tonemap, but never used them (don't remember how i tested them).


I do, we tested them on TV Series, Sports and other movies as I was desperately eager to get something to work with HDR stuff back in 2018. We didn't have LUT support (no cube) and we had literally nothing to handle PQ contents in Avisynth which made me worry a lot, so I was like really really pushing to get this. I even remember some of the assets: one was Riviera Season 1 coming from a DNxHQX 12bit in HLG, one was Avengers Infinity War coming from an H.265 in PQ at 1000 nits 10bit, one was Naples vs Juventus, a Serie A game in XAVC Intra Class 300 in HLG 10bit and then there were some other assets I tested 'em on which I forgot.
There were some I had to make the tests on myself and we couldn't share, while we worked together on some others with the FTP (I saturated it that time and you sent me a reply shortly after hahahahha) and also some other of them were disclosed publicly here on Doom9 as far as screenshots are concerned: https://forum.doom9.org/showthread.php?t=175488&page=4






Tested Mobius, Hable, black... (well not totaly black, but very black).

Maybe the HDR -> SDR tonemap is not working as i thought...? :confused:


It is, but as per the tests I made in May 2018, I always suggest:


#BT2020 HLG HDR to BT709 SDR
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.1)
ConvertXYZtoYUV(pColor=0)

and

#BT2100 HDR PQ to BT709 SDR
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)
ConvertXYZtoYUV(pColor=0)




Except, as i said, when i tested, is was, almost, black.


Yeah, that's "normal".



So, what these tonemaps finaly realy do ?


They do what they are supposed to do, so what you wrote in the PDF, but only when properly tweaked. ;)


Still don't give up on my first idea (maybe use Neural Network different way) of trying something with the 3 databases i've build.

More than a neural network, please please please make them scene-aware, that would be amazing.
My idea from here is still valid: https://forum.doom9.org/showthread.php?t=182823

jpsdr
19th June 2022, 10:26
one was Avengers Infinity War coming from an H.265 in PQ at 1000 nits 10bit
Oh... That's one of the 3 movies i used to build my HDR -> SDR database for my NeuralNetwork first idea.

If i do something for now, it will unfortunately not be as complex as scene aware. Also, the database i've build don't have this kind of information... And even, maybe, database is a big word for it.

If i do something for now, it will be some kind of tonemap function in 1-exp(x) form, maybe keep the NN part to compute the parameters. If you're curious of the curves i have, i can send you excel sheets.

joearmstrong
19th June 2022, 17:23
Hi there,

using for testing this values:



Colors are awesome, but the Brightness of the picture is to low. Any Ideas which Parameters i must set by ConvertXYZ_ACES_HDRtoSDR() ?


I have the same question. With more brightness the converted video would look very good. I'm missing the exposure parameter from the other tonemapping curves.
Thank you for implementing ACES tonemap!

jpsdr
20th June 2022, 21:42
Didn't see any kind of exposure parameter in ACES description.
If it's just a multiply coeff factor, for now, you can use in that case ConvertXYZ_Scale_HDRtoSDR just before to multiply the input, or after to multiply the output.
It's true indeed that the others tonemap have exposure parameter.
Maybe i'll think to add it for a next release...

jpsdr
21st June 2022, 21:50
New version, see first post, still not fully tested... :D

Edit :
More tests done now, seems Ok, i'll update the complete plugins package soon.

jpsdr
23rd June 2022, 17:45
Here some result HDR (X axis) -> SDR (Y axis) curves extracted from my database.

It's clearly an a.(1-exp(-b.x)) formula.
http://jpsdr.free.fr/XBMC/HDR_SDR1.jpg
http://jpsdr.free.fr/XBMC/HDR_SDR2.jpg

joearmstrong
25th June 2022, 11:53
I'm trying the new exposure parameters in ACES. Anybody found good settings to recommend?

FranceBB
25th June 2022, 22:45
Sorry for not replying earlier, but I've been extremely busy at work.
Anyway, yeah, I'd love to see the results you get and the values of the training you're doing on the experimental neural network.

jpsdr
26th June 2022, 10:47
I may have not been clear enough... For now, i only built a database, and have an excel of curves like in post #194.
Throw data to a NN just "like that" didn't work. Also, i'm far far far from being a expert in NN, i'm more a noob in the field.
The NN idea may work, but with a little thinking... Like, as said in post #194, curves seems to follow a specific formula pattern, maybe the NN can find the a and b values.
Anyway, i'll PM you.

For now, i'm wondering what to do with this. As it can be seen in post #194, for the same HDR value, there is several SDR results.
For now, i have to think how to use this database, and for exemple, figure out if there is some kind of reproduce things. The Xsdr is strongly from Xhdr, but as for same Xhdr there is several Xsdr, others things may have, small effect, like Y and Z. Maybe something like, according formula of #194 : Xsdr=a(Yhdr,Zhdr,...?).(1-exp(-b(Yhdr,Zhdr,...?).Xhdr)
All curves show something interesting : "big belly" with 2 convergence points. 0, obvious, and at "the end". This is interesting property, help and reduce parameters exploration.

DTL
28th June 2022, 15:45
If you have a time can you look in this difference:

LoadPlugin("plugins_JPSDR.dll")
LoadPlugin("avsresize.dll")
LoadPlugin("fmtcavs.dll")

Function Convert422ToRGB24mon_lin_x4_HLG(clip c)
{
uc=UToY(c)
vc=VToY(c)
uc=UserDefined2ResizeMT(uc,src_left=0.001,uc.width, uc.height, b=105, c=0)
vc=UserDefined2ResizeMT(vc,src_left=0.001,vc.width, vc.height, b=105, c=0)
uc=SincLin2ResizeMT(uc, src_left=0, uc.width*2, uc.height, taps=8)
vc=SincLin2ResizeMT(vc, src_left=0, vc.width*2, vc.height, taps=8)
yuv444=CombinePlanes(c, uc, vc, planes="YUV", source_planes="YYY", pixel_type="YUV444P10")

# jpsdr_plugin
rgb_lin=ConvertYUVtoLinearRGB(yuv444,Color=0,HDRMode=2)
rgb_lin=RGBAdjust(rgb_lin,r=3,g=3,b=3)

# avsresize
#rgb_lin=z_convertformat(yuv444,pixel_type="rgbps", colorspace_op="2020ncl:std-b67:2020:l=>rgb:linear:2020:l", nominal_luminance=800)
#rgb_lin=RGBAdjust(rgb_lin,r=3,g=3,b=3)

#fmtconv
# rgb_lin=fmtc_matrix(yuv444,mat="RGB", mats="2020",fulls=false, fulld=false)
# rgb_lin=fmtc_transfer(rgb_lin,transs="hlg",transd="linear",bits=32,fulls=false, fulld=false)
# rgb_lin=RGBAdjust(rgb_lin,r=3,g=3,b=3)

rgb_lin=SincLin2ResizeMT(rgb_lin,rgb_lin.width*4, rgb_lin.height*4, taps=16)
#return z_ConvertFormat(rgb_lin, pixel_type="rgbp8", colorspace_op="rgb:linear:709:l=>rgb:709:709:l").ConvertToRGB()
#return fmtc_transfer(rgb_lin,transs="linear",transd="709",fulls=false, fulld=false).ConvertBits(8,fulls=true,fulld=false).ConvertToRGB()
return ConvertLinearRGBToYUV(rgb_lin,Color=2).ConvertToRGB24(matrix="PC.709")
}
plY=Blankclip(width = 10, height = 1, pixel_type="Y10").Expr("sx 0 == 509 sx 1 == 509 sx 2 == 509 sx 3 == 509 sx 4 == 509 sx 5 = 498 sx 6 = 446 sx 7 == 361 sx 8 == 292 276 ? ? ? ? ? ? ? ? ?")
plU=Blankclip(width = 5, height = 1, pixel_type="Y10").Expr("sx 0 == 270 sx 1 == 263 sx 2 == 330 sx 3 == 761 754 ? ? ? ?")
plV=Blankclip(width = 5, height = 1, pixel_type="Y10").Expr("sx 0 == 203 sx 1 == 224 sx 2 == 271 sx 3 == 832 821 ? ? ? ?")
tr=CombinePlanes(plY, plU, plV, "YUV", "YYY", pixel_type="YUV422P10")

sust_l=Blankclip(width = 4, height = 1, pixel_type="YUV422P10").Expr("sx 0 == 509 sx 1 == 509 sx 2 == 509 509 ? ? ?","sx 0 == 270 270 ?","sx 0 == 203 203 ?").PointResize(50,1)
sust_r=Blankclip(width = 4, height = 1, pixel_type="YUV422P10").Expr("sx 0 == 276 sx 1 == 276 sx 2 == 276 276 ? ? ?","sx 0 == 754 754 ?","sx 0 == 821 821 ?").PointResize(52,1)

StackHorizontal(sust_l,tr)
StackHorizontal(last,sust_r)
PointResize(width, 100)
# source finishes here, 75% green-magenta transient HLG 10bit 4:2:2

Convert422ToRGB24mon_lin_x4_HLG()


Results are:
https://i3.imageban.ru/out/2022/06/28/0ab51aeedca3f93c64ac6f487b474a3d.png

So the functions from plugins_JPSDR_v3_3_0 return a bit lower RGB levels and the shape of transient also a bit different from 2 others HDR converting plugins. What may cause this difference ?
I tried to calculate levels values at https://forum.doom9.org/showthread.php?p=1952556#post1952556

"my advice would bet to test these 2 settings : Color=0,HDRMode=2,HLGLw=800 and Color=0,HDRMode=1,HLGLw=800"

With HDRMode=2 the HLGLw adustment change nothig.
With HDRMode=1 the mostly closely looking green is with HLGLw=11000 (or may be about 11500) but RB channels at magenta become unbalanced.

"try with OOTF=false, it will ouput the displayed linear data.
But in that case you have to put also OOTF=false in ConvertLinearRGBToYUV."

This returns very dark image with HDRMode=1.
With

rgb_lin=ConvertYUVtoLinearRGB(yuv444,Color=0,HDRMode=2, OOTF=false, HLGLw=350)
return ConvertLinearRGBToYUV(rgb_lin,Color=2, OOTF=false).ConvertToRGB24(matrix="PC.709")

The sustained RGB looks mostly close to other plugins and green-magenta transient may be looks the mostly nicely (with much less dark stripe and ringing). So this HDR magic is so magic. How to connect this magic value HLGLw=350 with 'typical Lw' I still do not know.
https://i6.imageban.ru/out/2022/06/28/760f514040c5803cb74efedf501230ce.png

As I test in MS Paint with cut-paste region - in RGB24 the fmtconv and avsresize output looks perfectly matches between each other at both green and magenta sustained levels and transient between colours.

jpsdr
28th June 2022, 17:53
Don't have time unfortunately right now.
But, if you want, you can do :
If both others plugins produce same result, mix the YUV -> RGB and RGB -> YUV (for exemple z_ConvertFormat doing YUV -> RVB followed by fmtc_transfer doing RVB->YUV), check if output is still the same. If yes, revert the mix.
If both mix are Ok, now do the same mix with my plugin. This will eventualy allow to see (if it's the case) if difference is only on one part.
If, for exemple, ConvertYUVtoLinearRGB followed by z_ConvertFormat or fmtc_transfer produces the same result than a complete conversion with another plugin, it meens it's ConvertLinearRGBToYUV which behaves differently.

jpsdr
20th November 2022, 15:08
New version, see first post.

Alexkral
20th November 2022, 16:45
May I ask why the default pct_hdr_skin for PQMode in ConvertXYZ_BT2446_C_HDRtoSDR is set to 0.44? I haven't seen anything in ITU-R BT.2408 regarding this, only about HLG.

jpsdr
20th November 2022, 19:03
I don't remember exactly... But if indeed there is nothing in BT.2408, i probably "estimate" it using informations from several BT, and i probably choose this value because "it seems not too bad".
There is probably some curve or anything which lead me to this choice.

Alexkral
20th November 2022, 20:45
Ah ok, I think I know why you did it. 44% PQ equals 50 nits, same as 50% HLG. It doesn't seem too bad indeed.

Alexkral
20th November 2022, 22:49
I found something funny looking at your code, not that it's in the least important, but I think I should let you know. You use 2.404 as the power in the BT.1886 EOTF, but the last 4 is actually a footnote :D. It's not that it's important as I say, but when I found the reason it made me laugh.

Also, I'm not too sure that the inverse OETF should be used, ITU repeats all over the place something that seems to imply this opinion, but I can understand why you do it.

jpsdr
21st November 2022, 01:43
Thanks for the 2.404, i'll change this later. My guess is that at the time i read it, i didn't see the footnotes and thought it was misprint... :D

jpsdr
21st November 2022, 19:30
New version, see first post.

jpsdr
26th February 2023, 12:36
New version, see first post.

LouieChuckyMerry
4th June 2023, 21:15
First, many thanks jpsdr for all your effort :) .

I was gifted a UHD Blu-ray but don't have a 4K TV, so I figured I'd shrivel it to 1080p using AviSynth after color converting and resizing losslessly with VirtualDub2. Unfortunately, after hours of effort, I can't figure out how to tonemap BT.2020 to BT.709. I'm here because it seems to me that that's what your HDRTools plugin is for but using

ConvertYUVToXYZ(Color=1)
ConvertXYZToYUV(pColor=1)

as in your example runs fine but appears to do nothing. Please, what am I missing?

Ahhh, a video sample (https://www.mediafire.com/file/tjhzaxbdhkfaw7g/TestClip2%255B2160p%255D.7z/file).

FranceBB
5th June 2023, 12:03
Unfortunately, after hours of effort, I can't figure out how to tonemap BT.2020 to BT.709.

Try this to go from BT2020 HDR PQ to BT709 with HDRTools:

ConvertBits(16)

ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)

ConvertXYZtoYUV(pColor=0)

Converttoyuv420()

If the conversion is fine but looks a bit off, change Reinhard's parameters accordingly 'till you're ok with the end result.

LouieChuckyMerry
6th June 2023, 00:48
Thanks for your reply, FranceBB. Your suggested script runs fine but doesn't appear to change the video in any way; i.e., the output looks the same as the input, dull and muted (the same-looking result as the script I posted above).

Boulder
6th June 2023, 07:05
If you have an nVidia GPU available, you can use DGHDRtoSDR to do the grading in one simple step. DGIndexNV can be used to tune the parameters per source.

FranceBB
6th June 2023, 11:58
Thanks for your reply, FranceBB. [...] the output looks dull and muted

Well, I wouldn't call it "Dull and Muted", but ok xD

Anyway, here's a comparison:

https://i.imgur.com/oCUGCkD.png


This is done with the following script:


FFVideoSource("D:\TestClip2[2160p].mkv")
SinPowerResize(848, 480)
original=last.Text("BT2020 HDR PQ 1043 nits - Original")

ConvertBits(16)
hbd=last
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - Reinhard tonemapping")
tonemapped=last


ConvertToPlanarRGB(hbd, matrix="Rec2020", interlaced=false)
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=true)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - FranceBB LUT")
lutted=last


StackVertical(original, tonemapped, lutted)



If you like the last one, then I strongly suggest you to check this out: https://forum.doom9.org/showthread.php?t=176091

LouieChuckyMerry
7th June 2023, 01:58
Boulder: Thanks for your reply. I do have an nVidia GPU and a license for DGIndexNV, so I'll attack your suggestion ASAP.
_____________

FranceBB: Thanks again for your help. Your latest suggestion looks good but I'll need a goodly stretch of free time to wrap my head around it.
_____________

I should have time this weekend to work on the above, possibly (but doubtfully) earlier. I really appreciate the help :) .
_____________

Edit: FranceBB: I took a quick look at your last link and, wow, that's really cool! Of course, I understand it intellectually but not really any of the details :o .

jpsdr
20th November 2023, 21:52
New version, see first post, but nothing big...

rgr
18th March 2024, 09:35
ConvertToPlanarRGB(hbd, matrix="Rec2020", interlaced=false)
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=true)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - FranceBB LUT")
lutted=last


StackVertical(original, tonemapped, lutted)
[/CODE]


If you like the last one, then I strongly suggest you to check this out: https://forum.doom9.org/showthread.php?t=176091

The latter worked great when playing the script through MPC-HC, but after conversion through ffmpeg it's still HDR -- there must be something missing in the script somewhere.


Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference fra : 4 frames
Codec ID : V_MPEG4/ISO/AVC
Duration : 3 h 0 min
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Writing library : x264 core 164 r3179 12426f5
Default : No
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.601



ffmpeg sets such data in the output:
Stream #0:0: Video: h264 (H264 / 0x34363248), yuv420p(tv, smpte170m/bt2020/smpte2084, progressive), 1920x1080, q=2-31, 23.98 fps, 1k tbn

FranceBB
18th March 2024, 10:35
Welcome to the world of frame properties, rgr!
No, jokes aside, it's not actually HDR but the reason why ffmpeg is reading it as HDR is that the frame properties are not updated.
When I wrote the script initially, we were in simpler times, when Avisynth only had the good old clip properties.

Anyway, to signal the right properties to ffmpeg you need to set them manually, so your script would become:


- For HDR Tools


#Indexing PQ source
video=LWLibavVideoSource("D:\TestClip.mxf")
audio=LWLibavVideoSource("D:\TestClip.mxf")
AudioDub(video, audio)

#Screw frame properties
propclearall()

#Bring everything to 16bit planar
ConvertBits(16)

#From YUV to XYZ with 16bit precision
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)

#BT2020 PQ to BT709 SDR tonemapping in XYZ with 16bit precision
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)

#From XYZ to YUV with 16bit precision
ConvertXYZtoYUV(pColor=0)

#Conversion to YUV 4:2:0 with 16bit precision
ConverttoYUV420(matrix="Rec709", interlaced=false)

#Dithering down to 8bit with the Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)

#Limiter TV Range 0.0 - 0.7V
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)

#Setting frame properties to make FFMpeg happy
propSet("_FieldBased", 0) #progressive
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709




- For LUTs



#Indexing PQ source
video=LWLibavVideoSource("D:\TestClip.mxf")
audio=LWLibavVideoSource("D:\TestClip.mxf")
AudioDub(video, audio)

#Screw frame properties
propclearall()

#Bring everything to 16bit planar
ConvertBits(16)

#From YUV to RGB with 16bit precision
ConvertToPlanarRGB(matrix="Rec2020", interlaced=false)

#From BT2020 PQ to BT709 SDR with 16bit precision and tetrahedral interpolation
Cube("C:\Program Files (x86)\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=1, interp=1)

#Conversion to YUV 4:2:0 with 16bit precision
ConverttoYUV420(matrix="Rec709", interlaced=false)

#Dithering down to 8bit with the Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)

#Limiter TV Range 0.0 - 0.7V
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)

#Setting frame properties to make FFMpeg happy
propSet("_FieldBased", 0) #progressive
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709




Needless to say, I hate frame properties.
Frame properties have their own utility in the sense that we can now tell other things outside of Avisynth (like the filter_builder in FFAStrans, FFMpeg, MPV etc) what we're outputting from Avisynth, but the problem is that not every function sets them correctly, so you almost always end up with the wrong ones. An easy workaround is to get rid of them all, always, at the very beginning, right after indexing, write the script as you're used to back when Avisynth didn't have them, then populate the right ones manually at the very end.
This is how I've done it for all the supply chains at work anyway, while for my personal stuff at home I use x264/x265 directly which don't really give a crap about frame properties so I'm safe from this.

rgr
18th March 2024, 15:26
Yes, I just found out.
If it already exists, it's a pity it doesn't have a pixel aspect ratio.

I also found in my notes:
"Color primaries" had an effect only on Quick Time...
"Transfer characteristics" did not have an effect on any player.
"Matrix coefficients" was the one that mattered in proper BT.601/BT.709 reproduction...

:)

Atlantis
28th April 2024, 08:52
I'm using staxrip to do HDR to SDR, it gives these default values.

ConvertYUVtoXYZ(Color=0, HDRMode=0, OOTF=false, OutputMode=2)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true, Lhdr=10000, Lsdr=100.0, pColor=0)
ConvertXYZtoYUV(Color=2, pColor=0, OOTF=false, OutputMode=2)
ConvertBits(8)

Things look good except the whites are crushed and too much contrast. I played with Lhdr and increasing it gives better results.
I go to the point Lhdr=17000 which is kind of the sweet spot. Now I'm 90% happy with the image.

There are still some scenes where the contrast could be lower for the highlights. I can't go up or down anymore with Lhdr.
What are some other things, values I can tweak to get a better result? I don't want complicated scripts, just a simple thing.

Atak_Snajpera
28th April 2024, 14:24
Try this


ConvertYUVtoXYZ(Color=0,HDRMode=0,OOTF=false,OutputMode=2)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true,Lhdr=50000.0,Lsdr=100.0,pColor=0,pct_ref=0.6,pct_ip=0.6,pct_wp=1.0,pct_sdr_skin=1.0,pct_hdr_skin=0.44)
ConvertXYZtoYUV(Color=2,pColor=0,OOTF=false)
ConvertBits(8)

These values emulate tonemapping in MadVR
https://forum.doom9.org/showthread.php?p=1893684#post1893684

Atlantis
28th April 2024, 16:09
Thank you, I will check to see. Any value that I changed in ConverXYZ_BT2446_C_HDRtoSDR had no effect at all except Lhdr!

tormento
17th October 2024, 15:50
Is there any way to have gamma-aware internal resizing?

I read this (https://forum.doom9.org/showthread.php?p=1722300) thread and it's a bit confusing to me.

Is

ConvertYUVtoLinearRGB()
Do_resample()
ConvertLinearRGBtoYUV()

enough?

DTL
20th October 2024, 23:00
In the modern complex world it is no more simple gamma transform but much more complex. So it may be better to write about resizing in linear domain. You may or may not get benefit with resizing in linear because there is no common standards about preparation of digital data for resize in linear or (system) transform domain. Also any conversion to and from subsampled chroma will damage your perfectly mastered digital data too.

You may get some benefit if you prepare your content in linear domain and also your display resize in linear domain. But if you prepare digital data for unknown users with unknown display resizers - it may not work as expected. So it is better to test best resize domain with your own displays if you prepare content for yourself. If you prepare for unknown users - may be better to resize in transform domain (because I think many displays are not doing resize in linear domain).

Your downsize operation is compression and displaying upsize is decompression operations and they must match to get perfect results (same as you compress/downsize with SinPow/UserDefined2 resize and master monitor with SincResize or SincLin2Resize). You can simulate with AVS scripting how much will be distortions if resize/codec domains are not match. But do not go to ugly subsampled chroma in between - it will damage irreversibly.

Also with HDR transform domains remember to re-transform to scene linear light to get correct linear data. Also see thread about usage of HDRtools in attempt to resize in linear domain - https://forum.doom9.org/showthread.php?t=183224 .

tormento
21st October 2024, 11:03
In the modern complex world it is no more simple gamma transform but much more complex.
Thanks for your kind and well argued answer.

My doubts arose both for gamma content but above all for HLG one, where the domain is "squished" in different ways on different parts. What could happen if we apply noise reduction that is not aware that the light part and the dark ones are not linearly represented? I tend to leave the PQ to HLG transformation as the last one but, as my computer is getting really slow with last filters, I resize the source directly in the zlib, such as:

z_ConvertFormat(width=1920, height=800, pixel_type="RGBP16", colorspace_op="2020:st2084:2020:limited=>rgb:st2084:2020:full", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)

DGCube("D:\Programmi\Media\AviSynth+\cube\1a_PQ1000_HLG_mode-nar_in-nar_out-nar_nocomp.cube", in="full", lut="full", out="full")

z_ConvertFormat(pixel_type="YUV420P10", colorspace_op="rgb:std-b67:2020:full=>2020:std-b67:2020:limited", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)

How will the subsequent filters will behave with something that is not even resembly linear?

DTL
21st October 2024, 13:27
Modern HDR transfer curvers are much more non-linear in comparison with gamma 2.2/0.45 of old SDR systems so making resize in HDR transfer domains may distort data more. But as we also do not have any standrard for display scaler - we can not say if resizing in linear or transfer domain is correct or not. With non-linear display scalers things may become even more complex and unpredictable.

"What could happen if we apply noise reduction that is not aware that the light part and the dark ones are not linearly represented?"

If noise deviation is not too large - the typical blocks blending process of MDegrain operates at close parts of transfer curve and possible distortions expected to be not very big. But if you try to process something like 4K-8K of 35mm film scan (silver black and white even worse) - it may be additional source of distortions. So it also depends on your source. But HDR linear require float32 samples to handle all range without too large quantization noise and mvtools may not work (or work good) with float32 samples. So maximum is 16bit integer and it is good only for SDR linear and partially for HLG HDR.

coolgit
30th December 2024, 22:36
Why is there a t missing in ConverXYZ_BT2446_C_HDRtoSDR when it should be ConvertXYZ_BT2446_C_HDRtoSD?

jpsdr
31st December 2024, 15:37
An error, maybe ? :D

jpsdr
20th July 2025, 10:18
New version, see first post.

jpsdr
25th August 2025, 12:29
Just for the record, as integer pictures (8 to 16 bits) use lookup tables, the AVX512 added has no effect.
I think there will be a small effect on float pictures with fastmode=true, and the most significant effect will be on float pictures with fastmode=false.

jpsdr
28th August 2025, 11:12
New version, see first post.
I made tests, but not intensive/exhaustive, so if any issue occurs, report here.

jpsdr
29th November 2025, 12:06
Update first page, minor changes.

AnonymousPeridot
21st February 2026, 04:18
Hi all, I've been playing around with this tool for sometime and I can't seem to accomplish what I want, so maybe you guys can help. I have a file that was incorrectly converted. The movie was already in bt.2020 but when the licensor brought it state side they incorrectly compressed it down to DCI.P3 inside a bit.2020 container, dulling the colors compared to foreign releases. Is there any way to convert the DCI.P3 back to the original bt.2020? I don't see DCI.P3 as an option in the color matrixes. Thank you for your consideration.

jpsdr
21st February 2026, 10:30
There is not direct named matrix option like "DCI.P3", you have to use the chromaticity coordinates parameters (check the readme) :

Rx,Ry,Gx,Gy,Bx,By,Wx,Wy -
These parameters allow to configure the chromaticity coordinates Red point, Green point, Blue point
and White point. If not set, the values defined in the BT.xxxx of the Color parameter are used.


So if you want to be sure of the proper (or specifix) matrix used, set these parameters.

AnonymousPeridot
22nd February 2026, 16:36
There is not direct named matrix option like "DCI.P3", you have to use the chromaticity coordinates parameters (check the readme) :

Rx,Ry,Gx,Gy,Bx,By,Wx,Wy -
These parameters allow to configure the chromaticity coordinates Red point, Green point, Blue point
and White point. If not set, the values defined in the BT.xxxx of the Color parameter are used.


So if you want to be sure of the proper (or specifix) matrix used, set these parameters.

Thank you so much that is exactly what I needed! After Googling the correct coordinates it fixed the colors. However it did show another issue with this film. It would appear as though they upped the brightness when converting it to Dolby Vision, and because of that it has effected the standard HDR 10 layer as well. Is there any way to possibly correct this also?

jpsdr
22nd February 2026, 17:55
Sorry, no idea, my tools are just for converting. For correcting, you have to use other filters i think.

AnonymousPeridot
23rd February 2026, 00:51
Sorry, no idea, my tools are just for converting. For correcting, you have to use other filters i think.

No worries it's all good your tool has already helped tremendously with just correcting the colors. Thank you.