Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
![]() |
#1 | Link |
Registered User
Join Date: Oct 2015
Posts: 54
|
HDR10 to SDR with Hable tone-mapping
Hi!
This is a basic script for hdr to sdr conversion, I'm not sure i've used the hable tonemapping in the right way. it's a tone mapping operator used for videogames but it seems good even for videos. Code:
import vapoursynth as vs core = vs.get_core() c = core.ffms2.Source(source = 'path/to/file') source_peak=1200 #set manually c=core.resize.Bilinear(clip=c, format=vs.YUV444PS, range_in_s="limited", range_s="full",chromaloc_in_s="center",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.RGBS, matrix_in_s="2020ncl", range_in_s="full",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.RGBS, transfer_in_s="st2084", transfer_s="linear",dither_type="none", nominal_luminance=source_peak) exposure_bias=source_peak/100 #hable/uncharted tone mapping tm = core.std.Expr(c, expr="x {exposure_bias} * 0.15 x {exposure_bias} * * 0.05 + * 0.004 + x {exposure_bias} * 0.15 x {exposure_bias} * * 0.50 + * 0.06 + / 0.02 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)#12=1200 nits / 100 nits w = core.std.Expr(c, expr="{exposure_bias} 0.15 {exposure_bias} * 0.05 + * 0.004 + {exposure_bias} 0.15 {exposure_bias} * 0.50 + * 0.06 + / 0.02 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)# c = core.std.Expr(clips=[tm,w], expr=" x 1 y / * ",format=vs.RGBS) #c=core.fmtc.primaries(clip=c, prims="2020", primd="709") c=core.resize.Bilinear(clip=c, format=vs.RGBS, primaries_in_s="2020", primaries_s="709",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.RGBS, transfer_in_s="linear", transfer_s="709",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.YUV420P8, matrix_s="709", range_in_s="full",range_s="limited",chromaloc_in_s="center") c.set_output() I only have some hdr video sample downloaded so I can't test exhaustively this script, but it produces reasonably good output. There's at least one issue: I use the resizer in the core for conversion from bt.2020 to bt.709 and from the github "Note that "z" is not a color management system and should not be used to perform drastic contrast or gamut reduction, such as BT.2020 to BT.709." Screenshot before/after: http://screenshotcomparison.com/comparison/203274 http://screenshotcomparison.com/comparison/203275 http://screenshotcomparison.com/comparison/203276 |
![]() |
![]() |
![]() |
#2 | Link |
Cary Knoop
Join Date: Feb 2017
Location: Newark CA, USA
Posts: 397
|
Super!
One quick question, going from full to limited range is designed to capture out of range values (WTW and BTB) and bring them into legal or is the script designed for full range video to be converted to limited range? Most video obviously uses limited range with the exception of 4:4:4 sources. It would be great to have an "up" conversion from SDR to HDR as well. |
![]() |
![]() |
![]() |
#3 | Link |
Registered User
Join Date: Dec 2002
Posts: 5,565
|
Neither. Both input of first filter as well as output of last filter are limited range.
I wonder if and how to handle e.g. color coordinates. The script only asks for peak luminance while HDR(10) metadata looks something like this: Code:
| + Video colour information | + Colour matrix: 9 | + Colour range: 1 | + Colour transfer: 16 | + Colour primaries: 9 | + Video colour mastering metadata | + Max luminance: 1000 | + Min luminance: 0.001 | + Red colour coordinate x: 0.68 | + Red colour coordinate y: 0.31996 | + Green colour coordinate x: 0.26494 | + Green colour coordinate y: 0.68996 | + Blue colour coordinate x: 0.15 | + Blue colour coordinate y: 0.05998 | + White colour coordinate x: 0.3127 | + White colour coordinate y: 0.32896 Last edited by sneaker_ger; 12th March 2017 at 18:24. |
![]() |
![]() |
![]() |
#4 | Link | |
Registered User
Join Date: Oct 2015
Posts: 54
|
Quote:
Bt2020 is the standard for hdr10 Maybe i can try to pass all the info from the metadata Last edited by age; 12th March 2017 at 18:33. |
|
![]() |
![]() |
![]() |
#6 | Link |
Registered User
Join Date: Oct 2015
Posts: 54
|
Right :-)
I think tone mapping is needed for hdr to sdr conversion, for sdr to hdr up conversion is needed an inverse tone mapping algo but i can't find such algorithm on google. Last edited by age; 12th March 2017 at 19:00. |
![]() |
![]() |
![]() |
#7 | Link | |
Registered User
Join Date: Oct 2016
Posts: 56
|
Quote:
https://cloud.mail.ru/public/2iEk/CiyUARGZy |
|
![]() |
![]() |
![]() |
#8 | Link | |
Registered User
Join Date: Nov 2004
Location: Poland
Posts: 2,834
|
Quote:
http://www.mysterybox.us/blog/2016/1...delivering-hdr and than use free Resolve and compare your result to Resolve. |
|
![]() |
![]() |
![]() |
#9 | Link | |
Registered User
Join Date: Nov 2004
Location: Poland
Posts: 2,834
|
Quote:
MadVR does it quite well, can you still some math from there? Last edited by kolak; 14th March 2017 at 12:14. |
|
![]() |
![]() |
![]() |
#11 | Link |
Registered User
Join Date: Apr 2002
Location: Germany
Posts: 4,926
|
Looks nice at least not like such a over saturated mess
![]() https://www.youtube.com/watch?v=vI91heLv_v4 sorry i know it gets old but i find this a master example of how your HDR->SDR tone mapping shouldn't endup ![]() You should also try https://knarkowicz.wordpress.com/201...mapping-curve/
__________________
all my compares are riddles so please try to decipher them yourselves :) It is about Time Join the Revolution NOW before it is to Late ! http://forum.doom9.org/showthread.php?t=168004 Last edited by CruNcher; 15th March 2017 at 01:47. |
![]() |
![]() |
![]() |
#13 | Link |
Registered User
Join Date: Oct 2015
Posts: 54
|
Thank you all for your suggestion and the hdr samples.
Well I've discovered some interesting things.... First, a better version of the hable tonemapping that gives better contrast,brightness and saturation. http://screenshotcomparison.com/comparison/203550 I've tried different algorithms, the aces tonemapping too but I don't like it very much. Here a good link for a lot of open source tm operators : https://github.com/tizian/tonemapper.../src/operators And a different version of aces: https://github.com/keijiro/PostProce...emapping.cginc new script with correct parameters Code:
import vapoursynth as vs core = vs.get_core() c = core.ffms2.Source(source = 'C:/bla') source_peak=1000 #set manually LDR_nits=100 #set 150 or 200 for lowering the brightness c=core.resize.Bilinear(clip=c, format=vs.YUV444PS, range_in_s="limited", range_s="full",chromaloc_in_s="center",dither_type="none") c=core.resize.Bicubic(clip=c, format=vs.RGBS, matrix_in_s="2020ncl", range_in_s="full",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.RGBS, transfer_in_s="st2084", transfer_s="linear",dither_type="none", nominal_luminance=source_peak) exposure_bias=(source_peak/LDR_nits) #hable tone mapping correct parameters #["A"] = 0.22 #["B"] = 0.3 #["C"] = 0.1 #["D"] = 0.2 #["E"] = 0.01 #["F"] = 0.3 #["W"] = 11.2 #((x * (A*x + C*B) + D*E) / (x * (A*x+B) + D*F)) - E/F" tm = core.std.Expr(c, expr="x {exposure_bias} * 0.22 x {exposure_bias} * * 0.03 + * 0.002 + x {exposure_bias} * 0.22 x {exposure_bias} * * 0.3 + * 0.06 + / 0.01 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)#12=1200 nits / 100 nits w = core.std.Expr(c, expr="{exposure_bias} 0.22 {exposure_bias} * 0.03 + * 0.002 + {exposure_bias} 0.22 {exposure_bias} * 0.3 + * 0.06 + / 0.01 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS) c = core.std.Expr(clips=[tm,w], expr=" x 1 y / * ",format=vs.RGBS) #c=core.fmtc.primaries(clip=c, prims="2020", primd="709") c=core.resize.Bilinear(clip=c, format=vs.RGBS, primaries_in_s="2020", primaries_s="709",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.RGBS, transfer_in_s="linear", transfer_s="709",dither_type="none") c=core.resize.Bilinear(clip=c, format=vs.YUV420P8, matrix_s="709", range_in_s="full",range_s="limited",chromaloc_in_s="center") c.set_output() |
![]() |
![]() |
![]() |
#16 | Link |
Registered User
Join Date: Oct 2001
Location: Germany
Posts: 7,086
|
for easier use, I wrapped the corrected version into a function:
(UPDATED VERSION in later post) Code:
''' HDR-10 to SDR mapping, from 'age' (https://forum.doom9.org/showthread.php?p=1800675) ''' import vapoursynth as vs def hablehdr10tosdr(clip, source_peak=1200, ldr_nits=100, tFormat=vs.YUV420P8, tMatrix="709", tRange="limited"): core = vs.get_core() clip=core.resize.Bilinear(clip=clip, format=vs.YUV444PS, range_in_s="limited", range_s="full",chromaloc_in_s="center",dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, matrix_in_s="2020ncl", range_in_s="full",dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, transfer_in_s="st2084", transfer_s="linear",dither_type="none", nominal_luminance=source_peak) exposure_bias=(source_peak/ldr_nits) #set 150 or 200 for lowering the brightness #hable tone mapping #["A"] = 0.22 #["B"] = 0.3 #["C"] = 0.1 #["D"] = 0.2 #["E"] = 0.01 #["F"] = 0.3 #["W"] = 11.2 #((x * (A*x + C*B) + D*E) / (x * (A*x+B) + D*F)) - E/F" tm = core.std.Expr(clip, expr="x {exposure_bias} * 0.22 x {exposure_bias} * * 0.03 + * 0.002 + x {exposure_bias} * 0.22 x {exposure_bias} * * 0.3 + * 0.06 + / 0.01 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)#12=1200 nits / 100 nits w = core.std.Expr(clip, expr="{exposure_bias} 0.15 {exposure_bias} * 0.05 + * 0.004 + {exposure_bias} 0.15 {exposure_bias} * 0.50 + * 0.06 + / 0.02 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)# clip = core.std.Expr(clips=[tm,w], expr=" x 1 y / * ",format=vs.RGBS) clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, primaries_in_s="2020", primaries_s=tMatrix,dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, transfer_in_s="linear", transfer_s=tMatrix,dither_type="none") if format != vs.RGBS: clip=core.resize.Bilinear(clip=clip, format=tFormat, matrix_s=tMatrix, range_in_s="full",range_s=tRange,chromaloc_in_s="center") return clip; Last edited by Selur; 1st January 2018 at 14:25. |
![]() |
![]() |
![]() |
#18 | Link |
Registered User
Join Date: May 2014
Posts: 33
|
I would really like to see that as well. The thread on HDR to SDR using FFmpeg is certainly helpful, but it would great to do it all within Avisynth+ scripting.
|
![]() |
![]() |
![]() |
#19 | Link |
Registered User
Join Date: Oct 2001
Location: Germany
Posts: 7,086
|
small adjustment to the above code,.. (made color location available)
Code:
''' HDR-10 to SDR mapping, from 'age' (https://forum.doom9.org/showthread.php?p=1800675) ''' def hablehdr10tosdr(clip, source_peak=1200, ldr_nits=100, tFormat=vs.YUV420P8, tMatrix="709", tRange="limited", color_loc="center"): core = vs.get_core() clip=core.resize.Bilinear(clip=clip, format=vs.YUV444PS, range_in_s="limited", range_s="full",chromaloc_in_s=color_loc,dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, matrix_in_s="2020ncl", range_in_s="full",dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, transfer_in_s="st2084", transfer_s="linear",dither_type="none", nominal_luminance=source_peak) exposure_bias=(source_peak/ldr_nits) #set 150 or 200 for lowering the brightness #hable tone mapping #["A"] = 0.22 #["B"] = 0.3 #["C"] = 0.1 #["D"] = 0.2 #["E"] = 0.01 #["F"] = 0.3 #["W"] = 11.2 #((x * (A*x + C*B) + D*E) / (x * (A*x+B) + D*F)) - E/F" tm = core.std.Expr(clip, expr="x {exposure_bias} * 0.22 x {exposure_bias} * * 0.03 + * 0.002 + x {exposure_bias} * 0.22 x {exposure_bias} * * 0.3 + * 0.06 + / 0.01 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)#12=1200 nits / 100 nits w = core.std.Expr(clip, expr="{exposure_bias} 0.15 {exposure_bias} * 0.05 + * 0.004 + {exposure_bias} 0.15 {exposure_bias} * 0.50 + * 0.06 + / 0.02 0.30 / - ".format(exposure_bias=exposure_bias),format=vs.RGBS)# clip = core.std.Expr(clips=[tm,w], expr=" x 1 y / * ",format=vs.RGBS) clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, primaries_in_s="2020", primaries_s=tMatrix,dither_type="none") clip=core.resize.Bilinear(clip=clip, format=vs.RGBS, transfer_in_s="linear", transfer_s=tMatrix,dither_type="none") if format != vs.RGBS: clip=core.resize.Bilinear(clip=clip, format=tFormat, matrix_s=tMatrix, range_in_s="full",range_s=tRange,chromaloc_in_s=color_loc) return clip; Last edited by Selur; 1st January 2018 at 14:29. |
![]() |
![]() |
![]() |
#20 | Link |
Registered User
Join Date: Dec 2009
Posts: 72
|
I have a vapoursynth port available. I've only tested it with HLG content. YMMV.
https://github.com/ifb/vapoursynth-tonemap |
![]() |
![]() |
![]() |
Tags |
hdr, sdr |
Thread Tools | Search this Thread |
Display Modes | |
|
|