PDA

View Full Version : Chroma is shifted after conversion YUY2->RGB and back


cedocida
27th August 2007, 21:37
I don't know if this issue/bug is already known (so, for discussion):
If I do a color conversion starting with a YUY2 clip using ConvertToRGB() and then ConvertToYUY2,
the color is slighly shifted to the left.
Version of Avisynth is 2.57.
Best you can see it after multiple conversions, e.g. with the following script and a test image:

-----------------------------------
clip_original = OpenDMLSource("testbild_color_0.avi")
clip0 = ConvertToYUY2(clip_original)

clip1 = Trim(clip0,0,-1)
clip2 = ConvertToRGB(clip0)
clip3 = ConvertToYUY2(clip2)
clip0 = clip1 ++ clip3

clip1 = Trim(clip0,0,-1)
clip2 = ConvertToRGB(clip0)
clip3 = ConvertToYUY2(clip2)
clip0 = clip1 ++ clip3

.... repeat .....
-------------------------------------------

For me it seems that the two conversion routines use different sampling/interpolation positions for the chroma samples.

IanB
28th August 2007, 00:33
@cedocida,

For the C++ code ConvertToRGB uses the same UV chroma for 2 RGB pixels, point upsampling. [YUYV]... -> [RGB][RGB]...

The Asm code uses the current UV chroma for the left RGB pixel and does bilinear interpolation of right UV chroma from the current and next pixel for the right RGB pixel.

ConvertToYUY2 uses the average chroma from 2 RGB pixels, bilinear downsampling. [RGB][RGB]... -> [YUYV]...

This different sampling will cause the chroma to move left. A [1 2 1] kernel in place of the currernt [0 1 1] kernel would alleviate the problem.

ConvertBackToYUY2 uses the chroma from the left RGB pixel only, the right RGB pixel only contribute to the right pixel Y value, point downsampling. [RGB][rgb]... -> [YUyV]...

These routines are original Ben code and were coded to be as fast as possible for the day, they are from Ben's HuffYUV codec. He has trimmed a slight corner here by only using 2 pixels interpolation.

Arguable using 3 pixels would avoid the problem, and today the performance penalty would be acceptable.

In AVS 2.6 the option to use the Resizer core (default BiCubic) to scale the chroma planes will be available with a corresponding fine control of chroma placement.

tritical
28th August 2007, 06:20
Heh, I was under the assumption that YUY2->RGB kept the chroma as is for the left pixel in each pair and interpolated the chroma for the right pixel in each pair, and that RGB->YUY2 used a [1 2 1] kernel to calculate chroma. My assumption being based on this webpage: http://avisynth.org/mediawiki/Sampling, but it seems that that is incorrect.

However, my question then is where does the leftward shift come from? If YUY2->RGB point upsamples chroma for each pair [YUYV]->[YUV YUV]->[RGB RGB], and RGB->YUY2 calculates the chroma using only those two RGB pixels [RGB RGB]->[YUV YUV]->[Y(U+U)/2(V+V)/2 Y], then the chroma should not shift to the left. However, try chaining about 16 converttorgb()+converttoyuy2() pairs together, and you'll see that the chroma shifts a significant amount to the left as cedocida has indicated.

It seems, therefore, that the YUY2->RGB conversion is averaging to get the chroma for the right pixel in each pair. That, combined with the RGB->YUY2 conversion using only 2 pixels would result in a gradual left shift of the chroma.

Consulting convert.cpp, the C code for YUY2->RGB works as IanB indicated. However, the asm code in convert_a.asm is actually averaging to get the chroma for the right pixel in each rgb pair... resulting in the leftwards shift when combined with the RGB->YUY2 conversion averaging from only two pixels.

IanB
28th August 2007, 11:39
Yep, Tritical you are right, :o the ConvertToRGB C++ code and the Asm code use different sampling.

As I said previously, the C++ code uses the current UV chroma for both RGB pixels, left point upsampling.

The Asm code uses the current UV chroma for the left RGB pixel and does bilinear interpolation of right UV chroma from the current and next pixel for the right RGB pixel.