Log in

View Full Version : Understanding Sub-Pixel Shift


MysteryX
13th July 2016, 06:42
There's the issue of sub-pixel shift that comes up now and then. I have a few questions about that.

What is the issue exactly and what causes that?

ResizeX apparently fixes that issue for standard resizers. What does ResizeX do exactly, and does it make sense to keep this limitation in the standard resizers of should Avisynth+ make the native resizers work right?

When resizing the chroma for YV12-YV24 conversion, do I have to make any such correction?

colours
13th July 2016, 06:54
The issue is that the majority of videos produced nowadays use MPEG-2 chroma siting and 4:2:0 subsampling, so if you look at a 2×2 block of luma samples, the logical location of the chroma sample is between the top-left and the bottom-left sample. However, AVS's resizers always assume MPEG-1/JPEG chroma siting instead, where the logical location of the chroma sample is exactly in the centre of the block of luma samples.

This discrepancy causes a shift, which may or may not be noticeable for very large resampling ratios.

MysteryX
13th July 2016, 07:25
The ConvertTo... functions have a parameter to specify chroma placement (MPEG2 by default). Don't internal resizer functions have that argument?

If not, that parameter should be added.

jpsdr
13th July 2016, 08:38
Check all the posts on the following thread here (http://forum.doom9.org/showthread.php?p=1660744#post1660744).
Also interesting is this (http://www.mir.com/DMG/chroma.html).

geometer
14th July 2016, 08:29
playing around with this function
function CShft(clip In, float X, float Y) {
w = In.Width()
h = In.Height()
In = MergeChroma(In, In.BlackmanResize(w, h, -X, -Y, w-X, h-Y, 5))
return In}
based on a snippet I found here, that sure has its computing cost,
I found out that it is very handy to control chroma sharpness at the same time, with the choice of the actual type of filtering.
I also preferred to use negative parameters for the correction of the typical shifts that come from the decoding or other processing.
(so far I didn't translate it into the 16 bit versions, but should be straightforward.)

example:
CShft(last,-0.66,0.0)

from the theory, I can make a guess on the values that might be correct, but only the magnifying glass on the result will judge anything.

StainlessS
14th July 2016, 17:15
but only the magnifying glass on the result will judge anything

http://forum.doom9.org/showpost.php?p=1762188&postcount=186

TheFluff
15th July 2016, 00:10
if you actually care about this stuff you could just implement the zimg resizers (https://github.com/sekrit-twc/zimg) for avisynth as a plugin, all the hard problems are already solved

MysteryX
15th July 2016, 03:34
if you actually care about this stuff you could just implement the zimg resizers (https://github.com/sekrit-twc/zimg) for avisynth as a plugin, all the hard problems are already solved
For once I have to say I agree with you. This library seems to solve many of the problems that need to be re-programmed in AviSynth, such as 16-bit processing and dithering. However, most of the features are already implemented in AviSynth and maintaining compatibility and the same behaviors as expected is important. For that reason, I expect the missing functions like Dithering to just be reprogrammed.

Actually... Z library doesn't need to be part of the core. It definitely can be added as a plugin as you say.

playing around with this function
function CShft(clip In, float X, float Y) {
w = In.Width()
h = In.Height()
In = MergeChroma(In, In.BlackmanResize(w, h, -X, -Y, w-X, h-Y, 5))
return In}
What benefits does this have over ResizeX functions?

Do the ResizeX functions, or performing a sub-pixel shift, have a cost on quality? Meaning if I do it one way, redo it the other way, do I get the same image back or it is distorted?

Now I'm thinking. Even if the standard function does it right, if we split the 3 planes and process the 3 planes separately, the output will be wrong as it won't know the difference between the Luma and Chroma planes. Would that produce the exact same distortion as you get with the standard function?

Also -- and here is a slightly different topic. I'm looking at the HLSL Bicubic code (https://github.com/mysteryx93/AviSynthShader/blob/master/Src/Shaders/Src/Bicubic.hlsl#L67), and I see it evaluates a ratio on the Y plane and applies it on all 3 planes. If I want to resize only the chroma, will that give a different result or that's fine?

And finally, in terms of the resize method, is there a difference between downscaling from 4:4:4 into 4:2:0 or into 4:2:2, or I can just use the same methods and change the resize dimensions?

geometer
19th July 2016, 12:26
@MysteryX it's just that I tested this, and quality and speed are enough for me, though I am considering I might switch to >=10 bit per plane one day. also, I have no computer with a usable GPU, purely business oriented.
it's worth a try.
it's a correctional tool, quite transparent, as I don't bother figuring out chroma sub that was mastered down incorrectly anyway, in many CDs, and the filtering chain has all kinds of issues as it is free, so who would bother to create all these data structures and push through a reliable standard. there are a few heroes only. kudos :)
perhaps the next avisynth generation will have it. (full analysis of chroma placement and matrix/level issues, more detailed meta data to propagate throughout the chain, meta data that technically describes a whole video e.g. suggested scene changes, histogram changes, spectrum changes, etc etc., all plugins have lead-in and lead-out automatics for required conversions, and optional internal upsampling, and they report what they have done and found, and another analyzer tells about unnecessary conversions and how to avoid them, similar to query execution path analysis in sql server. that would be professional though. in theory, the engine should easily be extended to provide a coherent execution plan and there to plug in info by plugins that report what they did.)
avidemux has some automatism, but not too reliable. we end up with erranous chroma shift as a side effect of otherwise powerful filters. but they are ported from avisynth.
just stuffing 25% of i7 processing into avisynth chain, and 75% into avidemux/x264. nosebleed minimized.

raffriff42
20th July 2016, 02:54
In the script below, the chroma offset varies from -2 to +2 pixels in 64 steps. You view the clip in frame jog, noting the shift that looks "best" (which will most likely be different for horizontal and vertical). Yes you need to use a magnifier of some kind. Run the test for both U and V channels. Now you know the shift required for a permanent fix.return Trim(0, -64).Animate(0, 64, "ShiftU", -2.0, +2.0)
return Trim(0, -64).Animate(0, 64, "ShiftV", -2.0, +2.0)

function ShiftU(clip C, float amount)
{
Assert(C.IsYUV, "ShiftU: source must be YUV")
C
U = UtoY
return YToUV(
\ U.BilinearResize(U.Width, U.Height, amount, amount, U.Width, U.Height)
\ , VtoY
\ , Last
\ ).Subtitle("U shift = " + String(amount, "%0.3f"), text_color=$808080)
}
function ShiftV(clip C, float amount)
{
Assert(C.IsYUV, "ShiftV: source must be YUV")
C
V = VtoY
return YToUV(
\ UtoY
\ , V.BilinearResize(V.Width, V.Height, amount, amount, V.Width, V.Height)
\ , Last
\ ).Subtitle("V shift = " + String(amount, "%0.3f"), text_color=$808080)
}


Output, enlarged 2x:
https://www.dropbox.com/s/3j5i5z55vxb8rwc/ShiftU-demo2.gif?raw=1

(source image here) (https://www.dropbox.com/s/3z8redsw0u0inlz/uv-stripes.png?dl=0)

------------------------
You can do the same with RGB clips:function ShiftR(clip C, float amount)
{
Assert(C.IsRGB, "ShiftR: source must be RGB")
C
return MergeRGB(
\ ShowRed.BilinearResize(Width, Height, amount, amount, Width, Height)
\ , ShowGreen
\ , ShowBlue
\ ).Subtitle("R shift = " + String(amount, "%0.3f"), text_color=$808080)
}
function ShiftB(clip C, float amount)
{
Assert(C.IsRGB, "ShiftB: source must be RGB")
C
return MergeRGB(
\ ShowRed
\ , ShowGreen
\ , ShowBlue.BilinearResize(Width, Height, amount, amount, Width, Height)
\ ).Subtitle("B shift = " + String(amount, "%0.3f"), text_color=$808080)
}
(assuming Green is the fixed, "reference" channel)