Log in

View Full Version : Basic support for bt.2390 and various tonemapping operator


age
22nd September 2019, 17:27
Just insert the path to the file, the function use the metadata but if missing they should be added manually :-)
The required plugin is vapoursynth-tonemap


import easytm
import vapoursynth as vs
core = vs.get_core()

c = core.ffms2.Source(source = 'C:/Users/.../video.mp4')

c=easytm.mobius(c,target_nits=100,masterdisplay=None,transfer=None,matrix=None,primaries=None,resize_1080p=True)

c.set_output()


The operators are mobius, reinhard, hable and bt2390test

The bt.2390 display mapping operator works for now in rgb and it assume black point=0

This is the code used, honestly i'm not sure it's right and i have modified the way KS is calculated


import vapoursynth as vs

core = vs.get_core()
c = core.ffms2.Source(source = 'C:/Users/.../videos.mp4')


def bt2390test(clip="",masterdisplay=None,target_nits="",transfer=None,matrix=None,primaries=None ) :
core = vs.get_core()
c=clip

if masterdisplay is None:
masterdisplay=c.get_frame(0).props.MasteringDisplayMaxLuminance
if transfer is None:
transfer=c.get_frame(0).props._Transfer
if matrix is None:
matrix=c.get_frame(0).props._Matrix
if transfer == 16 :
transfer = "st2084"
if transfer == 18 :
transfer = "std-b67"
if matrix == 9 :
matrix = "2020ncl"
if primaries is None:
primaries=c.get_frame(0).props._Primaries
if primaries == 9 :
primaries = "2020"
if primaries == 1 :
primaries = "709"



source_peak=masterdisplay
matrix_in_s=matrix
transfer_in_s=transfer



source_peak=source_peak





c=core.resize.Bicubic(clip=c, format=vs.RGBS, filter_param_a=0, filter_param_b=0.75, matrix_in_s=matrix_in_s,chromaloc_in_s="center",chromaloc_s="center", range_in_s="limited", range_s="full",dither_type="none")


lw = source_peak/10000
#eotf^-1 y=((x^0.1593017578125) * 18.8515625 + 0.8359375 / (x^0.1593017578125) * 18.6875 + 1)^78.84375
lw = ((((lw ** 0.1593017578125) * 18.8515625) + 0.8359375) / (((lw ** 0.1593017578125) * 18.6875) + 1))**78.84375


lmax=target_nits/10000
#eotf^-1 y=((x^0.1593017578125) * 18.8515625 + 0.8359375 / (x^0.1593017578125) * 18.6875 + 1)^78.84375
lmax = ((((lmax ** 0.1593017578125) * 18.8515625) + 0.8359375) / (((lmax ** 0.1593017578125) * 18.6875) + 1))**78.84375


#normalize the PQ values
#e1=(x-0)/(lw-0) ==> e1= x / lw
e1=core.std.Expr(clips=[c], expr="x {lw} /".format(lw=lw))
e1=core.std.Limiter(e1, 0,1)




#maxlum=(lmax-0)/(lw-0) ==> maxlum=lmax/lw
maxlum=lmax/lw

#ks1=(1.5*lmax)- 0.5
ks1=(1.5*lmax)- 0.5

#ks2=(1.5*maxlum)- 0.5
ks2=(1.5*maxlum)- 0.5

#ks=(ks1+ks2)/2
ks=(ks1+ks2)/2

#t=(x-ks)/(1-ks)
t = core.std.Expr(clips=[e1], expr="x {ks} - 1 {ks} - / ".format(ks=ks))

#p=(2t^3 - 3t^2 +1)*ks +( t^3-2t^2+t)*(1-ks)+(-2t^3+3t^2)* maxlum
p = core.std.Expr(clips=[t], expr=" 2 x 3 pow * 3 x 2 pow * - 1 + {ks} * 1 {ks} - x 3 pow 2 x 2 pow * - x + * + -2 x 3 pow * 3 x 2 pow * + {maxlum} * +".format(ks=ks,maxlum=maxlum))

e2=core.std.Expr(clips=[e1,p], expr="x {ks} < x y ? ".format(ks=ks))

#e3=e2+0*(1-e2)^4 ==> e3=e2
e3=e2

#invert the normalization of the PQ values
#e4=[e3*(lw-0)]+0 ==> e4=e3*lw
e4=core.std.Expr(clips=[e3], expr="x {lw} * ".format(lw=lw))
c=e4


c=core.resize.Bicubic(clip=c, format=vs.RGBS, transfer_in_s=transfer_in_s, transfer_s="linear",dither_type="none", nominal_luminance=target_nits)



c=core.resize.Bicubic(clip=c, format=vs.RGBS, primaries_in_s=primaries, primaries_s="709",dither_type="none")
c=core.resize.Bicubic(clip=c, format=vs.RGBS, transfer_in_s="linear", transfer_s="709",dither_type="none")
c=core.std.Limiter(c, 0,1)


c=core.resize.Bicubic(clip=c, format=vs.YUV422P16,matrix_s="709", filter_param_a=0, filter_param_b=0.75, range_in_s="full",range_s="limited", chromaloc_in_s="center", chromaloc_s="center",dither_type="none")

return c


c=bt2390test(c,target_nits=100,masterdisplay=None,transfer=None,matrix=None,primaries=None)






c.set_output()

age
22nd October 2019, 16:10
ICtCp tonemapping with bt.2390 curve


import vapoursynth as vs

core = vs.get_core()
c = core.ffms2.Source(source = 'C:/Users/videos/hdr.mkv')


def ictcp2390(clip="",masterdisplay=None,target_nits="",transfer=None,matrix=None,primaries=None ) :
core = vs.get_core()



c=clip
source_peak=masterdisplay
matrix_in_s=matrix
primaries=primaries
transfer_in_s=transfer
exposure_bias1=source_peak/target_nits
source_peak=source_peak


c=core.resize.Bicubic(clip=c, format=vs.YUV444PS, filter_param_a=0, filter_param_b=0.75,chromaloc_in_s="center",chromaloc_s="center", range_in_s="limited", range_s="full",dither_type="none")
c=core.resize.Bicubic(clip=c, format=vs.YUV444PS, filter_param_a=0, filter_param_b=0.75,chromaloc_in_s="center", transfer_in_s=transfer_in_s,chromaloc_s="center", range_in_s="full", range_s="full",dither_type="none", nominal_luminance=source_peak, matrix_in_s=matrix_in_s, matrix_s="ictcp")



lw = source_peak/10000
#eotf^-1 y=((x^0.1593017578125) * 18.8515625 + 0.8359375 / (x^0.1593017578125) * 18.6875 + 1)^78.84375
lw = ((((lw ** 0.1593017578125) * 18.8515625) + 0.8359375) / (((lw ** 0.1593017578125) * 18.6875) + 1))**78.84375
lmax=target_nits/10000
#eotf^-1 y=((x^0.1593017578125) * 18.8515625 + 0.8359375 / (x^0.1593017578125) * 18.6875 + 1)^78.84375
lmax = ((((lmax ** 0.1593017578125) * 18.8515625) + 0.8359375) / (((lmax ** 0.1593017578125) * 18.6875) + 1))**78.84375



lum=core.std.ShufflePlanes(c, planes=[0], colorfamily=vs.GRAY)
c=core.std.Expr(clips=[c], expr=["x {lw} /".format(lw=lw),"",""])
c=core.std.Limiter(c, 0,1,planes=[0])
maxlum=lmax/lw
ks1=(1.5*lmax)- 0.5
ks2=(1.5*maxlum)- 0.5
ks=(ks1+ks2)/2
t = core.std.Expr(clips=[c], expr=["x {ks} - 1 {ks} - / ".format(ks=ks),"",""])
p = core.std.Expr(clips=[t], expr=[" 2 x 3 pow * 3 x 2 pow * - 1 + {ks} * 1 {ks} - x 3 pow 2 x 2 pow * - x + * + -2 x 3 pow * 3 x 2 pow * + {maxlum} * +".format(ks=ks,maxlum=maxlum),"",""])
e2=core.std.Expr(clips=[c,p], expr=["x {ks} < x y ? ".format(ks=ks),"",""])
c=core.std.Expr(clips=[e2], expr=["x {lw} * ".format(lw=lw),"",""])
c=core.std.Limiter(c, 0,1,planes=[0])
lumtm=core.std.ShufflePlanes(c, planes=[0], colorfamily=vs.GRAY)


mult=1 /(lw-lmax)
mask1=core.std.Expr(clips=[lum,lumtm], expr=" x y - {mult} * ".format(mult=mult))
mask1=core.std.Limiter(mask1, 0,1)
mask1=core.std.ShufflePlanes(mask1, planes=[0,0,0], colorfamily=vs.YUV)

mask2=core.std.Expr(clips=[lum,lumtm], expr=" x y / y x / min ")
mask2=core.std.Limiter(mask2, 0,1)
mask2=core.std.ShufflePlanes(mask2, planes=[0,0,0], colorfamily=vs.YUV)


c2=core.std.Expr(clips=[c,mask2], expr=[" x "," x y * "," x y * "])
cgray=core.std.Expr(clips=[c], expr=[" x "," 0 "," 0 "])
c=core.std.MaskedMerge(c2, cgray, mask1)

c=core.resize.Bicubic(clip=c, format=vs.RGBS, filter_param_a=0, filter_param_b=0.75,chromaloc_in_s="center", transfer_in_s=transfer_in_s,chromaloc_s="center", range_in_s="full", range_s="full",dither_type="none", nominal_luminance=target_nits, matrix_in_s="ictcp")


c=core.resize.Bicubic(clip=c, format=vs.RGBS, transfer_in_s=transfer_in_s, transfer_s="linear",dither_type="none", nominal_luminance=target_nits)
c=core.resize.Bicubic(clip=c, format=vs.RGBS, primaries_in_s=primaries, primaries_s="709",dither_type="none")
c=core.resize.Bicubic(clip=c, format=vs.RGBS, transfer_in_s="linear", transfer_s="709",dither_type="none")
c=core.std.Limiter(c, 0,1)

c=core.resize.Bicubic(clip=c, format=vs.YUV422P16,matrix_s="709", filter_param_a=0, filter_param_b=0.75, range_in_s="full",range_s="limited", chromaloc_in_s="center", chromaloc_s="center",dither_type="none")

return c

c=ictcp2390(c,target_nits=100,masterdisplay=1000,transfer="st2084",matrix="2020ncl",primaries="2020")


c.set_output()



Sample images
https://i.ibb.co/3zkRNJX/hdr-ictcp-fast-simple-vpy-180.png (https://ibb.co/3zkRNJX) https://i.ibb.co/1sywQQL/hdr-ictcp-fast-simple-vpy-330.png (https://ibb.co/1sywQQL) https://i.ibb.co/84w4s81/hdr-ictcp-fast-simple-vpy-773.png (https://ibb.co/84w4s81) https://i.ibb.co/WBsfFwY/hdr-ictcp-fast-simple-vpy-2440.png (https://ibb.co/WBsfFwY) https://i.ibb.co/hXgYY4D/hdr-ictcp-fast-simple-vpy-3169b.png (https://ibb.co/hXgYY4D) https://i.ibb.co/KyPRDzh/hdr-ictcp-fast-simple-vpy-3238.png (https://ibb.co/KyPRDzh) https://i.ibb.co/n6t1Xjb/hdr-ictcp-fast-simple-vpy-3653.png (https://ibb.co/n6t1Xjb) https://i.ibb.co/GsJp5VF/8.png (https://ibb.co/GsJp5VF)