natural-harmonia-gropius / hdr-toys

Componentized Rec.2100 to Rec.709 conversion shader for mpv-player, featuring dynamic curves and a uniform color space.
MIT License
112 stars 1 forks source link

HDR to SDR (question) #59

Open geextahslex opened 5 months ago

geextahslex commented 5 months ago

Hi, I want to ask if there is a chance for a "simple" HDR "bt.2020" (HDR movies on UHD blurays) to SDR (normal TV) profile. This would be very useful.

Thank you

geextahslex commented 4 months ago

I changed it to 0.5 and its brighter, but I think it is to contrasty. You almost loose her right shoulder in the darkness ^^ reinhard reino hable2 (0.5) hable2

geextahslex commented 4 months ago

okay there is something I don't understand with reinhard. Even when I set L_hdr to 1000, so the stock value, the picture gets darker. There must be something behind this...

edit: it seems like the difference between both images is mpv gamma +3

natural-harmonia-gropius commented 4 months ago

1000 for most content is highest value, lower it, the value of it is strongly related to the current frame. and hdr-toys.js and hdr-toys-helper.lua would change L_hdr in runtime, delete them if you decide to set it manyally.

geextahslex commented 4 months ago

I tried it already with and without hdr-toys.js and there is no difference

natural-harmonia-gropius commented 4 months ago

lower the L_hdr to 250, still no difference?

geextahslex commented 4 months ago

there is a difference, the peaks are now clipping. and there is a 2nd difference, the picture gets darker.

try it out yourself, first run without the last line L_hdr, and then with. I don't know how to post code, so this looks not so good

and the issue is that as soon as you touch L_hdr, and it doesn't matter if you go up or down or leave it at stock, the picture gets darker. he is like in a different mode/state or something

tone-mapping=clip gamut-mapping-mode=clip

[bt.2100-pq] profile-cond=get("video-params/primaries") == "bt.2020" and get("video-params/gamma") == "pq" profile-restore=copy target-prim=bt.2020 target-trc=pq

glsl-shader=~~/shaders/hdr-toys/utils/clip_both.glsl glsl-shader=~~/shaders/hdr-toys/transfer-function/pq_inv.glsl glsl-shader=~~/shaders/hdr-toys/tone-mapping/reinhard.glsl glsl-shader=~~/shaders/hdr-toys/utils/black_point_compensation.glsl glsl-shader=~~/shaders/hdr-toys/gamut-mapping/bottosson.glsl glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl

glsl-shader-opts=L_sdr=150

glsl-shader-opts=L_hdr=250

natural-harmonia-gropius commented 4 months ago

L_hdr requires very fine tuning and need to set it for every scene. that's hard to do.

there is a difference, the peaks are now clipping.

This is as expected.

and there is a 2nd difference, the picture gets darker.

I don't get darker.

Overall

Default mapping of mpv is already done a good job. Don't pursue perfection, mapping just a matter of being able to watch. less fussing, more enjoying.

geextahslex commented 4 months ago

L_hdr requires very fine tuning and need to set it for every scene. that's hard to do.

not really. its just a "slider" white15 white3 white5

I don't get darker.

okay so if you picture doesn't get darker, then there must be a difference in our files/config or something

Default mapping of mpv is already done a good job. Don't pursue perfection, mapping just a matter of being able to watch. less fussing, more enjoying.

haha I know I know, but I have to figure out why this is happening

could you tell me how to post code?

natural-harmonia-gropius commented 4 months ago

how to post code?

Select multiline and click image

not really. its just a "slider"

We don't have "slider" in mpv and need to match frame's peak, it can't be done with eye or without pro tools.

geextahslex commented 4 months ago

okay thank you

the other thing I found out is that if you put L_hdr before L_sdr, there is no effect of L_hdr

glsl-shader-opts=L_hdr=250 glsl-shader-opts=L_sdr=150

geextahslex commented 4 months ago

I don't understand. Reinhard: you control the nits/brightness with L_sdr. the lower you go the brighter the image. But if you touch L_hdr than you loose this (L_sdr) functionality and the brightness goes back to stock settings (203). I think there is something broken. It's like L_hdr sets L_sdr out of business xD

NotMithical commented 4 months ago

the other thing I found out is that if you put L_hdr before L_sdr, there is no effect of L_hdr

glsl-shader-opts=L_hdr=250 glsl-shader-opts=L_sdr=150

Using glsl-shader-opts overwrites any opts that were previously set the same way. If you want it to use both options you need to use glsl-shader-opts=L_hdr=250,L_sdr=150

or glsl-shader-opts=L_hdr=250 glsl-shader-opts-append=L_sdr=150

geextahslex commented 4 months ago

thats the correct answer ^^ I was scratching my head since 2 days about it, thank you and it's a good thing to know for the future

geextahslex commented 4 months ago

what are the new reinhard rgb and maxrgb variants?

natural-harmonia-gropius commented 4 months ago

what are the new reinhard rgb and maxrgb variants?

reinhard curve + ARRI's working space + pre-channel / max rgb value approaches. mostly what camera's "std" and "vivid" mode doing. but these two approaches will be out of related to luminance. image https://www.arri.com/en/learn-help/learn-help-camera-system/image-science/reveal-color-science

geextahslex commented 4 months ago

okay nice, yes I have seen a change in the reds. And what is android13?

natural-harmonia-gropius commented 4 months ago

what is android13?

tone mapping algorithm of android 13. not good, just useable. add it as it's "factual standard". "OEMs are strongly encouraged to override the implementation" https://source.android.com/docs/core/display/tone-mapping

geextahslex commented 4 months ago

Could this kinda "clipped" or oversaturated blues be fixed?

normal/bottosson normal

reinhard/bottosson jhjhh

normal/bottosson normal2

reinhard/bottosson hjhjj

natural-harmonia-gropius commented 4 months ago

What is normal?

Try lower softness_scale, default to 0.33. yet another shader opt.

geextahslex commented 4 months ago

this is "normal"

target-prim=bt.2020
target-trc=bt.1886

glsl-shader=~~/shaders/hdr-toys/utils/clip_both.glsl
glsl-shader=~~/shaders/hdr-toys/transfer-function/srgb_inv.glsl
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/bottosson.glsl
glsl-shader=~~/shaders/hdr-toys/transfer-function/srgb.glsl

tone-mapping=st2094-10
target-peak=150

hdr-compute-peak=no
allow-delayed-peak-detect
tone-mapping-param=0.500
gamut-mapping-mode=relative
natural-harmonia-gropius commented 4 months ago
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886_inv.glsl
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl

as your target-trc=bt.1886

geextahslex commented 4 months ago

the normal works fine, as you see in the screenshots, reinhard has issues with dark blue

it gets better at soft=0 but its still not as good as "normal" oioio

geextahslex commented 4 months ago

okay I have found a fix for this issue...kinda

you have to use srgb at the end instead of bt1886 and ditch black point compensation, this also increases the contrast a bit

softness_scale at default

edit: this actually fixes many things (color aftifacts), I don't know if it is overall the better solution (because of the brightness shift) but you could look into this. I can make some comparison screenshots if you want

before buff

after nice

natural-harmonia-gropius commented 4 months ago

this update broke the solution I mentioned in "HDR to SDR (question) https://github.com/natural-harmonia-gropius/hdr-toys/issues/59" (now there are white dots artifacts in black regions) and didn't solve the clipped saturated colors issue

sample video as above pls. I will look at it tomorrow.

geextahslex commented 4 months ago

okay sorry my bad, I didn't test with the latest reinhard, so now there is no white dots artifact issue ^^

only the clipped blue saturated colors are still present, here is the sample Avatar.2.The.Way.of.Water.mkv.zip

[bt.2100-pq]
profile-cond=get("video-params/primaries") == "bt.2020" and get("video-params/gamma") == "pq"
profile-restore=copy
target-prim=bt.2020
target-trc=pq

glsl-shader=~~/shaders/hdr-toys/utils/clip_both.glsl
glsl-shader=~~/shaders/hdr-toys/transfer-function/pq_inv.glsl
glsl-shader=~~/shaders/hdr-toys/tone-mapping/reinhard.glsl
glsl-shader=~~/shaders/hdr-toys/utils/black_point_compensation.glsl
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/bottosson.glsl
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl

glsl-shader-opts=L_hdr=250,L_sdr=150
geextahslex commented 4 months ago

I have a question about reinhard. So I like the L_hdr at 250 but many things like fire, explosions etc. are clipping. Is there a way to modify the curve to keep the brightness and squash the hdr peaks more?

something like this xyxy

natural-harmonia-gropius commented 4 months ago

things like fire, explosions etc. are clipping.

maybe replace bottosson to jedypod or clip coulld fix this.

Is there a way to modify the curve

rewrite curve()

float curve(float x, float w)

https://pomax.github.io/bezierinfo/

geextahslex commented 4 months ago

I have no idea how this would translate into float curve(float x, float w) ^^

awdawd

geextahslex commented 4 months ago

Okay I was thinking about this clipping L_hdr stuff and I came up with an idea. So what if you would use 2 reinhards instead of one and let them work in tandem. You set up the first reinhard at L_hdr 250 so you have overall bright skyes, lights and so on. The 2nd reinhard is set to L_hdr 500 so there is no clipping at explosions and fires. And you let the 2nd reinhard only passtrough smoothstep transition 230/245-255 srgb, so you get only the peak information. I tested this in photoshop and it actually turns out very nice

L_hdr 250 clipping 250

L_hdr 500 no clipping 500

Pictures combined. Not perfect but better than clipping combined1

Color coding for better representation, the blue is L_hdr 500 on top of L_hdr 250 color coding

settings for the smoothstep transition settings2

Can you tell me how I can limit the ouput threshold/range from reinhard? I have no idea how to implement this but maybe you could help me with this Let me know what you think about it :)

natural-harmonia-gropius commented 4 months ago

You set up the first reinhard at L_hdr 250 so you have overall bright skyes, lights and so on. The 2nd reinhard is set to L_hdr 500 so there is no clipping at explosions and fires.

Don't use such low value for L_hdr.

use 2 reinhards

Halo artifacts around the fire.

limit the ouput threshold/range

https://github.com/natural-harmonia-gropius/hdr-toys/blob/master/shaders/hdr-toys/utils/range.glsl

geextahslex commented 4 months ago

I don't understand, how do I implement this into reinhard. Which values are the threshold? There is no smoothstep. There are no srgb values.

I need something like this but with reinhard instead of desaturation. There is also no need fo strength

//!PARAM Strength
//!DESC Desat Strength
//!TYPE float
//!MINIMUM 0
//!MAXIMUM 1
0.3

//!HOOK MAIN
//!BIND HOOKED
//!DESC Desaturation smooth 

#define Thresh 15/255.
#define w 10/255.
#define CoefLuma vec4(0.2126, 0.7152, 0.0722, 0) //sRGB, HDTV

/* simple threshold with mpv glsl 
Strength*desaturation [0 to1.0], 0: full color, 1: grayscale.
*/

vec4 hook()  {
   vec4 c0 = HOOKED_texOff(0);
   vec3 desaturation = smoothstep(Thresh + w, Thresh - w, c0.rgb);
   // return vec4(desaturation, 1);
   c0.rgb = mix(c0.rgb, vec3(dot(c0, CoefLuma)), Strength*desaturation);

   return c0;
}
natural-harmonia-gropius commented 4 months ago

https://github.com/natural-harmonia-gropius/hdr-toys/blob/38bbd55831a81d5359911be14f8f07d243555b34/shaders/hdr-toys/tone-mapping/reinhard.glsl#L129

Following codes maybe work, I didn't run it.

float I2_1 = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdr, 250 / L_sdr) * L_sdr);
float I2_2 = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdr, 500 / L_sdr) * L_sdr);
float I2 = smoothstep(I2, I3, 0.5);
geextahslex commented 4 months ago

with this change reinhard doesn't even appear in the shader pipeline

natural-harmonia-gropius commented 4 months ago

float I2 = smoothstep(I2_1, I2_2, 0.5);

0.5 can be other value.

geextahslex commented 4 months ago

I thought so, and changed them but the output is a black and white mess

natural-harmonia-gropius commented 4 months ago

try mix(I2_1, I2_2, 0.5);

geextahslex commented 4 months ago

mix worked, but this approach does not give the effect that I wanted. I want one vanilla reinhard.glsl and a 2nd reinhard.glsl that ouputs a specific range/threshold. So 2 shaders on top of each other

natural-harmonia-gropius commented 4 months ago

what about float I2 = smoothstep(I2_2, I2_1, 0.5);

geextahslex commented 4 months ago

what about float I2 = smoothstep(I2_2, I2_1, 0.5);

black and white mess

why you don't want to just put a output range/threshold at the end of the whole shader?

natural-harmonia-gropius commented 4 months ago

black and white mess

try smoothstep(I2_2, I2_1, (I2_2 + I2_1) * 0.5);

why you don't want to just put a output range/threshold at the end of the whole shader?

you can do this by simply I2 = I2 * 235 / 255

geextahslex commented 4 months ago

And where exactly do I put this line? I2 = I2 * 235 / 255

vec3 tone_mapping_ictcp(vec3 ICtCp) {
    float I2  = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdr, L_hdr / L_sdr) * L_sdr);
    ICtCp.yz *= mix(1.0, min(ICtCp.x / I2, I2 / ICtCp.x), sigma);
    ICtCp.x   = I2;
    return ICtCp;
}
natural-harmonia-gropius commented 4 months ago

after float I2 line I2 = I2 * 235 / 255;

geextahslex commented 4 months ago

This makes the whole picture darker and it also don't put out only the highlights. It effects the whole image With this calculation you only making the picture like 10% dimmer or so

https://maximmcnair.com/p/webgl-thresholding we would need threshold, like here, use the slider threshold

geextahslex commented 3 months ago

This isn't working, do you have any other ideas?

vec3 tone_mapping_ictcp(vec3 ICtCp) {
    float I2  = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdr, L_hdr / L_sdr) * L_sdr);
         I2 = I2 * 245 / 255;
    ICtCp.yz *= mix(1.0, min(ICtCp.x / I2, I2 / ICtCp.x), sigma);
    ICtCp.x   = I2;
    return ICtCp;
}
natural-harmonia-gropius commented 3 months ago

I will write an example shader of bezier in this weekend(or next).

geextahslex commented 3 months ago

That's good news :)

geextahslex commented 3 months ago

Do you make all this just in notepad or do you have any software or environment that gives you any feedback, for debugging etc.? To see what is happening at certain code lines.

natural-harmonia-gropius commented 3 months ago

I port functions to javascript to check the math. I have no idea how to debugging with glsl, just watch the result.

geextahslex commented 3 months ago

Can you tell me what values I2_1 and I2_2 have? Or how I can check it? This would make any changes easier. I stuck at something like this

vec3 tone_mapping_ictcp(vec3 ICtCp) {
        float I2_1 = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdrr, 250 / L_sdrr) * L_sdrr);
    float I2_2 = Y_to_ST2084(curve(ST2084_to_Y(ICtCp.x) / L_sdrr, 500 / L_sdrr) * L_sdrr);
    float mask = smoothstep(0.75, 1.0, clamp(length(0,9), 0.0, 1.0));
    float I2 = mix(I2_1, I2_2, mask);
    ICtCp.yz *= mix(1.0, min(ICtCp.x / I2, I2 / ICtCp.x), sigma);
    ICtCp.x   = I2;
    return ICtCp;
}
natural-harmonia-gropius commented 3 months ago

Port it to other languages by yourself, I can do nothing.