View Full Version : Decompose RGB and YUV in color?
Reel.Deel
5th April 2014, 22:16
Hi everyone,
After reading the YCbCr (http://en.wikipedia.org/wiki/YCbCr) page on Wikipedia there's an illustration (http://en.wikipedia.org/wiki/File:CCD.png) that shows RGB and YUV decoposed but with color. I thought it was kinda neat and tried doing it with AviSynth.
I know there is ShowRed/Green/Blue and UtoY/VtoY but the output is greyscale. I started tinkering and came up with something but I'm not completely sure if it's correct?
Source for this little experiment:
http://sipi.usc.edu/database/preview/misc/4.2.04.png
--------
For RGB:
# Source
ImageSource("4.2_04.png", end=0)
# Processing
R = ShowRed("Y8")
G = ShowGreen("Y8")
B = ShowBlue("Y8")
blank = BlankClip(R, color_yuv=$000000)
R2 = MergeRGB(R, blank, blank, pixel_type="RGB24")
G2 = MergeRGB(blank, G, blank, pixel_type="RGB24")
B2 = MergeRGB(blank, blank, B, pixel_type="RGB24")
StackHorizontal(R2, G2, B2)
http://i3.imageban.ru/out/2014/04/06/c1b400bdcc9e1e05cdab845e2028512c.png
--------
For YUV:
# Source
ImageSource("4.2_04.png", end=0)
ConvertToYV24(matrix="PC601")
o = last
# Processing
U = UToY8()
V = VToY8()
Blank = BlankClip(U, color_yuv=$808080)
Y = MergeRGB(o,o,o, pixel_type="RGB24")
U2 = YToUV(U, Blank, Blank)
V2 = YToUV(Blank, V, Blank)
UV = StackHorizontal(U2,V2).ConvertToRGB24(matrix="PC601")
StackHorizontal(Y, UV)
http://i2.imageban.ru/out/2014/04/06/efab1162fe96506fd367c6858e2321df.png
Wilbert
7th April 2014, 18:29
Just use RGBAdjust (setting r=g=0 for showing blue for example) and use ColorYUV (setting gain_y=-1, cont_u=-1 for showing v).
EncodedMango
8th April 2014, 04:54
That's really neat!
Might I ask what you're running the script in for the output or if you're using ImageWriter?
EDIT:
I stacked them vertically and used ImageWriter to output to bmp.
ImageWriter("%RGB.bmp")
ImageWriter("%YUV.bmp")
raffriff42
8th April 2014, 07:04
Nice, here's a little variation:
https://www.dropbox.com/s/lfi34nxsq48az7p/decompose-YUV-lena.jpg?raw=1
https://www.dropbox.com/s/vcxpue2vqyxuqyl/decompose-YUV-colorbars.png?raw=1## (requires MaskTools)
r = Last.ConvertToRGB24
ConvertToYV24(matrix="PC.601")
o = last
U = UToY8()
V = VToY8()
Blank = BlankClip(U, color_yuv=$808080)
UA = U.mt_lut(("(x < 128) ? 128 : x").mt_polish)
UB = U.mt_lut(("(x > 128) ? 128 : x").mt_polish)
VA = V.mt_lut(("(x < 128) ? 128 : x").mt_polish)
VB = V.mt_lut(("(x > 128) ? 128 : x").mt_polish)
Y = MergeRGB(o, o, o, pixel_type="RGB24")
U2A = YToUV(UA, Blank, Blank)
U2B = YToUV(UB, Blank, Blank)
V2A = YToUV(Blank, VA, Blank)
V2B = YToUV(Blank, VB, Blank)
UVA = StackHorizontal(U2A._sub("U+"), V2A._sub("V+"))
UVB = StackHorizontal(U2B._sub("U-"), V2B._sub("V-"))
StackVertical(
\ StackHorizontal(r, UVA.ConvertToRGB24(matrix="PC.601")),
\ StackHorizontal(Y, UVB.ConvertToRGB24(matrix="PC.601")))
return Last
function _sub(clip C, string msg) {
return C.Subtitle(msg, align=5, size=C.Height/8, text_color=$c0c0c0)
}
wonkey_monkey
8th April 2014, 22:17
Aside: I've often wondered why that image is still widely used in tests; it's washed out, soft, and only features a narrow range of colour.
Reel.Deel
9th April 2014, 16:31
Just use RGBAdjust (setting r=g=0 for showing blue for example) and use ColorYUV (setting gain_y=-1, cont_u=-1 for showing v).
Thanks for the response Wilbert. RGBAdjust works as expected but with ColorYUV(gain_y=-1, cont_u=-1) the output still looks the same as the input.
That's really neat!
Might I ask what you're running the script in for the output or if you're using ImageWriter?
I usually used AvsPmod or the good ol' VirtualDub but ImageWriter works just as well.
Nice, here's a little variation: Thanks raffriff42, that's nice.
Aside: I've often wondered why that image is still widely used in tests; it's washed out, soft, and only features a narrow range of colour.
Yeah I agree that picture is dull.
---------
Regarding YUV color decomposition, I've come across 2 different methods of doing this:
1). MATLAB
The code used is here (http://commons.wikimedia.org/wiki/File:Barns_grand_tetons_YCbCr_separation.jpg#Generator_code) and the output looks identical to the YUV script in the first post.
2). Perl or ImageMagick
This is the Perl script (http://en.wikipedia.org/wiki/File:Barn-yuv.png#Generation) used. There's a comment about this code being wrong but I'm not sure if it was ever fixed or not, there's even a thread how to do this with ImageMagick. (http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=19873#p78480)
Regardless here's how to do it with AviSynth.
# Source
ImageSource("4.2_04.png", end=0)
ConvertToYV24(matrix="PC.601")
o = last
# Processing
U = UToY8()
V = VToY8()
U2 = U.Invert()
V2 = V.Invert()
Blank = BlankClip(U, color_yuv=$000000)
Y = MergeRGB(o,o,o, pixel_type="RGB24")
U = MergeRGB(Blank, U2, U, pixel_type="RGB24")
V = MergeRGB(V, V2, Blank, pixel_type="RGB24")
UV = StackHorizontal(U,V)
StackHorizontal(Y, UV)
https://dl.dropboxusercontent.com/s/iyud3v99r6mhio8/YUV2.png
What method do you guys think it's more accurate? IMO I think it's the MATLAB method...
Gavino
9th April 2014, 18:32
with ColorYUV(gain_y=-1, cont_u=-1) the output still looks the same as the input.
It should be ColorYUV(gain_y=-256, cont_u=-256)
cretindesalpes
9th April 2014, 19:31
Whatever the method, I think the chroma should be scaled according to the luma.
Function decompose_yuv (clip src)
{
src
Assert (IsYUV (), "decompose_yuv: clip must be YUV")
b = last.BlankClip (color_yuv=$808080)
y = ConvertToY8 ()
u = UToY8 ()
v = VToY8 ()
y2 = IsYV24 () ? y : y.BicubicResize (u.Width (), v.Height ())
u = mt_lutxy (u, y2, "y 0 > x 128 - 128 * y / 128 + x ?")
v = mt_lutxy (v, y2, "y 0 > x 128 - 128 * y / 128 + x ?")
y = YToUV (b.UToY8 (), b.VToY8 (), y)
u = YToUV (u , b.VToY8 (), b)
v = YToUV (b.UToY8 (), v , b)
Interleave (y, u, v)
}
raffriff42
9th April 2014, 20:18
It should be ColorYUV(gain_y=-256, cont_u=-256)Use this and never worry about ColorYUV's strange argument scaling again :)### transform "normal" float arguments to
### ColorYUV's "gain_x", "gamma_x" & "cont_x" scale
##
function f2cuv(float f) {
return Round((f - 1.0) * 256.0)
}
/*
# example:
return Subtract(
\ ColorYUV(gain_y=-256, cont_u=-256),
\ ColorYUV(gain_y=f2cuv(0), cont_u=f2cuv(0))
\ )
*/
Reel.Deel
16th April 2014, 13:57
Whatever the method, I think the chroma should be scaled according to the luma.
Thanks for the input, with your method the decomposed chroma looks a bit more defined.
If I'm understanding correctly luma and chroma are compared pixel by pixel. If a luma pixel is greater than 0, replace that pixel by ((((x-128)*128)/y)+128) and if not leave the original chroma pixel value.
Regarding mt_lutxy, I understand the concept but how does one really come up with such an expression? Is there a general guideline? What baffles me is how do you know when to add, subtract, etc.? And ultimately how do you know if it's correct or not?
cretindesalpes
21st April 2014, 11:25
If I'm understanding correctly luma and chroma are compared pixel by pixel. If a luma pixel is greater than 0, replace that pixel by ((((x-128)*128)/y)+128) and if not leave the original chroma pixel value.
Actually it just means: adjust the contrast of each pixel individually to reach a luma of 128.
The comparison with 0 is just here to avoid to divide by 0.
Because the chroma is centered around 128, we need to shift it to 0 for the scaling with the -128, and shift it again after operation with +128.
In the expressions, /y scales the contrast to unity, and *128 scales it to the target luma.
For the mt_lut* expression, you have to be familiar with the Reverse Polish Notation (http://en.wikipedia.org/wiki/Reverse_Polish_Notation). If youre not, there is a mt_polish() function to convert natural expressions to RPN.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.