HDR -> SDR conversion
Re: HDR -> SDR tonemapping
I'm recommending a small change to the Avisynth+ script that improves things a bit. Note the ConvertBits() call:
loadplugin("DGDecodeNV.dll")
loadplugin("DGTonemap.dll")
loadplugin("avsresize.dll")
SetFilterMTMode("z_ConvertFormat", MT_MULTI_INSTANCE) # May not be needed.
DGSource("THE GREAT WALL.dgi",fulldepth=true)
ConvertBits(10) # use 12 for 12-bit
z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:l", dither_type="none")
# Choose one of these:
DGReinhard()
#DGHable()
z_ConvertFormat(pixel_type="YV12",colorspace_op="rgb:linear:2020:l=>709:709:709:l",dither_type="ordered")
prefetch(4)
loadplugin("DGDecodeNV.dll")
loadplugin("DGTonemap.dll")
loadplugin("avsresize.dll")
SetFilterMTMode("z_ConvertFormat", MT_MULTI_INSTANCE) # May not be needed.
DGSource("THE GREAT WALL.dgi",fulldepth=true)
ConvertBits(10) # use 12 for 12-bit
z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:l", dither_type="none")
# Choose one of these:
DGReinhard()
#DGHable()
z_ConvertFormat(pixel_type="YV12",colorspace_op="rgb:linear:2020:l=>709:709:709:l",dither_type="ordered")
prefetch(4)
Re: HDR -> SDR tonemapping
Do you require any testing or comparisons done with the change?
Re: HDR -> SDR tonemapping
No thank you, gonca, I've tested it and confirmed to my satisfaction that it works a little better. If you stumble across anything, though, please report it.
I got an email from someone thinking there is no difference between fulldepth=true and fulldepth=false. The difference between 8 and 10 bits is just 2 bits, i.e., a maximum difference of 4. So if you just look at the frames, you may not see a gross difference, especially if there are no large flat areas where you would see banding. However, if you do a subtract between the two and then do levels in VirtualDub(2) and preview/sample frame, you can see the spike of differences that is 4 pixels wide. If you zoom in the two ends of the Input levels slider to just bracket the spike, then you can see the detail that is being retained in those lower two bits. Those 2 bits break what would have been a difference of 1 to a difference of 4, or to say it another way, the granularity is improved by a factor of 4, and that's why banding is significantly reduced.
I got an email from someone thinking there is no difference between fulldepth=true and fulldepth=false. The difference between 8 and 10 bits is just 2 bits, i.e., a maximum difference of 4. So if you just look at the frames, you may not see a gross difference, especially if there are no large flat areas where you would see banding. However, if you do a subtract between the two and then do levels in VirtualDub(2) and preview/sample frame, you can see the spike of differences that is 4 pixels wide. If you zoom in the two ends of the Input levels slider to just bracket the spike, then you can see the detail that is being retained in those lower two bits. Those 2 bits break what would have been a difference of 1 to a difference of 4, or to say it another way, the granularity is improved by a factor of 4, and that's why banding is significantly reduced.
Re: HDR -> SDR tonemapping
Okay.
I asked you before if fulldepth=True operated the same as fulldepth=false on 8 bits sources.
I believe you said yes, so I always include True.
10 bit sources get passed as 10 bit, 8 bit sources get passed as 8 bit
I realize that on some sources 8 or 10 bit makes little difference, but on some the extra 2 bits can make a lot of difference on detail and color retention.
One question though
The ConvertBits(10) call comes after DGSource(xxx, fulldepth=True)
Shouldn't the output of DGSource already be 10 bit?
I do realize that if the source is 8 bit running it in 10 bit can be beneficial, especially in terms of banding, but the source should already be 10 bit as this should be a hdr source.
I am not questioning you so much as I am asking for info/knowledge on the why
Either way thank you for your continuous efforts and improvements to your software
I asked you before if fulldepth=True operated the same as fulldepth=false on 8 bits sources.
I believe you said yes, so I always include True.
10 bit sources get passed as 10 bit, 8 bit sources get passed as 8 bit
I realize that on some sources 8 or 10 bit makes little difference, but on some the extra 2 bits can make a lot of difference on detail and color retention.
One question though
The ConvertBits(10) call comes after DGSource(xxx, fulldepth=True)
Shouldn't the output of DGSource already be 10 bit?
I do realize that if the source is 8 bit running it in 10 bit can be beneficial, especially in terms of banding, but the source should already be 10 bit as this should be a hdr source.
I am not questioning you so much as I am asking for info/knowledge on the why
Either way thank you for your continuous efforts and improvements to your software
Re: HDR -> SDR tonemapping
DGSource(fulldepth=true) outputs 16-bit always, with the extra bits zeroed, i.e., for 10-bit source, the lower 6 bits are zero. So the ConvertBits() call gets rid of the extra lower bits. I did a subtract+levels test between the frames with and without the ConvertBits() and was able to see some extra detail being retained with the ConvertBits().
I welcome being questioned because I am a seeker after truth and things should stand up to scrutiny and healthy skepticism.
Off to the pool!
I welcome being questioned because I am a seeker after truth and things should stand up to scrutiny and healthy skepticism.
Off to the pool!
Re: HDR -> SDR tonemapping
Quick 2 questions
On hdr to hdr cases would you recommend using ConvertBits(10) for 10 bit sources to 10 bit output
On sdr to sdr cases would you recommend using ConvertBits(8) or fulldepth=False (8bit source to 8 bit output)
On hdr to hdr cases would you recommend using ConvertBits(10) for 10 bit sources to 10 bit output
On sdr to sdr cases would you recommend using ConvertBits(8) or fulldepth=False (8bit source to 8 bit output)
Re: HDR -> SDR tonemapping
It depends on what your encoder wants to receive. Otherwise, it doesn't matter, unless you doing some gamma adjustment or something unusual like that. In that case, umm, it depends.
Neither one is necessary as 8-bit will always be delivered as 8-bit. Anyway, fulldepth=false by default.On sdr to sdr cases would you recommend using ConvertBits(8) or fulldepth=False (8bit source to 8 bit output)?
Re: HDR -> SDR tonemapping
Do you know how to use ConvertBits() in VS? Is it doable?
Would fmtconv work as well as ConvertBits()?
I guess I can always convert my scrips to avs+ again
Would fmtconv work as well as ConvertBits()?
I guess I can always convert my scrips to avs+ again
Re: HDR -> SDR tonemapping
fmtc can do bits conversion. If you don't want to convert with fmtc, internal resizers can perform bits conversion as well:
Code: Select all
from vapoursynth import core, YUV420P16
...
clip = core.resize.Point(clip, format=YUV420P16)
PC: RTX 2070 | Ryzen R9 5950X (no OC) | 64 GB RAM
Notebook: RTX 4060 | Ryzen R9 7945HX | 32 GB RAM
Notebook: RTX 4060 | Ryzen R9 7945HX | 32 GB RAM
Re: HDR -> SDR tonemapping
Thank you
ConvertBits apparently drops the padded (zeroed) bits
fmtc dithers down
Would this affect the quality?
How do the internal resizers function, dithering, dropping padded zeroes?
ConvertBits apparently drops the padded (zeroed) bits
fmtc dithers down
Would this affect the quality?
How do the internal resizers function, dithering, dropping padded zeroes?
Re: HDR -> SDR tonemapping
Now, that is a great question, because if they are dithering down, then the "extra detail" I saw may be just dithering. I will check the Avisynth+ and Vapoursynth source code today.
Re: HDR -> SDR tonemapping
ConvertBits(8) just drops the Least significant bit, so you need to add dither=0 or 1, whatever method you want to use there.
PC: RTX 2070 | Ryzen R9 5950X (no OC) | 64 GB RAM
Notebook: RTX 4060 | Ryzen R9 7945HX | 32 GB RAM
Notebook: RTX 4060 | Ryzen R9 7945HX | 32 GB RAM
Re: HDR -> SDR tonemapping
According to this link the default is to not add dither
http://avisynth.nl/index.php/ConvertBits
dither = -1
http://avisynth.nl/index.php/ConvertBits
dither = -1
Re: HDR -> SDR tonemapping
You beat me to it, I was just looking over there. That's what we want, no dithering. Thanks, guys.
Re: HDR -> SDR tonemapping
That doesn't convert to 10-bit. I think this is correct:DJATOM wrote: ↑Thu Apr 19, 2018 4:42 amCode: Select all
clip = core.resize.Point(clip, format=YUV420P16)
import vapoursynth as vs
core = vs.get_core()
...
clip = core.resize.Point(clip, format=vs.YUV420P10)
...
Re: HDR -> SDR tonemapping
Code: Select all
clip = core.resize.Point(clip, format=vs.YUV420P10)
Code: Select all
clip = core.resize.Point(clip, format=vs.YUV420P10, dither_type=none)
Re: HDR -> SDR tonemapping
dither_type none is the default.
Re: HDR -> SDR tonemapping
Thank you
I didn't see that mentioned in the docs I looked at,
at least not in a way that I understood
I didn't see that mentioned in the docs I looked at,
at least not in a way that I understood
Re: HDR -> SDR tonemapping
Thanks
Re: HDR -> SDR tonemapping
You are welcome. It's always my pleasure.
Re: HDR -> SDR tonemapping
So, we have established that we need to do the 2020->709 conversion and the tonemapping all together on the GPU if we expect CUDA to give us good performance gains. So I have been researching how to do that. Here is my tentative plan for the 2020->709 part. If it pans out then tonemapping can be added. Please advise if I am planning anything stupid. I'm a bit of a dilettante in the colorimetry area, so...
Code: Select all
Convert HDR 10-bit in YUV420P16 to YV12
Step 1: Convert to P10.
Strip lower 6 bits (zeros)
Step 2: Convert to RGB
R = 1.164(Y-64) + 1.596(V-512)
G = 1.164(Y-64) - 0.813(V-512) - 0.392(U-512)
B = 1.164(Y-64) + 2.017(U-512)
Step 3: Linearize
R = R * R
G = G * G
B = B * B
Step 4: Map the gamut using inverse of rec 2087 matrix
R 1.6605 -0.5877 -0.0728 R
G = -0.1246 1.1330 -0.0084 * G
B -0.0182 -0.1006 1.1187 B
709 2020
Step 5: Gamma correct
R = sqrt(R)
G = sqrt(G)
B = sqrt(B)
clamp as needed
Step 6: Convert to 8-bit YUV
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
This can now be returned as YV12 for Avsynth+.
Re: HDR -> SDR tonemapping
I am a complete rookie at the color thingy, but based on all the stuff I have read on the topic, before my eyes glazed over, your approach seems to be spot on from the format (2020 to 709) to the clamping of the levels to accommodate the 8 bit standard
Re: HDR -> SDR tonemapping
OK, good to hear. Of course, there are a lot of ways to map the out-of-gamut values back into range, but it seemed sensible to me to just reverse what is given for 709->2020 in REC 2087.
https://www.itu.int/dms_pubrec/itu-r/re ... !PDF-E.pdf
https://www.itu.int/dms_pubrec/itu-r/re ... !PDF-E.pdf
Re: HDR -> SDR tonemapping
It does appear to be a logical approach
If
A>black box >B
then
B> inverse black box >A
Only in this case the black box is a known algorithm
If
A>black box >B
then
B> inverse black box >A
Only in this case the black box is a known algorithm