wonkey_monkey
16th March 2017, 17:35
Just something I'm musing on, and not sure how to test it exactly, but if I do this:
colorbars.converttoyv12.converttorgb
Then I see the dark line between green and magenta that is usually a hallmark of a lack of gamma awareness.
So does that mean the internal convert functions don't take gamma into account, and just treat all pixel values as linear?
martin53
16th March 2017, 20:36
If I may put my two cents in, then I think there are two things involved in your question, and maybe you will be so kind to comment my admittedly basic understanding of the gamma concept; because although this certainly has been described already over and over, there are still some people who lack knowledge in it (me) and even don't know where to learn it best (me again).
The first thing involved is the RGB->YUV->RGB colorspace conversion itself. We can observe the behaviour with ColorBars(pixel_type="RGB32") and then turning on and off .ConvertToYV24(). The conversion takes place with a linear matrix multiplication (at least basically, range adaption and bias shift of the two frame formats is also done).
ColorBars(pixel_type="RGB32").ConvertToYV24(matrix="Rec601").ConvertToRGB32() does not look differently to my amateur eyes from the pure ColorBars() command, and ColorBars(pixel_type="RGB32").ConvertToYV24(matrix="Rec601") does almost not (tests done with AvsPmod on two monitors). There is a subtle difference in the triple dark gray block, however.
From this I'd like to summarize that the RGB/YUV conversion by itself, calculated linearly, seems to give good results.
The other thing is color subsampling. From what I understood in convert_planar.cpp (which is by far not everything), the ConvertToYV12() conversion can be considered a hidden full size conversion, directly followed by bicubic downsize resampling (with the resampler offset adjusted to the different DV/MPEG1/MPEG2 chroma positions).
This is where I observe the mentioned dark line between green and purple.
I don't see any luma connection with the subsampling process, which appears to be done purely on the resp. color plane, one after the other. Again, I would describe the bicubic downsampler as working 'linear'.
Now here's what I'd like to ask in the discussion about 'gamma awareness'. I recently read some pages on sRGB, ideal HDR gamma and these things, and I learned that sRGB has a straightforward formula for higher luma, but a separate one or very dark luma; that HDR luma for a theoretical monitor with infinite contrast would approach a so and so gamma (was it 2.2?), but sRGB was a good approximation for daylight or office ambient and real contrast of 1000:1 or less.
This made me think that BlankClip(pixel_type="Y8").mt_lutspa(mode="relative",expr="x 219 * 16 +") should look like a "uniform gray gradient", or in other words linearly ascending clip luma codes should result in non linear ascending monitor radiance, which in turn visually appears like linearly ascending brightness.
In accordance with e.g. Wikipedia (https://en.wikipedia.org/wiki/Middle_gray), physically 18% luminance is perceptually halfway gray. And indeed, the halves of BlankClip(pixel_type="Y8").mt_lutspa(mode="absolute",expr="x 320 < 16 218 + 2 / x y + 5.5556 % 0 = 218 * 16 + ?") (all pixels being 18% bright vs. 18% fully bright pixels) will probably look acceptably similar if everything is adjusted well.
I learn from this very post that the perceptual fact comes into play when multiple pixels with a luminance meaning are 'averaged', and only then (correct?). The averaging should not be made arithmetically: a black and a white pixel together emit 50% radiance, while two 'middle gray' pixels emit 18%. Instead, after averaging 0.5 must then be raised to the power of 2.474, to get 0.18 .
But averaging without exponentiation can not produce a dark line, it must always produce a bright artefact?
Now ConvertToYV12() does not average luma, but chroma values. Because chromaticity is the ratio between the Y and the U|V components in YUV space, when they are averaged arithmetically, they pretend a too high chromaticity. For example, let's have one pixel with 10% luma (emitting 0.1^2.4 for simplified sRGB) and one with 90% (emitting 0.9^2.4), and each have chroma components identical to luma. Then, a resulting chroma component of 0.5 combined with the perceptive brightness of 0,19 (because I used 2.4, not 2.474) produces a 0.5/0.19 = 2.64-fold chroma component.
From that I would expect that chroma-downscaled pictures looked significantly too saturated when averaging of highly different chromaticities happens. Personally, I can't say I ever observed that consciously, and the following script shows something completely different. But at least I am too confused at least with these results to continue myconsiderations.
uvexpr="x 320 < 128 30 - 128 x y + 2 % 0 = 30 * - ?"
#uvexpr="128" #uncomment line to get the gray reference image
BlankClip(pixel_type="YV24").mt_lutspa(mode="absolute",yexpr="x 320 < 64 128 + 2 / x y + 5.5556 % 0 = 128 * 64 + ?",uexpr=uvexpr,vexpr=uvexpr,u=3,v=3)
TheFluff
16th March 2017, 21:11
What do you mean, "gamma aware"? Both rec 601 and rec 709 are standardized in terms of conversion to a gamma compressed YCbCr signal, so obviously yes, anything converting between them has to be "gamma aware" (there is a bt 2020 variant with a linear transfer function, but Avisynth's builtin conversions do not support that). On the other hand, Avisynth assumes gamma compressed RGB pretty much everywhere, so obviously no, the convertto* functions are not "gamma aware", they just assume that the input is correctly gamma compressed already.
If you drop the ancient garbage from the 90's and instead use a scaling and colorspace library that actually works, such as zimg (https://github.com/sekrit-twc/zimg), you can specify the color primaries, transfer characteristics and matrix coefficients independently of each other for both input and output, so you can actually do standards conversion.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.