View Full Version : Deinterlace should preserve original pixels?
Gavino
10th August 2008, 23:46
Yes, I'm afraid it's Yadiq - Yet Another Deinterlacing Question :)
Given that deinterlacing is basically a problem of interpolation, is it considered a) essential, b) desirable or c) unimportant that a deinterlacer/bobber preserves the original pixel values. Please explain your answers ;)
To clarify, what I am asking is, given the interlaced input, with dots representing pixels,
y \ time-------------->
| . . . .
| . . . .
| . . . .
v . . . .
etc
should the dots be preserved unchanged in the output and the work be limited to 'filling in the blanks'?
Is the answer the same for both 'normal' deinterlacing (50i->25p) and bobbing (50i->50p)? (Clearly, in the first case, you throw some information away as well.)
How do some of the well-known deinterlacers behave in this respect?
Aside - deinterlacing seems to be one of those mysterious topics, like quantum mechanics or relativity, where the more you learn, the more you realise how much further you still have to go...
Guest
11th August 2008, 00:07
should the dots be preserved unchanged in the output What are you thinking they should be changed to and why?
Gavino
11th August 2008, 00:36
What are you thinking they should be changed to and why?
Well, as a rule I don't think they should be (and it seems you agree), but I have read suggestions that this is not always the case (eg here and here).
IanB
11th August 2008, 00:52
Ideally the input pixels should be preserved. As you say "the work be limited to 'filling in the blanks'".
But this is a perfect world view. In reality you have to invent the new pixel values to fill in the gaps and this will occasionally lead to mistakes. Sometimes these mistake lead to visually unpleasant artefacts.
If a given implementation chooses to do some extra processing to limit the visual significance of these mistake, and it involves tweaking the value of the original input pixels, and this truly makes these mistakes less objectionable, then I would say it is okay to munge the input values slightly to improve the total result.
The dumb internal Bob() filter takes this approach. It moves the top field down 0.5 pixel and the bottom field up 0.5 pixel using the Bicubic resizer to do the work. This is so that all output frames are equally processed. Using some clever values for B, C and Height the input pixel values can be retained, I do not like the look of the result, but for some applications it is relevant.
Manao
11th August 2008, 06:02
I checked, and bob keep (alternatively) one field at the same position, and recreates the other field by moving the first one 0.5 pixel up or down. However, the field looks slightly lowpassed, which makes sense for a dumb spatial bob since a field taken alone necessarily has some aliasing.
Alex_ander
11th August 2008, 10:55
Probably, NNEDI does keep original pixels. Don't know about its internal procedures, but documentation says it 'interpolates the missing pixels using only information from the kept field'. Considering its speed :) looks like it doesn't do it some dumb way. It wouldn't work good at plain deinterlacing in some critical cases (e.g. one field black, the other white), but at bob -> resize -> interlace the same example somehow should work.
2Bdecided
11th August 2008, 11:06
There's a post somewhere where Didee explained that mcbob strictly preserves the original fields, but this constraint could be relaxed - and this might potentially give a nicer looking output in some circumstances.
I care about preserving the original fields if I'm generating a progressive version for processing, and will revert to interlaced for the final output. It at least gives the chance of the whole thing becoming a NOP (at least in theory!) if/where necessary.
I care about the nicest looking output if the progressive version is the final output - and in that case, I'll use whatever looks best - whether it preserves, or not.
Interlacing, and deinterlacing, are compromises. You have to throw ideals away sometimes when working with compromises!
Cheers,
David.
Gavino
13th August 2008, 00:25
Thanks for the responses, everyone. I think the answers show that the question was not a trivial one.
Encouraged by that, I have done a bit more investigation, and have found that the truth about Bob [sounds like the title of a bad movie] is a bit more complex than the documentation says.
Since Bob uses a Bicubic (aka Mitchell-Netravali) reconstruction filter, it will keep the original pixels when that filter acts as a pure interpolator, ie if and only if b=0 (regardless of the value of c). Hence the default values (b=c=1/3) do not preserve the input data. As the documentation states, (b=0, c=1) will do so, but so will b=0 and any other value of c, including c=0.5 (the Catmull-Rom spline) which keeps the desirable property b+2*c=1.
I have verified this in practice by undoing the Bob (via SeparateFields, SelectEvery and Weave) and doing a Compare with the original.
What no-one mentioned (perhaps because they thought it self-evident) is that for YV12 it is wrong and makes no sense for any deinterlacer to preserve the original chroma data, because of the different way YV12 chroma is stored in interlaced and progressive frames.
IanB
13th August 2008, 03:25
Input YV12 chroma sample could be preserved as well, just the positioning is a little different.
vcmohan
13th August 2008, 03:49
I am interested to know how the yv12 chroma is originally arrived at in case of interlaced video? U and V values correspond to two by two pixels. In this case the two vertical pixels may have completely different chroma values. I am intending to do a rotation in my spinner plugin and need to know the chroma scheme.
Gavino
13th August 2008, 08:13
@IanB
You're right that in the case of Bob (or anything that works on only one field at a time), input chroma could be preserved by changing the resampling positions for the chroma (but I'm not sure if this would be theoretically 'correct'). For deinterlacers that combine the two fields, I think it would be wrong. Consider the effect on a stationary scene.
@vcmohan.
See here (http://avisynth.org/mediawiki/Sampling) for all the gory details.
I'm not sure it makes sense to do rotation on interlaced video.
Or do you plan to deinterlace, rotate and re-interlace?
Even then I don't think it could work right.
Manao
13th August 2008, 08:26
What no-one mentioned (perhaps because they thought it self-evident) is that for YV12 it is wrong and makes no sense for any deinterlacer to preserve the original chroma data, because of the different way YV12 chroma is stored in interlaced and progressive frames.Chroma samples are spatially at the same place in progressive & interlaced frame. However, the relative position of chroma samples in regard to luma samples varies when you consider a single field.
X X X X ----> Top luma
O O ----> Top chroma
X X X X ----> Bottom luma
X X X X ----> Top luma
O O ----> Bottom chroma
X X X X ----> Bottom lumaSo the top field taken alone looks like :
X X X X
O O
X X X XAnd the bottom field like that :
X X X X
O O
X X X X
IanB
13th August 2008, 10:10
Borrowing and correcting (Mpeg1 versus Mpeg2 placement) Manao's nice ascii art :-X X X X ----> Top luma
O O ----> Top chroma
* * * * ----> Interpolated luma
X X X X ----> Top luma
+ + ----> Interpolated chroma
* * * * ----> Interpolated lumaWhat is conceptually so difficult about this, practicality is another matter ;)
Gavino
13th August 2008, 17:01
Chroma samples are spatially at the same place in progressive & interlaced frame. However, the relative position of chroma samples in regard to luma samples varies when you consider a single field.
Ah, that was the missing link in my understanding.
Thanks for that - now what you and IanB are saying makes perfect sense.
I was assuming that each field was equivalent to a half-sized progressive YV12 image, whereas, as far as the chroma sampling positions are concerned, it is not the same.
However, the corollary of this seems to be that Bob is actually operating wrongly on YV12 chroma, since it resizes each field as if it were a standard progressive image. (This is independent of whether or not it retains the original pixels.)
Should it not be shifting the chroma differently from the luma before resizing?
Going further, it also suggests that the approach of resizing an interlaced image by SeparateFields, etc, will also introduce a chroma error with YV12 unless the chroma is treated specially. Can this be right?
IanB
14th August 2008, 01:11
However, the corollary of this seems to be that Bob is actually operating wrongly on YV12 chroma, since it resizes each field as if it were a standard progressive image.
Should it not be shifting the chroma differently from the luma before resizing?No, the resizer maintains the spacial relationship between luma and chroma centre points.
Internally the chroma planes are offset +/-0.125 as the luma planes are offset +/-0.25 so the overall effect is correct.
Going further, it also suggests that the approach of resizing an interlaced image by SeparateFields, etc, will also introduce a chroma error with YV12 unless the chroma is treated specially. Can this be right?Again no, because the resizer is "maintain centre based" the offset adjustments come out in the wash.
The input crop value is the result of 3 components Input offset.
Output un-offset.
Resizer centre correction.
The Input and Output offsets are the same numeric pixel value, but of opposite sign and in different spatial units (the pixel sizes are different).
Top field Luma = 0.0
Top field chroma = 0.125
Bottom field Luma = 0.5
Bottom field chroma = 0.625
The centre correction for the chroma planes has all the values halved, notably the subrange_start value. // the following translates such that the image center remains fixed
double pos = subrange_start + ((subrange_width - target_width) / (target_width*2));
or
= subrange_start - 0.5*(1 - subrange_width/target_width);
vcmohan
14th August 2008, 03:51
Is there a flag to find out if a image is bobbed or just plain separated?
In case of RGB what happens for bobbed clip if we trim and join at places not matching?
@Gavino: I have provision to linearly move the coordinates of rotation center along clip. In such case I need to know where exactly these coordinates are in each field.
IanB
14th August 2008, 06:16
A clip after SeparateFields() has vi.IsFieldBased() true.
Gavino
14th August 2008, 09:13
IanB, thanks for the explanation.
Can you please clarify one detail for me - do the resizers treat fieldbased and framebased clips differently, or are you saying specifically there is no need for them to do so (because it 'comes out in the wash')?
IanB
14th August 2008, 09:40
No the resizer always treats the frame as framebased. This is why you need to manually calculate the offset for the top and bottom fields when using my interlaced resizing function.
To answer the question I think you were really trying to ask :- Because the resizer is centre of image referenced the relationship between luma and chroma is maintained during a resize. If chroma is 0.125 old pixels up in input it will still be 0.125 new pixels up on output.
vcmohan
14th August 2008, 09:58
A clip after SeparateFields() has vi.IsFieldBased() true. How does one know whether an image is bobbed or not?
Gavino
14th August 2008, 10:37
Because the resizer is centre of image referenced the relationship between luma and chroma is maintained during a resize. If chroma is 0.125 old pixels up in input it will still be 0.125 new pixels up on output.
So resizing a fieldbased YV12 clip will produce a correct fieldbased clip of the new size, with properly aligned resampled chroma?
But Bob does this and treats the result as framebased, so is that not wrong? :confused:
AVIL
14th August 2008, 12:15
Hi all,
Due to noise, original pixel can be as fake as interpolated ones. So IMHO deinterlacers can alter it in order to prevent artifacts. Original pixels can be restored if needed with no effort.
IanB
14th August 2008, 13:37
How does one know whether an image is bobbed or not?You cannot tell programmatically, it is like any other frame based image. You are going to have to trust the human to write the script sensibly. ;)
IanB
14th August 2008, 14:04
So resizing a fieldbased YV12 clip will produce a correct fieldbased clip of the new size, with properly aligned resampled chroma?... the relationship between luma and chroma is maintained during a resize.No, resizing a fieldbased YV12 clip will not produce a correct fieldbased clip of the new size. The luma to chroma alignment will still be the same, but spatial alignment of the frame, both luma and chroma, will be offset. This is why you need the +/- offset to the separated fields when doing an interlaced resize. And yes I guess the resizer could have been taught about fieldbased clips and parity, but it hasn't.
But Bob does this and treats the result as framebased, so is that not wrong?No it does not. Bob applies the correct compensation to the top and bottom fields. The output is truly frame based with the alternate field correctly, but poorly, interpolated.
Gavino
14th August 2008, 17:02
OK, thanks for your patience, IanB. I think I've got it now...
Basically: The resizers treat everything as framebased, but as long as you apply the correct offsets for each case, you will get the right results, both in the case of interlaced resizing and for simple Bob (which correctly meets its limited specification). Yes?
And I suppose that anyone writing a plugin that does its own resampling (eg any sort of geometrical transformation) needs to take this issue into account when dealing with a fieldbased YV12 clip? (Hence vcmohan's interest)
Gavino
18th August 2008, 21:47
I wanted to be sure I really understood this properly, so I've dug a bit more, including looking at the resizing source code.
Bob applies the correct compensation to the top and bottom fields. The output is truly frame based with the alternate field correctly, but poorly, interpolated.
My investigations suggest that this is wrong.
Because the resizer is centre of image referenced the relationship between luma and chroma is maintained during a resize. If chroma is 0.125 old pixels up in input it will still be 0.125 new pixels up on output.
That's only true if the luma and chroma grids have the same centre point, and for fieldbased YV12 they don't.
Try number-crunching some example resampling patterns on paper and you will see this.
(The actual 'centre correction' is the same for luma and chroma since it depends only on the ratio of input to output size.)
To allow for the YV12 chroma being 'off-centre', it needs an additional 'input crop' of 1/4 field pixel (and in the case of interlaced resizing, a corresponding extra 'output uncrop').
The error is small, perhaps imperceptible in many cases, but I believe it is there, and it is an error.
In the case of Bob, its effect is that frames constructed from top fields appear with their chroma shifted down half a (frame) pixel and those from bottom fields have it shifted up 1/2. More significantly perhaps, it stops Bob preserving the input pixels for YV12 chroma when it should.
The following script, which bobs and re-interlaces any source and compares the results, demonstrates this.
orig = last # assumed set previously
Bob(b=0.0, c=1.0) # or any other value of c
# re-interlace
GetParity(orig) ? AssumeTFF() : AssumeBFF()
SeparateFields()
SelectEvery(4, 0, 3)
Weave()
Compare(orig)
# for luma/chroma only, use channels="Y" or "UV"
Try this and you will see that the original source is exactly reconstructed, except for the chroma of YV12 clips.
The documentation (http://avisynth.org/mediawiki/Bob) even points out that YV12 chroma is not preserved, but fails to recognise that this is an error and not something to be expected. (like the dog who failed to bark in the Sherlock Holmes story)
If you replace Bob by the following function, you will find that a perfect reconstruction is done for all clips.
function FixedBob(clip cp, float "b", float "c", int "h") {
h = Default(h, cp.Height)
w = cp.Width
shift = GetParity(cp) ? 0.25 : -0.25
cp.SeparateFields()
even=SelectEven().BicubicResize(w, h, b, c, 0, shift, w, Height())
odd=SelectOdd().BicubicResize(w, h, b, c, 0, -shift, w, Height())
evenChr=SelectEven().BicubicResize(w, h, b, c, 0, 2*shift, w, Height())
oddChr=SelectOdd().BicubicResize(w, h, b, c, 0, -2*shift, w, Height())
Interleave(even, odd)
IsYV12() ? MergeChroma(Interleave(evenChr, oddChr)) : last
AssumeFrameBased()
}
The lines in blue are the ones that fix the problem - the remaining lines are equivalent to the existing implementation of Bob.
(I'm not suggesting any real implementation fix would do it exactly like this, it's just to demonstrate the concept, and provide a script-level workaround for anyone who wants it.)
And if I turn out to be completely wrong about all this, I apologise in advance. :)
"If nothing else brings me six feet under, interlaced YV12 will." - Didée
I'll second that emotion!
IanB
20th August 2008, 13:38
@Gavino,
Yes you are correct, maintaining the centre relationship between the luma and chroma during the resize not what is wanted for a Bob() operation.
I have forgotten that field separated VY12 frames no longer have the chroma centred between the lines. It is offset 0.25 pixel up on the top field and offset 0.25 pixel down on the bottom field. Bob() incorrectly maintains that offset. It needs to correct for it.
The ascii art shows the relationship.Fos Frame Top Bottom Tos Bos
0.0 x x x x x x x x 0.0
0.5 c c c c 0.25
1.0 x x x x x x x x 0.0
1.5
2.0 x x x x x x x x 1.0
2.5 c c c c 0.75
3.0 x x x x x x x x 1.0
I guess this is also going to effect my interlaced resize with YV12 data. Care to suggest a correction.
Gavino
20th August 2008, 14:27
I guess this is also going to effect my interlaced resize with YV12 data. Care to suggest a correction.
Yes indeed it does.
Basically the correction is similar to the one I showed above for Bob.
AssumeTFF()
SeparateFields()
Shift=(Height()/Float(NewHeight/2)-1.0)*0.25
Tf=SelectEven().XXXResize(NewWidth, NewHeight/2, 0, -Shift, Width(), Height())
Bf=SelectOdd().XXXResize(NewWidth, NewHeight/2, 0, Shift, Width(), Height())
TfChr=SelectEven().XXXResize(NewWidth, NewHeight/2, 0, -2*Shift, Width(), Height())
BfChr=SelectOdd().XXXResize(NewWidth, NewHeight/2, 0, 2*Shift, Width(), Height())
Interleave(Tf, Bf)
IsYV12() ? MergeChroma(Interleave(TfChr, BfChr)) : last
Weave()
You could tweak the order of the operations, but basically that's it, I think.
IanB
21st August 2008, 02:10
@Gavino,
That does not seem to do the trick. I don't have time to work out why this is fubar, but the brute force answers using Animate() to give the best UV PSNR with compare are weird.Function Foo(clip clip, float shift) {
Clip
Tc=SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, -Shift, Width(), Height())
Bc=SelectOdd().Spline36resize(NewWidth, NewHeight/2, 0, Shift, Width(), Height())
Interleave(Tc, Bc)
Weave()
}
...
Chr=Animate(0, 2000, "Foo", -1.0, 1.0)
...Using the above code fragment to manually vary the amount of chroma shift, while using the standard shift for the luma and the YUY2 comparison clip. I found the frame with the best PSNR for the "UV" channels only. I recorded the Chroma and Luma shift values for that frame. I tested for a range of resizing ratios varing Rat=NewHeight/Height from a 2:1 reduction (0.5) to a 5:1 increase in height (5.0). Interesting that the 2% increase and 2% decrease in height had a PSNR improvement with a noteable amount of shift.Rat ChShft LShft
0.5 +1.470 +0.25
0.67 +0.130 +0.125
0.90 -0.117 +0.025
0.98 -0.075 +0.005
1.02 -0.122 -0.005
1.1 -0.190 -0.023
1.2 -0.210 -0.042
1.5 -0.384 -0.083
2.0 -0.417 -0.125
2.5 -0.466 -0.15
3.0 -0.517 -0.167
3.5 -0.531 -0.179
4.0 -0.546 -0.188
4.5 -0.563 -0.194
5.0 -0.581 -0.2
mikeytown2
21st August 2008, 03:22
Here's my take on doing a compare
ColorBars(480,240).Trim(0,1999).ConvertToYV12()
orginal=last
Function Foo(clip cp, float shift)
{
Global shifter=shift
h = cp.Height
w = cp.Width
#shift = GetParity(cp) ? 0.25 : -0.25
cp.SeparateFields()
even=SelectEven().BicubicResize(w, h, 0, 1, 0, shift, w, Height())
odd=SelectOdd().BicubicResize(w, h, 0, 1, 0, -shift, w, Height())
#~ evenChr=SelectEven().BicubicResize(w, h, b, c, 0, 2*shift, w, Height())
#~ oddChr=SelectOdd().BicubicResize(w, h, b, c, 0, -2*shift, w, Height())
Interleave(even, odd)
#~ IsYV12() ? MergeChroma(Interleave(evenChr, oddChr)) : last
AssumeFrameBased()
}
Animate(0, 1999*2, "Foo", -1.0, 1.0)
SeparateFields()
SelectEvery(4, 0, 3)
Weave()
Compare(last,orginal).GRunT_ScriptClip("Subtitle(String(shifter),align=2)")
GRunT() (http://forum.doom9.org/showthread.php?t=139337)
-0.269235 BicubicResize 0,1 PNSR 49.6242
-0.264500 BilinearResize PNSR: 51.86
-0.268500 Spline36Resize PNSR: 52.34
-0.267500 Spline64Resize PNSR 52.35
-0.265500 BlackmanResize PNSR: 52.60
-0.273500 Spline16Resize PNSR: 53.09
IanB
21st August 2008, 06:55
@mikeytown2,
WtF! :confused:
We are trying to work out for interlaced YV12 resizing what the shift correction for the chroma planes should be. It is certainly NOT 2 times the luma shift as it is for the Bob() case.
I will add more description to my post above to try an clarify what I did.
Gavino
21st August 2008, 08:51
@IanB.
Can you please clarify what you are comparing with what in your test?
I take it you start with a YUY2 (interlaced) clip. Then you resize by two different routes:
1) your standard approach
2) convert to YV12(interlaced=true), resize (varying chroma shift)
Then you compare the two resized clips.
Is that right?
I'll try replicating your tests once I wake up properly :)
IanB
21st August 2008, 16:01
Start with a static YV12 image. Then you resize by three different routes:
0) Normal Progressive Resize, for visual reference only.
1) ConvertToYUY2(), standard Interlace Resize.
2) Interlaced resize (varying chroma shift), ConvertToYUY2()
Compare 2 with 1, stack all 3.
0 is always slightly better looking than 1. Adjust to make 2 look as good as 1, confirm is also near the best PSNR.
Change height, wash, rinse, repeat.
Round 2: Will try using FixedBob().SeparateFields().SelectEvery(4, 0,3).Weave() to generate the comparison clip.
Gavino
22nd August 2008, 00:18
I wonder if the difference between doing the ConvertToYUY2 before and after resizing introduces a larger variability, swamping the effect of the shift correction (which is quite small for normal ratios).
I have verified that my proposed new interlaced resize gives identical results to FixedBob(h=newsize).SeparateFields().SelectEvery(4, 0,3).Weave() in the case of upsizing, if the same resizer is used in both.
For downsizing, you get differences due to the extended filter support, but the peak correlation still corresponds to my predicted chroma shift value (twice the luma shift).
IanB
23rd August 2008, 10:49
@Gavino,
I've had some time to look into my problem and I agree with your your YV12 Chroma offset values.
The problem I was having was due to mismatching field parity in various places in my test script. I was only comparing the U and V channels so eventually I could force an approximate match. Below is the final script I am using. The Blue code that was missing is what was biting me....
A=IResize(Width(), NewHeight)
B=FixedBob(NewHeight).SeparateFields().selectEvery(4, 0,3).Weave()
Compare(A, B, "UV")
###########################################################
function IResize(clip Clip, int NewWidth, int NewHeight) {
Clip
SeparateFields()
Shift=(GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
E = SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, Shift)
O = SelectOdd( ).Spline36resize(NewWidth, NewHeight/2, 0, -Shift)
Ec = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, 2*Shift)
Oc = SelectOdd( ).Spline36Resize(NewWidth, NewHeight/2, 0, -2*shift)
Interleave(E, O)
IsYV12() ? MergeChroma(Interleave(Ec, Oc)) : Last
Weave()
}
###########################################################
function FixedBob(clip clip, int "Height") {
h = Default(Height, clip.Height)
w = clip.Width
shift = GetParity(clip) ? 0.25 : -0.25
clip.SeparateFields()
E = SelectEven().Spline36Resize(w, h, 0, shift)
O = SelectOdd( ).Spline36Resize(w, h, 0, -shift)
Ec = SelectEven().Spline36Resize(w, h, 0, 2*shift)
Oc = SelectOdd( ).Spline36Resize(w, h, 0, -2*shift)
Interleave(E, O)
IsYV12() ? MergeChroma(Interleave(Ec, Oc)) : Last
AssumeFrameBased()
GetParity(clip) ? AssumeTFF() : AssumeBFF()
}
Gavino
23rd August 2008, 11:31
Thanks, Ian.
I was fairly sure, as the reasoning behind the chroma shift for resizing is the same as for Bob, just that it has the additional 'output uncrop' of 1/4 new pixels.
I thought of putting the "GetParity(clip) ? AssumeTFF() : AssumeBFF()" line in my original FixedBob, but left it out because the real Bob doesn't do it (arguably it should), and put it in my script instead.
Don't you need to put the width and height in explicitly in all the resizer calls? Eg
E = SelectEven().Spline36Resize(w, h, 0, shift, Width(), Height())
Otherwise it seems to me you are changing the scale factor as well as shifting.
EDIT: No, it's OK - these are the default values. (I thought default was 0, but it isn't)
IanB
23rd August 2008, 14:11
const double subrange_left = args[0].AsFloat(0), subrange_top = args[1].AsFloat(0);
double subrange_width = args[2].AsFloat(vi.width), subrange_height = args[3].AsFloat(vi.height);
// Crop style syntax
if (subrange_width <= 0.0) subrange_width = vi.width - subrange_left + subrange_width;
if (subrange_height <= 0.0) subrange_height = vi.height - subrange_top + subrange_height;
florinandrei
23rd August 2008, 23:12
So, is everyone in agreement? Is this the final version of the YV12 interlaced resizer?
Global NewHeight=480
Global NewWidth=720
DirectShowSource("hd.m2ts", audio=false)
# Pick one if DirectShow can't decide
AssumeTFF()
#AssumeBFF()
SeparateFields()
Shift = (GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
Elum = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, Shift)
Olum = SelectOdd() .Spline36Resize(NewWidth, NewHeight/2, 0, -Shift)
Echr = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, 2*Shift)
Ochr = SelectOdd() .Spline36Resize(NewWidth, NewHeight/2, 0, -2*shift)
Interleave(Elum, Olum)
IsYV12() ? MergeChroma(Interleave(Echr, Ochr)) : Last
Weave()
Gavino
24th August 2008, 00:45
So, is everyone in agreement? Is this the final version of the YV12 interlaced resizer?
Strictly for the interlaced resizing itself, it doesn't matter whether you have the right parity information - all that matters is you use -0.25 for the top fields and that the (real) parity is preserved (which is ensured by the Interleave).
So from that point of view you could get away with
AssumeTFF() # to get top fields in SelectEven
SeparateFields()
Shift = -0.25*(Height()/Float(NewHeight/2)-1.0)
...
However, that has the side-effect of altering the parity assumed in later parts of the script (if it was originally BFF) so it's probably cleaner to write it as you have it.
Considering that one of the advantages of the original method over that of bob-resize-Weave was speed, I would like to ask IanB how much of that advantage has been lost in the case of YV12, given the extra work it now has to do. Can the code possibly be tweaked to reduce the penalty?
henryho_hk
24th August 2008, 03:52
What if we pull the U & V channels out 1st (utoy and vtoy) and then resize them? Are the corrections simpler?
Nikos
24th August 2008, 07:58
Does eedi2Bob or nnediBob has similar problem with shift?
Also may i replace the Bob with FixedBob in MCBob function or in yadifmod?
s = last
interp=s.FixedBob().selecteven()
s.yadifmod(mode=0, edeint=interp)
IanB
24th August 2008, 11:14
@florinandrei,
Nit pick 1 :-
# Pick one if DirectShow can't decide
This implies in some alternate universe DirectShowSource knows something about field order. In this world it has no idea. For interlaced content you always have to work it out and script appropriately.
Nit pick 2 :-
Your edit to "Elum = " is not universally correct. For other pixel formats these are the Even and Odd complete data.
@Gavino,Considering that one of the advantages of the original method over that of bob-resize-Weave was speed, I would like to ask IanB how much of that advantage has been lost in the case of YV12, given the extra work it now has to do. Can the code possibly be tweaked to reduce the penalty?Well it is doing 2 near identical resize operations instead of 1, plus a MergeChroma (half Blit). So a bit less than 50% speed.
In the 2.5 world there is no quick way to spec the resizer luma and chroma offsets independently. One could always razor the code, but it is hardly worth it. In the 2.6 development Sh0dan has added the beginnings of some chroma positioning options. This may allow Bob() to spec the resizer luma and chroma offsets independently. Also there is the Y8 pixel format available so each plane can be independently processed in a user script. Somewhat like this :-...
SeparateFields()
Shift=(GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
Y = ConvertToY8() # Zero cost
Ey = Y.SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, Shift) # Uniplanar
Oy = Y.SelectOdd( ).Spline36resize(NewWidth, NewHeight/2, 0, -Shift) # Uniplanar
UV = Interleave(UtoY8(), VtoY8()) # Zero cost
Euv = UV.SelectEvery(4, 0,1).Spline36Resize(NewWidth/2, NewHeight/4, 0, Shift) # Uniplanar*2
Ouv = UV.SelectEvery(4, 2,3).Spline36Resize(NewWidth/2, NewHeight/4, 0, -shift) # Uniplanar*2
E = YToUV(SelectEven(Euv), SelectOdd(Euv), Ey) # Blit
O = YToUV(SelectEven(Ouv), SelectOdd(Ouv), Oy) # Blit
Interleave(E, O)
Weave()
@henryho_hk,
Might be a little easier for us poor Humans to visualise but the dumb computer couldn't care less.
@Nikos,
eedi2Bob or nnediBob, we do not know, Tritical is sitting on the source code because they are part of his thesis. Why don't you test and report what you find.
It probably does not matter, the actual error here is really quite small. I had trouble building a suitable test pattern to reliably see this error. In normal use the chroma subsampling for interlaced 4:2:2 is severe enough that it out weighs our small displacement problem.
florinandrei
24th August 2008, 19:39
It probably does not matter, the actual error here is really quite small. I had trouble building a suitable test pattern to reliably see this error. In normal use the chroma subsampling for interlaced 4:2:2 is severe enough that it out weighs our small displacement problem.
Maybe the chroma error introduces a tiny bit of blur?
halsboss
15th September 2008, 15:04
SeparateFields()
Shift=(GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
Y = ConvertToY8() # Zero cost
Ey = Y.SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, Shift) # Uniplanar
Oy = Y.SelectOdd( ).Spline36resize(NewWidth, NewHeight/2, 0, -Shift) # Uniplanar
UV = Interleave(UtoY8(), VtoY8()) # Zero cost
Euv = UV.SelectEvery(4, 0,1).Spline36Resize(NewWidth/2, NewHeight/4, 0, Shift) # Uniplanar*2
Ouv = UV.SelectEvery(4, 2,3).Spline36Resize(NewWidth/2, NewHeight/4, 0, -shift) # Uniplanar*2
E = YToUV(SelectEven(Euv), SelectOdd(Euv), Ey) # Blit
O = YToUV(SelectEven(Ouv), SelectOdd(Ouv), Oy) # Blit
Interleave(E, O)
Weave()
So, was this the final script instead of that in post 38 http://forum.doom9.org/showthread.php?p=1174185#post1174185 ??
Fizick
15th September 2008, 22:34
well, interesting discussion!
not directly related, but now i understand, that pelclip in MVTools is not quite correct for chroma. :)
similar is that original points are (should) preverved
henryho_hk
17th September 2008, 02:30
@henryho_hk,
Might be a little easier for us poor Humans to visualise but the dumb computer couldn't care less.
I thought the extracted UtoY and VtoY contain 1/4 data of their original image. Hence, It will be a bit faster (esp for 1080i or p footages).
IanB
17th September 2008, 10:03
Maybe the chroma error introduces a tiny bit of blur?(I should have said 4:2:0) The issue is that the small offset error in the code is small compared to the chroma subsampling.
So, was this the final script instead of that in post 38No, that is a pseudo example of how you might be able to code it up in 2.6. Post 38 is an academically pure version for 2.5, given the trouble I had building a test pattern to actually see the error, I do not believe it is worthwhile.
@Fizick,
As above, I do not believe there is anything significant to worry about. But we are all a little anal about getting this stuff right, so it is good to document where we are wrong and how to eventually fix it.
@henryho_hk,
Yes, I guess if you are sufficiently motivated you could use UtoY to make a sightly faster version.
florinandrei
19th September 2008, 00:39
No, that is a pseudo example of how you might be able to code it up in 2.6. Post 38 is an academically pure version for 2.5, given the trouble I had building a test pattern to actually see the error, I do not believe it is worthwhile.
On my system (AMD Phenom 4 core 9850), the "pure" version is only a little bit slower than the "brute" one. It's 10.3 fps "pure" vs 12.7 fps "brute" when transcoding from 1080i AVCHD (MainConcept decoder via DirectShow) to 480i MPEG2 (HCenc encoder with max quality profile).
IanB
19th September 2008, 05:23
... It's 10.3 fps "pure" vs 12.7 fps "brute" ...So the "pure" takes 18.3ms out of 78.7ms per frame longer to process ... ... ...
halsboss
19th September 2008, 10:15
No, that is a pseudo example of how you might be able to code it up in 2.6. Post 38 is an academically pure version for 2.5, given the trouble I had building a test pattern to actually see the error, I do not believe it is worthwhile.
On my system (AMD Phenom 4 core 9850), the "pure" version is only a little bit slower than the "brute" one. It's 10.3 fps "pure" vs 12.7 fps "brute" when transcoding from 1080i AVCHD (MainConcept decoder via DirectShow) to 480i MPEG2 (HCenc encoder with max quality profile).
Er, which was the "brute" one I could use and not notice the difference ? 10.3->12.7 is significant enough for me.
Gavino
19th September 2008, 10:40
Er, which was the "brute" one I could use and not notice the difference ? 10.3->12.7 is significant enough for me.
The 'brute' version is the one that was generally accepted before I discovered the error and proposed the 'pure' solution. This is the 'pure' version:
function IResize(clip Clip, int NewWidth, int NewHeight) {
Clip
SeparateFields()
Shift=(GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
E = SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, Shift)
O = SelectOdd( ).Spline36resize(NewWidth, NewHeight/2, 0, -Shift)
Ec = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, 2*Shift)
Oc = SelectOdd( ).Spline36Resize(NewWidth, NewHeight/2, 0, -2*shift)
Interleave(E, O)
IsYV12() ? MergeChroma(Interleave(Ec, Oc)) : Last
Weave()
}
Removing the lines in blue gives the 'brute' solution.
Spline36Resize can be replaced by another resizer if you wish.
halsboss
20th September 2008, 05:54
Well, that's floored me, look at the signs on SHIFT in this link http://forum.doom9.org/showthread.php?p=1172981#post1172981
Function Foo(clip clip, float shift) {
Clip
Tc=SelectEven().Spline36resize(NewWidth, NewHeight/2, 0, -Shift, Width(), Height())
Bc=SelectOdd().Spline36resize(NewWidth, NewHeight/2, 0, Shift, Width(), Height())
Interleave(Tc, Bc)
Weave()
}
which, just a few posts later http://forum.doom9.org/showthread.php?p=1174185#post1174185 turns into
SeparateFields()
Shift = (GetParity() ? -0.25 : 0.25) * (Height()/Float(NewHeight/2)-1.0)
Elum = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, Shift)
Olum = SelectOdd() .Spline36Resize(NewWidth, NewHeight/2, 0, -Shift)
Echr = SelectEven().Spline36Resize(NewWidth, NewHeight/2, 0, 2*Shift)
Ochr = SelectOdd() .Spline36Resize(NewWidth, NewHeight/2, 0, -2*shift)
Interleave(Elum, Olum)
IsYV12() ? MergeChroma(Interleave(Echr, Ochr)) : Last
Weave()
whihc is it ??
Gavino
20th September 2008, 10:05
@halsboss
In the first link, function Foo was part of a test IanB was doing to verify the correct value of the shift, varying shift from -1.0 to +1.0, so on its own it is incomplete.
The second link shows one way of expressing the complete 'pure' solution, and is equivalent to what I posted (#51).
halsboss
21st September 2008, 01:26
OK. Thankyou for clarifying that. Cheers !
Katie Boundary
25th September 2018, 17:20
This is all fascinating. Regarding bob-deinterlacers and YCbCr colorspaces, I'm afraid I don't understand why such complex solutions are necessary. Couldn't you just write them so they function like this:
L=bob()
C=separatefields().bicubicresize(720,480)
Mergechroma(L,C)
?
wonkey_monkey
27th September 2018, 22:01
For the same reason bob exists in the first place. You wouldn't do separatefields().bicubicresize() on luma, so why would you do it on chroma? There is top field chroma and bottom field chrome just as there is top field luma and bottom field luma. Separatefields "loses" information on their proper positioning.
johnmeyer
27th September 2018, 23:39
I think that if you want to do a bob() that can then immediately be recombined to give you exactly what you started with, you use this:
bob(0.0,1.0)
Obviously you would never actually bob and then do this:
separatefields().selectevery(4,1,2).weave()
to put everything back together, but there are all sorts of scripts where it is important not to introduce shifts.
Katie Boundary
29th September 2018, 23:34
Yes but the question is whether or not preserving the original scanlines is a good idea when dealing with YCbCr colorspaces.
TheFluff
30th September 2018, 00:30
This is all fascinating. Regarding bob-deinterlacers and YCbCr colorspaces, I'm afraid I don't understand why such complex solutions are necessary. Couldn't you just write them so they function like this:
?
I'm pretty sure that if you do that to an actually interlaced source, the chroma will appear to jump up and down because you're treating the top and bottom field chroma sample positions as if they were in the same spatial positions, which they aren't.
The question whether it's a good idea to preserve the original pixels has been extensively discussed in this thread already. I'm of the opinion that there's no inherent reason as to why doing so would make the image look any better, and many bob-style deinterlacers either don't preserve original pixels at all or does so only by coincidence.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.