Log in

View Full Version : Need help keeping the RGB color impression when converting to YUV444P8


Selur
22nd July 2020, 17:15
What I did so far:
I wrote wrote a short script to look at an image (https://i.imgur.com/4vmgQYj.png) using Vapoursynth.
# Imports
import vapoursynth as vs
core = vs.get_core()
# Loading C:\Users\Selur\Desktop\4vmgQYj.png using vsImageReader
clip = core.imwri.Read(["C:/Users/Selur/Desktop/4vmgQYj.png"])
clip = core.std.Loop(clip=clip, times=100)
# making sure frame rate is set to 25
clip = core.std.AssumeFPS(clip, fpsnum=25, fpsden=1)
# Setting color range to TV (limited) range.
clip = core.std.SetFrameProp(clip=clip, prop="_ColorRange", intval=1)
# Output
clip.set_output()

I then added:

#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, transfer_in="linear", matrix_s="709", range_s="limited") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, transfer_in="linear", matrix_s="709", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="470bg", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="470bg", range_s="limited") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="170m", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="170m", range_s="limited") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="240m", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="240m", range_s="limited") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="fcc", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="fcc", range_s="limited") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="ycgco", range_s="full") # -> wrong color
#clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="ycgco", range_s="limited") # -> wrong color

to my script and alternated between those lines and the output without them to see which of those would be the one that would preserve the color properly.

None of them did. :/
I feel like I'm clearly overlooking something (basic) since all those conversions change the color quite a lot.

Only way that does seem to work is by using:
# Imports
import vapoursynth as vs
core = vs.get_core()
# Loading C:\Users\Selur\Desktop\4vmgQYj.png using vsImageReader
clip = core.imwri.Read(["C:/Users/Selur/Desktop/4vmgQYj.png"])
clip = core.std.Loop(clip=clip, times=100)
# making sure frame rate is set to 25
clip = core.std.AssumeFPS(clip, fpsnum=25, fpsden=1)

clip = core.std.SetFrameProp(clip=clip, prop="_ColorRange", intval=0) # setting flag to full range
clip = core.resize.Bicubic(clip, range_in_s="full", range_s="limited") # converting full to limited range
clip = core.std.SetFrameProp(clip=clip, prop="_ColorRange", intval=1) # setting flag to full range
clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P8, matrix_s="709", range_s="limited") # using the

# Output
clip.set_output()
the rgb color and the output colors seem to be the same.

But this simply does seem wrong!

-> Can someone tell me how to do this properly?


Cu Selur

age
22nd July 2020, 20:11
import vapoursynth as vs
core = vs.get_core()
clip = core.imwri.Read(["C:/Users/.../Desktop/4vmgQYj.png"])
clip = core.std.Loop(clip=clip, times=100)
clip = core.std.AssumeFPS(clip, fpsnum=25, fpsden=1)

#convert to yuv full range
clip=core.resize.Bicubic(clip=clip, format=vs.YUV444P8,matrix_s="709", filter_param_a=0, filter_param_b=0.75, range_in_s="full",range_s="full", chromaloc_in_s="center", chromaloc_s="center",dither_type="none")

#convert back to rgb with same matrix
#clip=core.resize.Bicubic(clip=clip, format=vs.RGB24,matrix_in_s="709", filter_param_a=0, filter_param_b=0.75, range_in_s="full",range_s="full", chromaloc_in_s="center", chromaloc_s="center",dither_type="none")

clip.set_output()

poisondeathray
22nd July 2020, 21:18
The problem is
# Setting color range to TV (limited) range.
clip = core.std.SetFrameProp(clip=clip, prop="_ColorRange", intval=1)



I think the explanation is clipping vs clamping in YUV/RGB conversions

1) You're starting out with a "normal" full range RGB 0-255 image. If you use limited range input, you lose 0-15, 236-255 parts of the image (clipped) so contrast is messed up

ie. Limited range RGB 16-235 (clipped) => YUV 0-255 (limited to full)

or

ie Limited range RGB 16-235 (clipped) => YUV 0-235 (limited to limited)

Either way, the image is messed up from the clipping

2)
The one that "works" is clamping first, not clipping
(There is a typo in one that works, the 3rd one's comment intval=1 should be setting flag to limited range, not full)

clamp RGB 0-255 => RGB 16-235 first (analogous to levels PC to TV , but in RGB)
intval=1 means set limited range prop
Convert RGB 16-235 => Y 16-235, because limited in to limited out . No RGB range was lost.

Selur
23rd July 2020, 03:49
Thanks for the help!

Cu Selur