View Full Version : 1080p 4:2:0 to 540p 4:4:4 without resizing chroma?
Reel.Deel
5th January 2014, 14:08
Hi everyone,
I'm wondering if is possible to correctly downscale 1080p 4:2:0 to 540p 4:4:4 without resizing chroma?
Using the idea and example from here (http://forum.doom9.org/showthread.php?p=1646992#post1646992), this is what I have so far.
# 1920x1080p Source
DGSource("00042.dgi")
# Processing
Y = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2)
U = UToY8()
V = VToY8()
YToUV(U, V, Y)
ConvertToRGB24(matrix="Rec709")
To the eye it looks good but I don't know if it's technically correct.
feisty2
5th January 2014, 14:21
most yv12 clips are top left aligned so you shouldn't use a center aligned resizer to resize the luma and merge it to a top left aligned chroma
instead, using a top left aligned resizer should be correct, something like xxxresize (960,540,src_top=1,src_left=1)
Reel.Deel
14th January 2014, 06:21
Okay, so I had some time and I did some test to try to figure out the correct offsets regarding chroma position. Since I want to leave the chroma untouched the alternative is to shift the luma when resizing.
I don't really know what I'm doing so I tried a handful of different offset values.
Just a sample:
# 1920x1080p Source
DGSource("00042.dgi")
# Processing
Y = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2, src_left=0.00, src_top=0.00).Subtitle("Y")
Y2 = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2, src_left=0.25, src_top=0.00).Subtitle("Y2")
Y3 = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2, src_left=0.50, src_top=0.00).Subtitle("Y3")
Y4 = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2, src_left=0.50, src_top=0.75).Subtitle("Y4")
Y5 = ConvertToY8(matrix="Rec709").Spline36Resize(width/2, height/2, src_left=1.00, src_top=1.00).Subtitle("Y5")
U = UToY8()
V = VToY8()
Y = YToUV(U, V, Y)
Y2 = YToUV(U, V, Y2)
Y3 = YToUV(U, V, Y3)
Y4 = YToUV(U, V, Y4)
Y5 = YToUV(U, V, Y5)
Interleave(Y, Y2, Y3, Y4, Y5)
PointResize(width*2, Height*2) # for testing only
ConvertToRGB24(matrix="Rec709")
After all that I think src_left=0.50, src_top=0.75 produced better results (at least to my eyes) although I think it's incorrect. In the end, I'm still left with uncertainty.:(
Does anyone know the math involved to calculate the correct offsets?
No. It is incorrect code. I tried this way some time ago and got color artifacts (chroma placement)...
To be honest I do not see any obvious color artifacts, if anything the incorrect offsets are hardly noticeable.
Gavino
14th January 2014, 11:54
The correct offsets are src_left=-0.50, src_top=0.
Avisynth resizers preserve the position of the image centre (treating the pixels as point samples).
For 4:2:0 with MPEG2 placement, the horizontal chroma centre is 0.5 luma pixels to the left of the luma centre.
luma centre
|
Luma: L L L L ... L L L L ... L L L L
Chroma: C C ... C C ... C C
|
chroma centre
Therefore, to make the resized luma coincide with the original chroma, you need src_left=-0.5.
Since the vertical centre positions are the same for luma and chroma, src_top=0.
The visual difference when using the wrong offsets (or no offsets) is very small except where you have a sharp chroma transition.
mastrboy
14th January 2014, 13:26
I have 2 generic questions about downscaling 1080p 4:2:0 to 540p 4:4:4 someone hopefully could answer:
- In a blind sample test would you actually be able to differentiate between a 540p 4:2:0 and a 540p 4:4:4 downscaled from a good BD source?
- For a generic source, how much would the filesize increase when using x264 and crf encoding at for example crf 16 ? (A guesstimate is good enough)
Reel.Deel
14th January 2014, 16:05
The correct offsets are src_left=-0.50, src_top=0.
I'm not surprised that I was completely wrong (didn't even try negative values :o)
Thank you very much Gavino. Your illustration helps me understand the offsets a bit better...(Now I'm going to read this post (http://forum.doom9.org/showpost.php?p=1506374&postcount=385) multiple times :))
wonkey_monkey
14th January 2014, 17:34
I have 2 generic questions about downscaling 1080p 4:2:0 to 540p 4:4:4 someone hopefully could answer:
- In a blind sample test would you actually be able to differentiate between a 540p 4:2:0 and a 540p 4:4:4 downscaled from a good BD source?
I think you'd have to run the test (since the point of a blind test is to get at what people can see, not what people say they can see). My answer would be an unequivocal "maybe" ;)
In normal viewing conditions, with normal content, I'd say it's unlikely. That's 4:2:0's raison d'etre, after all.
DarkSpace
14th January 2014, 22:36
I'm just trying to grasp this logically, but wouldn't a left shift mean that you should use
in = BlankClip(pixel_type="YV12")# or any other YV12 source, really
Y = ConvertToY8().Spline36Resize(in.Width()/2, in.Height()/2, src_left=-0.5, src_width=-0.5)
U = UToY8()
V = VToY8()
YToUV(U, V, Y)
instead? As I understand it, all that src_left=-0.5 does by itself is "widen" the resolution to Width+0.5...
Gavino
15th January 2014, 00:22
The default for src_width is the width of the input (not zero as in Crop()), so it can be omitted.
src_width=-0.5 has the same effect and is also correct.
DarkSpace
15th January 2014, 12:21
The default for src_width is the width of the input (not zero as in Crop()), so it can be omitted.
src_width=-0.5 has the same effect and is also correct.
Thanks. I've been wondering how that fits for some time, but I always assumed Crop-like behavior. No wonder I was wrong.
Divet
24th January 2014, 11:32
The correct offsets are src_left=-0.50, src_top=0.
May I ask another question here, would You advise me, please?
If I want to make 1280x720 4:4:4 bd-rip from 1920x1080 4:2:0 source blu-ray (Yes, I know it won't be "true" 4:4:4 color but It will be better than 4:2:0, because less source data will be lost) what code (or both) will be right (or not)?
Y = ConvertToY8().Spline36Resize(1280, 720, src_left=-0.5)
U = UToY8().Spline36Resize(1280, 720)
V = VToY8().Spline36Resize(1280, 720)
YToUV(U, V, Y)
Y = ConvertToY8().Spline36Resize(1280, 720)
U = UToY8().Spline36Resize(1280, 720, src_left=0.25)
V = VToY8().Spline36Resize(1280, 720, src_left=0.25)
YToUV(U, V, Y)
Gavino
24th January 2014, 17:37
what code (or both) will be right (or not)?
Both are correct as far as chroma alignment is concerned.
The first one shifts the luma centre 0.5 pixels to the left so it lines up with the chroma centre. The second one shifts the chroma centre 0.25 chroma pixels (=0.5 luma pixels) to the right, again producing alignment.
I prefer the second one conceptually as it seems more consistent with normal resizing to preserve the luma centre.
Divet
24th January 2014, 19:00
Both are correct as far as chroma alignment is concerned.
Thank You very much!
I got it! Now it is clear, when we have progressive blu-ray (1080p).
But I am interesting in 1080i too. Is it more complex? How to resize interlaced Y, U, V independently?
I am talking about true interlaced video, shooted by interlaced camera, such as documentary movies. Not about transferred cinema with pulldown, etc.
First, I do this:SeparateFields()
then I do:video1=SelectEven()
then I must do vertical shift correction! So is it correct to add src_top=0.5 to resizing each panel - Y, U and V? (And do not add src_top=0.5 to resizing Y, U and V from video2=SelectOdd().)
But I am not sure about chroma placement after SeparateFields()... Are both videos (made by SelectEven and SelectOdd) normal, common 4:2:0 progressive videos?
I am not planning to reconstruct interlaced video after resizing. The last lines of my avs scrypt will be:Interleave(video1, video2)
AssumeFrameBasedso the result will be 4:4:4 progressive video with 50fps if pal (or 59.94fps if ntsc)
Gavino
24th January 2014, 22:21
So is it correct to add src_top=0.5 to resizing each panel - Y, U and V? (And do not add src_top=0.5 to resizing Y, U and V from video2=SelectOdd().)
But I am not sure about chroma placement after SeparateFields()... Are both videos (made by SelectEven and SelectOdd) normal, common 4:2:0 progressive videos?
Top fields and bottom fields have different vertical chroma placement relative to luma, neither of which is the same as a progressive 4:2:0 frame - see here (http://avisynth.nl/index.php/Sampling#YV12_color_format).
You need to use src_top=+0.25 when resizing each of Y, U and V for top fields, and src_top=-0.25 similarly for bottom fields.
For a TFF source, SelectEven() gives you the top fields and SelectOdd() the bottom fields. For BFF, it is the other way round.
Divet
25th January 2014, 00:02
You need to use src_top=+0.25 when resizing each of Y, U and V for top fields, and src_top=-0.25 similarly for bottom fields.
I am surprised! This +0.25 and -0.25 I need for vertical shift compensation? I mean, shift between fields = half of one field line (pixel).
And if src_top is the same for Y, U and V, then I can figure out that there is no vertical shift between luma and chroma (in a field). Is it correct?
And what about horizontal shift between luma and chroma? I remember I need src_left=0.25 when resizing U and V! Is it correct for fields?
Gavino
25th January 2014, 01:44
I am surprised! This +0.25 and -0.25 I need for vertical shift compensation? I mean, shift between fields = half of one field line (pixel).
Yes, since displacement between top field and bottom field is one original (full-frame) line, which is half of one field line. (You previously suggested +0.5 and zero, which is also a relative difference of 0.5.)
And if src_top is the same for Y, U and V, then I can figure out that there is no vertical shift between luma and chroma (in a field). Is it correct?
Since chroma spacing is twice luma spacing, the offsets, though numerically equal, represent different distances. (Assuming you are still separating luma and chroma and resizing independently as before.)
So there is a vertical shift between luma and chroma, and that is necessary because (in a field, unlike a progressive frame) their vertical centres are in different places.
And what about horizontal shift between luma and chroma? I remember I need src_left=0.25 when resizing U and V! Is it correct for fields?
Yes, horizontal chroma placement is the same for fields and frames.
Divet
25th January 2014, 09:08
the offsets, though numerically equal, represent different distances.
Understood! Thanks!
(in a field, unlike a progressive frame) their vertical centres are in different places.
This is because different vertical chroma placement, is this?
Yes, horizontal chroma placement is the same for fields and frames.
So we can write this, for example:Y = ConvertToY8().Spline36Resize(1280, 720, src_top=0.25)
U = UToY8().Spline36Resize(1280, 720, src_top=0.25, src_left=0.25)
V = VToY8().Spline36Resize(1280, 720, src_top=0.25, src_left=0.25)
YToUV(U, V, Y)
Gavino
25th January 2014, 15:18
This is because different vertical chroma placement, is this?
Yes, see the reference I gave in post #15, which shows the layout of both progressive and interlaced YV12:
http://avisynth.nl/index.php/Sampling#YV12_color_format
Also the MPEG-2 section of this: http://www.mir.com/DMG/chroma.html
So we can write this, for example:Y = ConvertToY8().Spline36Resize(1280, 720, src_top=0.25)
U = UToY8().Spline36Resize(1280, 720, src_top=0.25, src_left=0.25)
V = VToY8().Spline36Resize(1280, 720, src_top=0.25, src_left=0.25)
YToUV(U, V, Y)
Yes, that's correct for the top fields. For bottom fields, you need src_top=-0.25 in all three places.
Divet
25th January 2014, 21:58
Yes, that's correct for the top fields. For bottom fields, you need src_top=-0.25 in all three places.
Yes! Many thanks!
And if I don't resize something horizontally I don't need src_left=0.25. For example, if I resize chroma 960x270 (one field chroma) to 960x540 or to 960x360. Correct?
Gavino
26th January 2014, 00:25
And if I don't resize something horizontally I don't need src_left=0.25. For example, if I resize chroma 960x270 (one field chroma) to 960x540 or to 960x360. Correct?
No, incorrect.
If you are still downsizing the luma (to match the chroma size and produce a 4:4:4 result), then you still need src_left=0.25 on the chroma, or alternatively src_left=-0.5 on the luma. The luma downsize shifts the luma sampling positions, so the chroma must be shifted to match, even when staying at its original size.
TheSkiller
26th January 2014, 12:31
By the way, not trying to hijack this thread but, wouldn't it be possible to incorporate the horizontal shift correction for resizing horizontally subsampled chroma formats (explained here (http://forum.doom9.org/showthread.php?p=1506374#post1506374)) into some UtoY magic?
All we need is a formula to calculate src_left for U and V, I think.
Now, after some trying I found that the formula used for the MergeChroma(...) correction after resizing *seems* to be correct for src_left. Does this make sense?
#Let's resize a 1280x960 YUY2 clip to 640x480 YUY2.
#Prevent the usual horizontal chroma shift.
Y = ConvertToY8().Spline16Resize(640, 480)
U = UToY8().Spline16Resize(640/2, 480, src_left=-0.25)
V = VToY8().Spline16Resize(640/2, 480, src_left=-0.25)
YToUV(U, V, Y)
ConvertToYUY2() #YV16 to YUY2 (planar to interleaved)
Formula for src_left:
0.25 * (1 - Width_in / Width_out)
Edit: Corrected the formula not to confuse people, thanks Gavino.
Divet
26th January 2014, 16:15
No, incorrect.
If you are still downsizing the luma (to match the chroma size and produce a 4:4:4 result), then you still need src_left=0.25 on the chroma, or alternatively src_left=-0.5 on the luma. The luma downsize shifts the luma sampling positions, so the chroma must be shifted to match, even when staying at its original size.
Yes! Yes! It was my mistake! When I wrote about not to resize chroma horizontally I thought about not to resize luma horizontally too and so produce 4:2:2 video. I forgot to write about that, sorry. I thought about resizing Y, U and V only vertically.
May I ask about pulldowned video now?
If we use:AssumeTFF
Tfm(slow=2)
TDecimate
AssumeFrameBased-what about this output? Is it progressive video? What do You think about luma and chroma in it? How to resize them independently as above?
Gavino
26th January 2014, 17:46
Formula for src_left:
0.5 * (1 - Width_in / Width_out)
Your method is valid, but this formula is incorrect here.
That gives the shift in units of luma pixels, but here we are applying the offset when resizing the chroma, so it needs to be expressed in chroma pixel units (which are twice the width).
Hence src_left = 0.25 * (1 - Width_in / Width_out)
and it should be -0.25 in your example.
May I ask about pulldowned video now?
If we use:AssumeTFF
Tfm(slow=2)
TDecimate
AssumeFrameBased-what about this output? Is it progressive video? What do You think about luma and chroma in it? How to resize them independently as above?
After IVTC, it is progressive and can be processed just as described earlier in this thread for that case.
Divet
27th January 2014, 09:13
Hence src_left = 0.25 * (1 - Width_in / Width_out)
I'm confused. My understanding is not good.
I thought src_left is independ of Width_in / Width_out.
So if we resize 1920 to 1280, src_left must be 0.125?
I haven't understood this. Help me please.
Gavino
27th January 2014, 11:25
It's confusing because we are now talking about two different things.
TheSkiller's code applies to resizing of YUY2 or YV12, to correct the slight horizontal chroma shift which is introduced by the current Avisynth resizers (see this post and the ones following it). Here there is no change in chroma subsampling - both luma and chroma are resized in the same ratio.
Previously, we were discussing using a similar method to convert 4:2:0 to 4:4:4. Here the chroma is doubled in size relative to the luma (and ends up coincident with it). In this case (the one that you were interested in), src_left is independent of the final sizes.
Reel.Deel
27th January 2014, 20:54
Hello again,
Going back to the original topic (full size 4:2:0 to half size 4:4:4 without resizing chroma) I have another scenario which I don't know if it's correct or not.
I have some 4:2:0 JPEGs that I want to convert to half size 4:4:4. If I'm understanding correctly, JPEGs use the MPEG-1 chroma placement meaning that the chroma is center aligned (http://avisynth.nl/index.php/Sampling#mpeg-1_versus_mpeg-2_sampling) with luma both horizontally and vertically.
So does that mean that the defaults (src_left=0, src_top=0) are correct?
Example:
# 1600x1200 JPEG
JpegSource("20120502_235247.jpg", rec=0, length=1)
# Processing
Y = ConvertToY8().Spline36Resize(width/2, height/2)
U = UToY8()
V = VToY8()
YToUV(U, V, Y)
ConvertToRGB24(matrix="PC.601") #for testing only
Gavino
27th January 2014, 21:40
If I'm understanding correctly, JPEGs use the MPEG-1 chroma placement meaning that the chroma is center aligned (http://avisynth.nl/index.php/Sampling#mpeg-1_versus_mpeg-2_sampling) with luma both horizontally and vertically.
So does that mean that the defaults (src_left=0, src_top=0) are correct?
Yes, assuming your info on JPEGs is correct (I don't know if that's true or not).
Reel.Deel
28th January 2014, 00:57
Yes, assuming your info on JPEGs is correct (I don't know if that's true or not).
Thanks for the confirmation. Regarding 4:2:0 JPEGs having MPEG-1 chroma placement, I didn't really know that until I read this:
Remember that JPEGs use PC levels, Rec.601 colorspace and MPEG1 chroma position most of the time.
After reading that I did some research and I've found JPEGsnoop to be a handy tool for correctly identifying JPEG chroma placement. Most original JPEGs have metadata with the YCbCrPositioning (http://freeimage.sourceforge.net/fnet/html/4A015DE9.htm) property; it can either be "centered" or "co-sited".
After testing lots of pictures I came to the conclusion that all of my 4:2:0 JPEGs taken with various camera phones are "centered" and 4:2:2 JPEGs taken 2 different cameras are "co-sited".
This Chrominance Subsampling in Digital Images (http://dougkerr.net/Pumpkin/articles/Subsampling.pdf) PDF (page 3-6) has good information on the chroma placement between "centered" and "co-sited". Lastly, this Chroma Subsampling Notation (http://www.poynton.com/PDFs/Chroma_subsampling_notation.pdf) PDF (page 2) describes JPEG/JFIF, H.261, and MPEG-1 as having the same chroma placement.
I hope I'm not misunderstanding something.
TheSkiller
7th January 2015, 17:26
Sorry to revive this thread but I need help figuring out the correct value for src_left in the following scenario:
4:4:4 (YV24) to 4:2:2 (YV16 with standard MPEG2 siting), so basically the reverse of what the original OP did.
Say I want to resize a 640x480 YV24 clip to 1024x768 YV16 – which is the correct value for src_left and why?
Reel.Deel
8th January 2015, 05:33
Assuming YV24 input, ConvertToYV16() uses src_left=-0.50, just like the example below:
y = last
u = UToY8().BicubicResize(width/2, height, src_left=-0.50)
v = VToY8().BicubicResize(width/2, height, src_left=-0.50)
YToUV(u, v, y)
So to go from a 640x480 YV24 to 1024x768 YV16:
y = ConvertToY8().BicubicResize(1024, 768)
u = UToY8().BicubicResize(Width(y)/2, Height(y), src_left=-0.50)
v = VToY8().BicubicResize(Width(y)/2, Height(y), src_left=-0.50)
YToUV(u, v, y)
I'm not 100% sure so feel free to smack me around if I'm wrong. :)
colours
8th January 2015, 17:06
Almost, but not quite. That doesn't take into account that the output has a different sampling rate; the −0.5 shift applies to the output, not the input.
y = ConvertToY8().BicubicResize(1024, 768)
u = UToY8().BicubicResize(Width(y)/2, Height(y), src_left=-0.50*Width(last)/Width(y))
v = VToY8().BicubicResize(Width(y)/2, Height(y), src_left=-0.50*Width(last)/Width(y))
YToUV(u, v, y)
This fits intuition if you consider resizing to either an extremely small size or extremely large size. The smallest size you can go is to a width of two pixels, and in that case the shift involved should be the largest. On the other hand, with large sizes, the effect of the shift should tend to zero, and hence the shift itself (measured in input samples) should also tend to zero.
(Why won't MPEG-2 chroma siting just die already?)
TheSkiller
9th January 2015, 17:29
Thanks for the answers, that makes perfect sense.
So here is a little recap.
1) When resizing in horizontally subsampled color spaces the standard resizers produce a slight horizontal chroma shift (see this post (http://forum.doom9.org/showthread.php?p=1505975#post1505975) and following). To overcome this we can do the resize the manual way and apply the necessary shift to the chroma planes (U, and V) via the src_left argument of the resizer.
To prevent the shift when resizing in all horizontally subsampled color spaces (except 4:1:1!) src_left can be calculated as follows.
src_left = 0.25 * (1 - Width_in / Width_out)
Example resize from any horizontally subsampled color space (except 4:1:1!) to 704x576 YV12 (src_left is calculated automatically).
Y = ConvertToY8().Spline16Resize(704, 576)
U = UToY8().Spline16Resize(Width(Y)/2, Height(Y)/2, src_left=0.25*(1-Float(Width(Last))/Width(Y)))
V = VToY8().Spline16Resize(Width(Y)/2, Height(Y)/2, src_left=0.25*(1-Float(Width(Last))/Width(Y)))
YToUV(U, V, Y)
2) When resizing from a 4:2:0 or 4:2:2 subsampled color space to 4:4:4 (YV24) the shift for U and V is always constant.
src_left = 0.25
3) When resizing from 4:4:4 (YV24) to a horizontally subsampled color space (excluding 4:1:1!) the shift can be calculated as follows:
src_left = -0.50 * Width_in / Width_out
For an example with automatically calculated src_left see colours' post above.
Everybody agree? :)
Reel.Deel
12th January 2015, 23:57
Thanks for the recap makes it much easier to follow.
Everybody agree? :)
1) I checked the output against Resize8 (https://www.nmm-hd.org/newbbs/viewtopic.php?t=1323) (with correct settings, of course) and the results are identical.
2) Is consistent with the way AviSynth does things. Although there was an issue submitted to AviSynth+ (https://github.com/AviSynth/AviSynthPlus/issues/48) that makes me wonder.
3) I believe colours knows what he's talking about. :)
----
One more thing, can PointResize be used to do lossless subpixel shifting? For example lets say I have a YV12 JPEG file with MPEG1 chroma siting that I want to convert to MPEG2 (or vice versa).
JpegSource("pic.jpg")
Y = last
U = UToY8().PointResize(width/2, height/2, src_left=-0.25) # for MPEG2 to MPEG1 src_left=0.25
V = VToY8().PointResize(width/2, height/2, src_left=-0.25) # for MPEG2 to MPEG1 src_left=0.25
YToUV(U, V, Y)
Does this work correctly or are there some caveats I'm unaware about?
colours
13th January 2015, 03:44
3) I believe colours knows what he's talking about. :)
The flattery is nice, but sometimes I'm wrong too. Only sometimes, though!
One more thing, can PointResize be used to do lossless subpixel shifting?
[snip]
Does this work correctly or are there some caveats I'm unaware about?
You can't do subpixel shifting with PointResize because it uses only integer pixel coordinates. For that matter, there's no finite impulse response filter other than the no-op (and integer translations) which, when convolved with its reverse, results in the no-op filter. (This is not difficult to prove, but this isn't a mathematics forum.)
There are sort-of-reversible ways of doing a subpixel shift; if you use BilinearResize or BicubicResize to shift by a fractional amount, you'll necessarily lose some precision due to rounding error, but you can still use Debilinear or Debicubic to unshift the image.
Dogway
18th January 2015, 23:50
TheSkiller's code applies to resizing of YUY2 or YV12, to correct the slight horizontal chroma shift which is introduced by the current Avisynth resizers (see this post and the ones following it).
Is this for real? still to this day? does that mean that whatever we have been resizing with simple spline36resize() or lanczos is wrong? I'm a bit shocked so asking for confirmation. I thought chroma placement was only needed when explicitly dealing with it (converting from one to other).
3) When resizing from 4:4:4 (YV24) to a horizontally subsampled color space (excluding 4:1:1!) the shift can be calculated as follows:
src_left = -0.50 * Width_in / Width_out
Where does the 0.50 comes from? The misalignment of the resizers for chroma planes has an offset of 1/4 (0.25) in respect to luma.
colours
19th January 2015, 01:26
Where does the 0.50 comes from? The misalignment of the resizers for chroma planes has an offset of 1/4 (0.25) in respect to luma.
You have to consider the units here.
When we're looking at 4:2:0/4:2:2 with MPEG-2 chroma siting, the horizontal offset is 0.5 luma sample. It's just that chroma samples are twice as "wide" as luma samples, so 0.5 luma sample = 0.25 chroma sample.
If we start from 4:4:4, our original chroma sample width is the same as the luma sample width, so the chroma planes should be shifted by 0.5 when horizontally subsampling chroma with MPEG-2 siting.
feisty2
19th January 2015, 04:21
Is this for real? still to this day? does that mean that whatever we have been resizing with simple spline36resize() or lanczos is wrong? I'm a bit shocked so asking for confirmation. I thought chroma placement was only needed when explicitly dealing with it (converting from one to other).
Where does the 0.50 comes from? The misalignment of the resizers for chroma planes has an offset of 1/4 (0.25) in respect to luma.
BTW...subpixel=3 and pel=4 is wrong in smdegrain
it should be nnedi3_rpow2 (rfactor=2).nnedi3_rpow2 (rfactor=2), not nnedi3_rpow2 (rfactor=4), check awarp4 document
Dogway
19th January 2015, 09:07
The -0.5 shift applies to the output, not the input.
If the output is subsampled chroma plane it's not 0.5 spacing anymore, it should be 0.25. It severely depends on what is done first.
feisty2: wrong thread. But if you are in a hurry, go fix nnedi3 (http://forum.doom9.org/showthread.php?p=1507235#post1507235).
colours
19th January 2015, 12:21
If the output is subsampled chroma plane it's not 0.5 spacing anymore, it should be 0.25. It severely depends on what is done first.
I guess I was being a bit sloppy with my explanation.
I meant 0.5 luma output sample, which equals to 0.25 chroma output sample. But our input chroma is not subsampled, so shifting it by x luma input samples (in this case x = 0.5⋅output_width/input_width) is the same as shifting it by x chroma input samples. There's no need to divide by two.
TheSkiller
19th January 2015, 21:01
Is this for real? still to this day? does that mean that whatever we have been resizing with simple spline36resize() or lanczos is wrong?Well, after some testing just now using the very latest AviSynth 2.6 RC 1 [150114] I found that the shift is still there.
Using this test pattern's (http://en.wikipedia.org/wiki/Philips_PM5544) Y/C delay test area (PNG image) and these scripts, this is what happens.
First, here is a reference with no resize at all.
ImageSource("PM5544_with_non-PAL_signals.png")
ConvertToYV16()
ConvertToRGB()
Crop(240,460,-240,-30)
PointResize(Width*2, Height*2) #for better visibility
Subtitle("No Resize at all (just RGB->4:2:2->RGB)")
http://picload.org/image/cigrdir/no_resize.png
Here is plain Spline36Resize, out of the box.
ImageSource("PM5544_with_non-PAL_signals.png")
ConvertToYV16()
Spline36Resize(Width*32, height)
ConvertToRGB()
Spline36Resize(Width/32, height)
Crop(240,460,-240,-30)
PointResize(Width*2, Height*2) #for better visibility
Subtitle("Plain Spline36Resize")
http://picload.org/image/cigrdia/plain.png
Here is a corrected Spline36Resize.
ImageSource("PM5544_with_non-PAL_signals.png")
ConvertToYV16()
Y = ConvertToY8().Spline36Resize(Width*32, 576)
U = UToY8().Spline36Resize(Width(Y)/2, Height(Y), src_left=0.25*(1-Float(Width(Last))/Width(Y)))
V = VToY8().Spline36Resize(Width(Y)/2, Height(Y), src_left=0.25*(1-Float(Width(Last))/Width(Y)))
YToUV(U, V, Y)
ConvertToRGB()
Spline36Resize(Width/32, height)
Crop(240,460,-240,-30)
PointResize(Width*2, Height*2) #for better visibility
Subtitle("Corrected Resize")
http://picload.org/image/cigrdic/corrected.png
I guess it's almost safe to say this is close to impossible to detect in a real life image. But it's still there, yeah.
Dogway
19th January 2015, 21:38
Yes, I tested yesterday and found out, also tested Dither_resize16() and luckily cretindesalpes got that covered (matches results from Resize8() ), so my panic level decreased.
It just feels odd that a "restoration" program degrades an image in some form, and nobody cares. Same with nnedi
I meant 0.5 luma output sample, which equals to 0.25 chroma output sample. But our input chroma is not subsampled, so shifting it by x luma input samples (in this case x = 0.5·output_width/input_width) is the same as shifting it by x chroma input samples. There's no need to divide by two.
I still need to wrap up my mind on all this, but I had this stuck on my mind:
The resizer core is designed to preserve the position of the image centre, and it does this for both luma and chroma independently.
That means MPEG1 placement which has an offset of (this is the tricky part) one quarter of a chroma pixel in relation to luma for a MPEG2 siting. image (http://www.mir.com/DMG/css-420-jpeg.png)This is subsampled, as the output of the example we are talking 4:4:4->4:2:0
Not saying it's wrong just that it feels I'm missing something. I will look onto this better tomorrow. edit: I think I got it, src_left is not applied before or after, just at the same time as the resizing, it's hard to grasp but I think I figured it out.
TheSkiller
19th January 2015, 21:57
Yes, I tested yesterday and found out, also tested Dither_resize16() and luckily cretindesalpes got that coveredDidn't know that. Indeed, Dither_Resize16 is correct. Nice! :)
ImageSource("PM5544_with_non-PAL_signals.png")
ConvertToYV16()
Dither_convert_8_to_16()
Dither_Resize16(Width*32, 576, kernel="Spline36")
Ditherpost(mode=-1)
ConvertToRGB()
Spline36Resize(Width/32, height)
Crop(240,460,-240,-30)
PointResize(Width*2, Height*2) #for better visibility
Subtitle("Dither_Resize16")
http://picload.org/image/cigrowc/resize16.png
feisty2
11th February 2015, 18:30
Those two are the same expression...
Do the 10 years old kid math urself
Edit: 0.25-0.25/(out/in)=0.25(1-1/(out/in))=0.25(1-in/out)
Dogway
11th February 2015, 18:44
Those two are the same expression...
Do the 10 years old kid math urself
Edit: 0.25-0.25/(out/in)=0.25(1-1/(out/in))=0.25(1-in/out)
How old are you?
jpsdr
31st July 2015, 21:22
feisty2: wrong thread. But if you are in a hurry, go fix nnedi3 (http://forum.doom9.org/showthread.php?p=1507235#post1507235).
I've tried.:cool:
Any test, feedback, comment on the formula used in the code are welcomed :p.
You can find informations here (http://forum.doom9.org/showthread.php?t=170083).
kuchikirukia
31st July 2015, 22:34
About the resize chroma problem, is there a way to write a script to get Resize8 to catch all calls to Spline36resize? Since I have tons of scripts that use Spline36resize.
And is the replacement of Lanczos with Spline36 here:
kernel = Default(kernel, yup ? "Lanczos4" : "Spline36")
kernel_c = Default(kernel_c, cup ? "Lanczos" : "Spline36")
... all I need to change for my Resize8 to use Spline36 for everything as default?
luquinhas0021
31st July 2015, 23:01
My dear friend, how are you thinking about convert YCbCr 4:2:0 to YCbCr 4:4:4? As I know, YCbCr subsampling makes a lot of pixels have only Y value. So how recover the miss information?
Wilbert
31st July 2015, 23:43
Did you even bother to read the thread? They scale the luma plane by a factor of two (guess some prefer to use Spline36Resize for that) and they adjust the offset of the chroma with respect to the luma.
Nb, when there is subsampling it means that several pixels share the same chroma, and not that some don't have chroma.
luquinhas0021
3rd August 2015, 18:39
Wilbert, thank you so much for you correct me about subsampling, but I guess you didn't get me completely! if I subsample from YUV 444 to YUV 420, for example, I will lost so much chroma information, so will be praticaly impossible I recover that. Considering that subsample generates artifacts, in better case, the interpolation to YUV 444 will maintain that, without creates more (What didn't occur with Spline36). So, even you try convert to YUV 444, probably you will never have a true 444.
poisondeathray
3rd August 2015, 22:17
Wilbert, thank you so much for you correct me about subsampling, but I guess you didn't get me completely! if I subsample from YUV 444 to YUV 420, for example, I will lost so much chroma information, so will be praticaly impossible I recover that. Considering that subsample generates artifacts, in better case, the interpolation to YUV 444 will maintain that, without creates more (What didn't occur with Spline36). So, even you try convert to YUV 444, probably you will never have a true 444.
That is not what the topic is about - you are not "recovering" information, you are downscaling the Y' channel
YUV 420 at 1920x1080 means Y is 1920x1080, but U,V are 960x540. You are downscaling Y to match U, V
Y - 960x540
U - 960x540
V - 960x540
That is 4:4:4
Similarly , if you had UHD 4:2:0, you can downscale to 1080 4:4:4
Nothing is "true 4:4:4" unless it's CG , or oversampled by a large margin. Even high end expensive cameras that shoot 4:4:4 don't really have 4:4:4 resolution when measured on zone plates. Effective resolution is lost due to processing, debayering. Only if you oversample and downscale, can you get true 4:4:4
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.