View Full Version : Double-blend IVTC Removal


foxyshadis
17th October 2005, 15:16
MOmonster's FixBlendIVTC 0.9 (http://forum.doom9.org/showthread.php?t=95924), part of R_pack, has definitely surpassed my function on speed, reliability, quality, and tweakability, so I advise you all to grab a copy of it and let my old version rot. ;) And it now includes a readme!

The same caveat applies: Any form of pre-processing (other than a simple blur or resize) will disrupt the blend detection.

Requires 2.0a22+ (http://forum.doom9.org/showthread.php?t=98985), Average (http://forum.doom9.org/showthread.php?t=100626), Removegrain (http://home.arcor.de/kassandro/RemoveGrain/RemoveGrain.rar), and Decomb (http://neuron2.net/decomb/decombnew.html) for decimating.


-------------------

Old News


v0.4, now with automatic pattern-matching! MOmonster and mg262 contributed greatly to helping me achieve that.

Uses difference masks and edge masks to improve unghosting. The less filtering you use beforehand, the better detection and reversal works. Unblend/removeblend is faster and about as accurate with single blends, especially those without a pattern.

Requires masktools and Average (http://forum.doom9.org/showthread.php?t=100626). Note that Momonster is actively developing a higher quality and faster version, I'll probably post that here when he finishes.


function fx_unblendTC(clip input, bool "nopp") {
nopp = default(nopp,false)
## Non-volatile variables ##
global source = input
global greymain = source.levels( 16, 1, 200, 128, 128, coring = false)
global test = Average(greymain, 1, source,0.25, source.trim(1,0),-0.5, source.trim(2,0),0.5, \
source.trim(3,0),-0.25).reduceby2().YV12Lut("x 128 - 3 ^ 4 / 128 +")
global grey = greymain.reduceby2
global framez5 = blankclip(test,length=5) + test
global framez4 = blankclip(test,length=4) + test
global framez3 = blankclip(test,length=3) + test
global framez2 = blankclip(test,length=2) + test
global framez1 = blankclip(test,length=1) + test
global frame0 = test
global frame1 = test.trim(1,0) + blankclip(test,length=1)
global frame2 = test.trim(2,0) + blankclip(test,length=2)
global frame3 = test.trim(3,0) + blankclip(test,length=3)
global frame4 = test.trim(4,0) + blankclip(test,length=4)
global frame5 = test.trim(5,0) + blankclip(test,length=5)

# frames to use for output
sframe3 = input.duplicateframe(0)
sframe4 = input
sframe5 = input.trim(1,0)
sframe6 = input.trim(2,0)

# unblend output and various post-processing measures
unblend1 = Average(sframe3, -1.0, sframe4, 2.0)
unblend2 = Average(sframe5, 2.0, sframe6, -1.0)
edgemerge = fx_unblend_edges(unblend1,unblend2)
unblend1 = edgemerge.selectevery(2,0)
unblend2 = edgemerge.selectevery(2,1)
diffframe1 = overlay(sframe4, sframe3, mode="difference") \
.levels(120,1,192,0,255,coring=false).binarize(threshold=30,upper=true).blur(.5)
diffframe2 = overlay(sframe5, sframe6, mode="difference") \
.levels(120,1,192,0,255,coring=false).binarize(threshold=30,upper=true).blur(.5)
unblend1 = MaskedMerge(unblend1,sframe6,diffframe2)
unblend2 = MaskedMerge(unblend2,sframe3,diffframe1)

# one-step deblend, use for speed
global output = Average(sframe3, -0.5, sframe4, 1.0, sframe5, 1.0, sframe6, -0.5)

global unblended = nopp ? output : Average(unblend1, .5, unblend2, .5)

## Volatile variables ##
global isblend = false
global isblend1 = false
global isblend2 = false
global isblend3 = false

## Conditional Chain ##

d99=scriptclip(source, """(isblend1 == true ? unblended : \
(isblend2 == true ? unblended.duplicateframe(0) : source))""")

# new pattern must start minimum of 4 from last.
d5=FrameEvaluate(d99, "isblend = (!isblend1 && !isblend2 && !isblend3) && \
(residue / div < .2)")
# closer the pattern match (max 8) the higher the allowed threshold
d4=FrameEvaluate(d5, "global div = frametesta + frametestz >= 7.5 ? 500 : \
(frametesta + frametestz >= 7 ? 5 : (frametesta + frametestz >= 6 ? 3 : \
(frametesta + frametestz >= 4 ? 1 : .01)))")
# assign weights to pattern positions
d2=FrameEvaluate(d4, " global frametestz = (( min(diffz1,diffz2) > residue ?2:-4 ) + \
( diffz3 > residue ?.5:-.5 ) + ( diffz4 > residue ?.5:0 ) + \
( diffz5 < min(diffz1,diffz2,diffz3,diffz4) ?1:0 ))
global frametesta = (( min(diff1,diff2) > residue ?2:-4 ) + \
( diff3 > residue ?.5:-.5 ) + ( diff4 > residue ?.5:0 ) + \
( diff5 < min(diff1,diff2,diff3,diff4) ?1:0 ))")
# set up differences
d1=FrameEvaluate(d2, "global residue = LumaDifference(frame0,grey)
global diffz1 = LumaDifference(framez1,grey)
global diffz2 = LumaDifference(framez2,grey)
global diffz3 = LumaDifference(framez3,grey)
global diffz4 = LumaDifference(framez4,grey)
global diffz5 = LumaDifference(framez5,grey)
global diff1 = LumaDifference(frame1,grey)
global diff2 = LumaDifference(frame2,grey)
global diff3 = LumaDifference(frame3,grey)
global diff4 = LumaDifference(frame4,grey)
global diff5 = LumaDifference(frame5,grey)
isblend3 = isblend2
isblend2 = isblend1
isblend1 = isblend")
return(d1)
}

function fx_unblend_edges(clip sup1, clip sup2) {
edgemask1 = sup1.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special").levels(96,1,160,0,255,coring=false)
edgemask2 = sup2.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special").levels(96,1,160,0,255,coring=false)
diffedgemask1 = overlay(edgemask1, edgemask2, mode="subtract").inflate().blur(.7)
diffedgemask2 = overlay(edgemask2, edgemask1, mode="subtract").inflate().blur(.7)
edgemerge1 = MaskedMerge(sup1,sup2,diffedgemask1)
edgemerge2 = MaskedMerge(sup2,sup1,diffedgemask2)
return interleave(edgemerge1,edgemerge2)
}


Because it improves the deblending with a difference mask, the stronger the luma difference the less artifacts will show in the output.

A few clips for your perusal below: (Xvid q4)
2: blend (http://foxyshadis.slightlydark.com/random/cb_blendclip2.avi) unblend (http://foxyshadis.slightlydark.com/random/cb_unblendclip2.avi)
3: blend (http://foxyshadis.slightlydark.com/random/cb_blendclip3.avi) unblend (http://foxyshadis.slightlydark.com/random/cb_unblendclip3.avi)
4: blend (http://foxyshadis.slightlydark.com/random/cb_blendclip4.avi) unblend (http://foxyshadis.slightlydark.com/random/cb_unblendclip4.avi)
5: blend (http://foxyshadis.slightlydark.com/random/cb_blendclip5.avi) unblend (http://foxyshadis.slightlydark.com/random/cb_unblendclip5.avi)
6: blend (http://foxyshadis.slightlydark.com/random/cb_blendclip6.avi) unblend (http://foxyshadis.slightlydark.com/random/cb_unblendclip6.avi)

Usage is just fx_unblendTC(). If there are long stretches of no blends, it shouldn't hurt to leave it on but it will slow it down. It typically won't get the very first and last blends of a clip, so a few still show in the samples even though they were caught fine when I used the full video.

After reversal use TDecimate or FDecimate as required. Random access is unreliable so make sure that every frame is touched in order (tdec mode 5 won't). It is recommended for now to write the output to a lossless temp file and working from there. (Inline Fdec worked fine for 4-6 but messed up the patterns for 2-3.)

v0.2 - I realized I was using subtract and it was throwing off some calulations. Also, added static area detection, much better on static parts (both forward and backward). Removed unnecessary conditionalfilters.
v0.3 - yv12subtract for full reversals, a few additional options.
v0.4 - rewritten as conditional, automated pattern detection.

Didée
18th October 2005, 08:18
With all respect for the work you put into this ... when I tried it on one source with "blend-IVTC" I've lying around, your function acted as a perfect NOP. Not one single pixel was changed. Input==Output, bit-identical.

Are you sure everything's okay with that function? Perhaps some hardcoded values should be parametrized?

foxyshadis
18th October 2005, 09:24
I'm not actually sure. The first frame number does have to be the start of a 5-cycle of 3 clear and 2 blends - even if it's across a scenechange, it won't hurt it. Can I see a piece of your clip? Having more than the three or four I have (which are mostly very similar in their blending patterns) would be really nice to have, although the effect is definitely there on the ones I tried.

I'll probably go back in with a much wider test body for the next iteration, I've had a few ideas percolating.

And don't worry about my feelings, it's just a personal quest for perfection that I hope might be of use to others someday as well. =p

MOmonster
18th October 2005, 11:07
I couldnīt test the function till now. I think it is only for NTSC footage (right?). But also if Didee tested a pal-clip, I think there should happen something. It looks a bit komplex for me, but therefore it avoids the evaluate enviroment. How good get it clear with Edits.

EDIT:
Iīm a bit confused :confused: . I have seen pal to ntcs blend-conversions (cycle=6) and of course ntsc to pal blend-conversions (cycle=25), but you work on the cycle 5?
Can anybody explain me, what is mean with blend-IVTC (or better blend-TC)?

foxyshadis
18th October 2005, 13:05
Telecined footage, but instead of being IVTC'd like any sane method, frame-blended to remain 30p without being wildly interlaced every few frames. That's my sources. If pal->ntsc clips are much different, I'd have to see a few. (Just changing the cycle to 6 would be simple though.)

I'm afraid it wouldn't be any good with all blends through a whole film, it's meant to use clean frames around the blends to wipe away blend-artifacts. I'm still working on different algorithms on the hunt for something better. Maybe I should use some of your guys' really complex scripts for cribbing. :p

Edit: Oh geez I'm such a huge idiot, I need to redo a few things. Give me a bit to sort things out.

Also, I hate it when inspiration strikes at 4 in the morning.

Edit2: Okay, I modified it to use difference rather than subtract. Also got my static area inspiration working.

I suppose my examples aren't great. What I do is:
x=mpeg2source("file")
x=x.fx_unblend(316,343)
return x

This returns it in 30fps with the unblended frame duplicated. Once I have the ranges I want, I run tdecimate on it. But I included 24 in case someone wants it. Once I get it more thorough and more efficient, I'm going to add parameters for noise thresholds too; right now it's made for really noisy sources, but it shouldn't hurt clean ones much. Cycle shouldn't be hard, I just need to think about how to apply it with selectevery/interleaveevery.

Edit3: Changed the thread title to be clearer as to its purpose.

MOmonster
19th October 2005, 11:48
Yes, this is what I also thought yesterday evening. Here I can only play this file with vlc (slow motion), because itīs not my pc, but of course that doesnīt give me so much informations.
If I understand it right, this is the pattern:
example1: A AB B BC C D DE E EF G
And we know, the blendweights are all 50:50, because it was a result of deinterlacing. The Blends doesnīt seem to be bad catchable (good wight and clear structures because itīs a Anime), so Cdeblend or restore24 should also are able to kill the most blends.
But if Iīm right with the blendweight, why not just using a simple differencing? If we had the pattern example (example1), then the differences between B and BC (B->BC) should be really similar to the difference BC->C and:
D->DE ~ DE->E
E->EF ~ EF->F
...
And in general the difference C->D would be significantly bigger than the differences around. So if:
C->D * thresh > BC->C (and then of course also B->BC) &&
C->D * thresh > D->DE (and then of course also DE->E)
with a thresh around 0.7 or 0.75, we know the pattern. Its the only Difference, that can be significantly bigger than the differences around, because all other differences has a really similar difference.
If C->D isnīt the biggest Difference for example because of a scenechange, then we just keep the last pattern till the next clear decission.

Thatīs the way, I would solve the problem, but of course this can fail and is maybe worse than your way, but I like to make it a bit more easier and faster. ;)
If I was wrong with the blendweight or the pattern, please tell me. I never has sawn such sources before.

foxyshadis
19th October 2005, 13:45
If it was that easy, I'd have never started this. Sorry I'm not very good at explaining though, I guess I'd hoped it was more common but it doesn't seem that it is.

The pattern is A B C CD DE | E F G GH HI | I... where my filter returns A B C D D | E F.... So for every group of five frames to be returned to 4 requires extracting the last one from the frames around it somehow. I've seen premiere barf up something like this before, and it came up again while working on a set of videos someone would like me to restore from low-quality mpegs, so I made this up.

I know one other person posted recently (http://forum.doom9.org/showthread.php?t=100952) with a problem like this, so I put it out in case it was a larger problem to see if there was any demand for developing it beyond my immediate need. It is rather a special case, I know.

I did spend some time before I started experimenting with crestore, restore24, and restorefps, and I got the best results out of the latter, but not great. I didn't want to clutter up other threads with my bizarre blending patterns. :p

Edit: Wow, I feel tremendously stupid having done all that just to figure out it could be boiled down to several add/subtract statements. ;_; It'd be even simpler if overlay would return negative differences as well as positive.

# experimental
subframe1 = overlay(frame4, sframe3, mode="subtract")
subframe1swap = overlay(sframe3, frame4, mode="subtract")
subframe2 = overlay(frame5, sframe6, mode="subtract")
subframe2swap = overlay(sframe6, frame5, mode="subtract")
frame1add = overlay(frame4, subframe1, mode="add").overlay(subframe1swap, mode="subtract")
frame2add = overlay(frame5, subframe2, mode="add").overlay(subframe2swap, mode="subtract")

# finally, merge. naive will be 50% orig, 25% each blend, mine hopefully rather better.
deblended = merge(frame1add,frame2add)

The output could still be quite improved, maybe with some of the other stuff I wrote, but... sigh. What a way to waste a weekend. I'll chalk it up to a learning experience and rusty math.

Edit2: (I'm editing all over this thread.) Actually, a straight subtract brings out some horrific mpeg artifacting, since it doesn't play nicely with mpeg's psychovisual model. Heavy pre-filtering helps but not really enough. Wow. I'll have to ponder this new wrench.

MOmonster
20th October 2005, 09:50
Ok, I finally get it. Now, your function is also more clear for me. Maybe in a week, I can have a closer look on the source and your script, but now I have no suggestions for you.
Keep up the good work. ;)

Edit: Is it right that the blendweight is for all blends 50:50?

mg262
20th October 2005, 10:04
It'd be even simpler if overlay would return negative differences as well as positive.I haven't tested it in this incarnation, but the Average plug-in I recently released should be able to cope with negative weights, if it is any use...

http://forum.doom9.org/showthread.php?t=100626&highlight=Average

(In fact the code was just pulled straight out of the experimental fieldblending reversal plugin, which computes plenty of weighted averages to reverse blending. What all the maths in that is for is to figure out the correct add/subtract weights for arbitrary patterns... and to detect/cope with pattern breaks. RestoreFPS was hardwired to reverse a specific blending pattern, which is why it couldn't deal with your case that well... )

MOmonster
20th October 2005, 10:20
@mg262
So your Average Filter take also negative Weights. This of course would make it much more effective. :D
Is this possible? (I canīt test it here)
Average(alpha, -1.0, beta, 1.0, gamma, 1.0)

mg262
20th October 2005, 10:40
Yes. If you use weights which are (IIRC) < -2 or >= 2, it will use C instead of assembly, with a corresponding slowdown -- but I don't think there are any other limitations. It does exactly what it says, namely "average" = sum with given weights, so if you use it to subtract a clip from itself you will get 0 in both luma and chroma (not 128)... obviously you can get around this by adding an appropriate BlankClip as an extra argument. (In the case of fieldblend reversal, I don't think this should ever be an issue.)

I've just run a brief test and everything seemed to be fine, but if you have any problems, poke me...

foxyshadis, you can have your thread back now ;)

MOmonster
21st October 2005, 16:13
Ok, because I want to learn, too, I created also a small function against this problem:
find last version on page 3
The function is fast and easy, but there are three problems, two because of Average (stability and a green right). The other is the scenechanging. The function donīt work on the first five frames and can have problems on scenechanges.
If it is not stable enough on your pc, I can also use Lutxy instead of average (but that wouldnīt be that amasingly fast). ;)

Edit: mg262 has fixed the bug. Use the newest Average version and everything is running fine. ;)

foxyshadis
22nd October 2005, 03:14
I actually started on a rewrite using yv12subtract, it was much simpler than the overlay mess, but I think I hit a bug in avisynth's caching. (It's weird, if I returned side-by-side the difference behind and in front of the blend frames, it worked like it should, but if I showed the output in the left the right pane changed! It became a compare to two frames forward instead of the next one, and it seems to cause the output to mess up. And it happens so rarely but consistently that I can't make a testcase without going "here's my function and here's the frames it screws up on", even minor function tweaks changes where it shows up.)

I'm going to give yours a shot, it looks promising. I really need to get more comfortable in conditional environments, I mostly get a lot of "I don't know what 'blah' means" even when I work from the doc's examples.

MOmonster
22nd October 2005, 07:25
I changed the code a little bit for you.
Because your sample is an anime source, maybe there are 12fps scenes. For this I changed the pattern conditions a bit and added a alternative code. Because for 12fps parts there is only one blend of course we canīt use the same method. Iīm not sure if "Cowboy Bebop" has 12fps sequences, because your sample is not typical for that, but there are many other sources, that has still many 12fps sequences.

foxyshadis
22nd October 2005, 08:15
It has 12 and 24 fps sequences, so thanks for considering that. (Although with a single blend the recovered frame is obviously the same as the frame where the other blend would've been, you just have to figure out which is which. In testing mine I noticed that if you chose the wrong offset it would be very obvious even though it should have been roughly equivelent, in a single pattern, whichever way you went.)

MOmonster
22nd October 2005, 12:05
So the pattern of your function is really constant? My function try to find the pattern with the LumaDifference, if it is not clear the function decimate the some frame like in the last pattern but it doesnīt try to restore a clear frame, because he could use the wrong frames and that will look worse then the source.

foxyshadis
22nd October 2005, 23:40
I should add some more samples, that way you'll have more to test against if you want. The pattern changes every scene change and occasionally within a scene (I manually shifted it in those cases).

2 (http://foxyshadis.slightlydark.com/random/cb_rawclip2.avi), 3 (http://foxyshadis.slightlydark.com/random/cb_rawclip3.avi), 4 (http://foxyshadis.slightlydark.com/random/cb_rawclip4.avi), 5 (http://foxyshadis.slightlydark.com/random/cb_rawclip5.avi), 6 (http://foxyshadis.slightlydark.com/random/cb_rawclip6.avi)

(They should be uploaded within 10 minutes, all 3-5 megs and about a hundred frames.)

I'm thinking that with less clean sources difference squared would be better than plain lumadifference, but I'm not sure how to do that in pure avs script. (mg, since you're so awesome at whipping up quick filters, would it be possible to make a ssd/satd/whatever filter with your restorefps code? Unless one already exists that I don't know about.)

mg262
23rd October 2005, 08:55
More than happy to! (But I'm out all day today, so you will have to wait a little -- sorry about that.) I exposed my blend detection method for use yesterday (check the RestoreFPS thread)... that might be what you need? Otherwise I can easily expose the SSD as well.

foxyshadis
23rd October 2005, 11:13
Wow, that's hot! I hadn't seen your edits in the other thread. I'll test it out right now.

(I think Y/U/VDifferenceToNextSquared functions might be useful to other authors, but I don't know how much. I have no idea how useful satd would be, but that's mvtools land.)

mg262
23rd October 2005, 20:56
So, for anyone else reading this thread, foxyshadis and I sent a couple of PM's back and forth... the upshot being that although the BlendAngle is not meant for consecutive blends, although it seems not to be as bad as I thought. I also promised to give the error measure I would use for this particular problem (if you don't want to wade through the maths, skip to Conclusion)...

We start with this model for how our blended frames A,B,C,D are produced:
A=x
B=0.5x+0.5y
C=0.5y+0.5z
D=z

And we are trying to recover the original unblended pictures x,y,z. There are two methods you can use, one simple one where you just use x=A and z=D, and a more complicated one where you try and use the information in B to give a better guess for x. I'm going to stick with the simple method.

The least squares method I use in RestoreFPS gives the following estimate y' for y:
y'=-0.5A + B + C -0.5D
also as noted
x'=A
z'=D
(And MoMonster has independently come up with the same thing.)

Now, we can plug these guesses for the original frames back in to our model to see what they would have actually given when blended.

B' = 0.5x'+0.5y' = 0.5A + 0.5(-0.5A + B + C -0.5D) = 0.25A + 0.5B + 0.5C - 0.25D
C' = 0.5y'+0.5z' = 0.5(-0.5A + B + C -0.5D) + 0.5D = -0.25A + 0.5B + 0.5C + 0.25D

Now, if the original model was sensible, B' and C' should be very similar to B and C respectively. So the sum squared differences between B and B', and between C and C', should be small. I.e., the following two quantities should be small:

(B'-B)^2 = (0.25A - 0.5B + 0.5C - 0.25D)^2
and
(C'-C)^2 = (-0.25A + 0.5B - 0.5C + 0.25D)^2

These are the same quantity... so to determine whether in the model is a good one (i.e. blends lie in this particular pattern), we compute (0.25A - 0.5B + 0.5C - 0.25D)^2 and see if it is small -- i.e. we compute (0.25A - 0.5B + 0.5C - 0.25D) for each pixel, square the results and add.

Note that we can multiply this quantity, (0.25A - 0.5B + 0.5C - 0.25D), by any constant we choose (it just affects the blend-detection threshold). So we could use A-2B+2C-D... but the original (or a version with even smaller coefficients) may be preferable to prevent overflow.

Probably the easiest way to implement this is to use Average or some other plug-in to compute (0.25A - 0.5B + 0.5C - 0.25D) (offset at 128), and I will throw together a plug-in that subtracts 128 from each pixel, squares, and adds together the results to provide a quantity you can threshold on.

I try to stay away from the actual equations where possible... I hope that wasn't too unreadable. In any case,

Conclusion:
To check whether you have this pattern:
Frame n =A=x
Frame n+1=B=0.5x+0.5y
Frame n+2=C=0.5y+0.5z
Frame n+3=D=z
Compute (0.25A - 0.5B + 0.5C - 0.25D), and see if the average squared value of this is small. [You can try using other averages, like LumaDifference.]

Edit: the "complicated" estimate of x is 0.9A+0.2B-0.2C+0.1D (and z similarly). But calculating something like this may magnify the errors due to MPEG encoding... so be careful if you try it.

MOmonster
24th October 2005, 13:42
I have allready the idea for a blenddetection that is easy and not to slow and makes no difference between 12 or 24fps, so maybe it will work better. But I canīt test it now, tomorrow I think I can tell more.

@Clouded
There is allready a possibility to get the SSD for low differences. With Lutxy we can create a squared diffmask and then get the value with AverageLuma. But this way is slow and strong limited (only for low differences), so that a function would be really useful for many of my functions.
Iīll test your blenddetection also this evening ;) .
For what is the complicated way useful? We can change the influence of every frame on the result, but for this example we donīt know what has the better quality. Or is the only for the explaination? If I give A a higher weight, then we canīt compare the result so good.

mg262
24th October 2005, 17:20
Assuming that noise is introduced after blending...
another thing - i couldn't find a pertinent bit to quote, but you mention you're assuming a "noiseless" blend between fields. the converter is digital, so no matter how noisy the source is, the actual blending will not have any noise (except rounding error, but that should be very minor). however, after mpeg-2 compression a fair bit of noise could be introduced....and also making sensible assumptions about the noise (such as that you get the same amount on every frame), then the maths predicts that

0.9A+0.2B-0.2C+0.1D

will give you a better (more accurate/less noisy) guess at what the original frame was than simply using

A

. On the other hand, the reduction in noise is only predicted to be 10%, so I'm not sure it's worth trying. (Until I did the calculation, I expected a slightly larger effect...)


foxyshadis+MoMonster,

Something I forgot to mention in the other thread (sorry about this... yesterday was very crazy) is that you can dump the number-streams produced by BlendWeight, BlendAngle to a text file by writing this kind of thing:bob
source = last
angle = blendangle(source)
WriteNumber(angle, "angle.txt")
-- but be warned that that will calculate and dump the numbers of all the frames -- so either use it on short clips or be prepared to wait.

I was thinking of putting together a function called AverageSquare which subtracts 128 from each pixel value, squares them all, averages the values for each frame, and returns the result like blendangle or blendweight so you can threshold on it. Average-Square has all the nice properties of Sum-Square, plus the numbers are smaller and comparable between frames of different sizes. (Taking the square root of this gives another number, RMS or root-mean-square -- in some ways nicer because it actually corresponds to a legal luma value, and because it directly corresponds to the distancess on the triangles I drew.) Probably just C++ to begin with, with assembly added when I have a little more time.

So you would write something like
A = source
B = source.trim(1, 0)
C = source.trim(2, 0)
D = source.trim(3, 0)

Average(D, -0.25, A,0.25,B, -0.5,C,0.5)
#D first because length of the result is taken from the first argument... perhaps I should change this to the shortest length?
blendprobability= AverageSquare()
If(blendprobability.isbelow(...),...,...)

Would that be satisfactory?

Edit: bug in that script... I should have added an extra BlankClip argument to Average in order to add 128 to all the pixel values...

foxyshadis
24th October 2005, 19:14
Clouded, Momonster, one of the things I found after I switched to yv12subtract (which is essentially the same as average but in two steps), is that a straight difference will do an admirable job of giving back the original frame but still rather artifacty, and each has artifacts from the clear frame next to it, so a further difference of the two and swapping areas with edges that don't appear in the other. (Edges are easiest, since I don't know how to decide which frame to pick parts from in an overall difference.) It significantly improves the recovery from a compressed source.

ie, this:

edgemask1 = reversedframe1.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special") \
.levels(96,1,160,0,255,coring=false)
edgemask2 = reversedframe2.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special") \
.levels(96,1,160,0,255,coring=false)
diffedgemask1 = overlay(edgemask1, edgemask2, mode="subtract").inflate().blur(.7)
diffedgemask2 = overlay(edgemask2, edgemask1, mode="subtract").inflate().blur(.7)
frame1 = MaskedMerge(frame1, frame2, diffedgemask1)
frame2 = MaskedMerge(frame2, frame1, diffedgemask2)


The specific edgemask, inflate, and blur values are just what gave better results on a few segments of this source after testing, I made no real effort to find the 'best' possible values but I might be able to do something if it'd help.

I also have something that I realized is a sort of clipped median, parts of a clean and blended frame that are essentially equal should be propogated across where the average would move the value, but this I haven't tested as much so I don't know how useful it really is.

diffframe1 = overlay(blendframe4, clearframe3, mode="difference")
diffframe2 = overlay(blendframe5, clearframe6, mode="difference")
# if identical areas are found between subsequent frames, use them, forget the algorithm
samemaskframe1 = diffframe1.levels(120,1,192,0,255,coring=false) \
.binarize(threshold=30,upper=true).blur(.5)
samemaskframe2 = diffframe2.levels(120,1,192,0,255,coring=false) \
.binarize(threshold=30,upper=true).blur(.5)
frame1 = MaskedMerge(frame1,clearframe6,samemaskframe2)
frame2 = MaskedMerge(frame2,clearframe3,samemaskframe1)

Again the precise values are more 'what worked' than calculated anyhow.

I don't know if you want to build the post-processing into it, but at least the first step would probably be essential for encoded sources and couldn't really be done post-merge. Unless yours just leaves the two separate frames in the output, though a merge and copy is also good for artifact reduction.

Oh yeah, question. Your filter scans ahead as well as back, right? One of the things that annoys me about removeblend (ack, all these unblenders, I'm getting confused) is that it'll take a frame that's just marginally within the threshold and skip a one that's way under it since it can't have two in a row, rather than looking ahead and picking the best. (Which also changes its forward/backward behavior.) I'm probably going to try modifying the source for that one.

mg262
24th October 2005, 20:13
AverageSquare, 24 October 2005 (http://people.pwf.cam.ac.uk/mg262/posts/blend/AverageSquare_24Oct05.dll)

Just use source.AverageSquare(), and you will get a number stream like that produced by BlendAngle()... you can use the same IsAbove+If/WriteNumber functions on it. It works as noted above, i.e. subtract 128 from pixel values before taking the square.

N.B. these number streams are just like clips... you can use Trim(1,0) to get the value for the "next" frame, and more generally cut/splice/interleave them just like clips.

Proper reply tomorrow... but the filter will definitely look ahead. Don't worry too much about feedback on the blending methods... for the general case it's quite hard to squeeze things into the maths. I'm pretty much limited to just pushing it through and seeing what comes out... although I envisage postprocessing in scripts which will depend on the source type -- for example my blended material is largely VHS, so macroblocks aren't a problem!

foxyshadis
24th October 2005, 21:15
It isn't so much macroblocks as residuals of the previous/next frame that were supposed to be in the blend but were compressed away. Hmm. I thought VHS tended to similarly compress/smear areas with minor differences, but maybe that's only older tapes.

mg262
24th October 2005, 22:39
Just for fun, try this...
avisource("...")
source = last
A = source
B = source.trim(1, 0)
C = source.trim(2, 0)
D = source.trim(3, 0)
grey =d.levels( 16, 1, 200, 128, 128, coring = false)

residueframe=Average(Grey, 1, A,0.25,B, -0.5,C,0.5,D, -0.25)
residue= AverageSquare(residueframe)
WriteNumber(residue)
ispatternstart =residue.isbelow(0.7)
singleframe = ispatternstart.Trim(0, -1)
isfirstblend = singleframe +ispatternstart
issecondblend = singleframe+singleframe+ispatternstart

if (isfirstblend,A.Trim(1,1)+Average(A,-0.5,B, 1,C,1,D, -0.5), \
if (issecondblend,A.Trim(1,2)+Average(A,-0.5,B, 1,C,1,D, -0.5), \
source.greyscale))
stackvertical(source, last)

You may need to adjust the 0.7 threshold. Frames that have been passed through unchanged are grayscaled to make it easier to see the reconstruction. The blend detection method here is very primitive and uses no pattern guidance -- the filter should do a lot better (like I said, this is just for fun!). I don't actually think AverageSquare() is the best thing to use in a reversal script in these circumstances... we maywant something that penalises large values even more heavily. Try looking at stackvertical(source, residueframe), noting that the residue is low on the frame immediately before the blended pair.

NB decimation should occur at the same time as reversal, i.e. all the secondblends should be removed... but that's hard to achieve in a script.* So I just duplicated frames.

*Just as I wrote that I had an idea... I will elaborate on it tomorrow.

Edit: it should be possible to improve the results by borrowing one of MoMonster's ideas and blurring the residueframe. This needs a blur with fixed weights -- Blur() or one of the gaussian blurs or box blurs floating round this forum. Or... ReduceBy2() or even ReduceBy2().ReduceBy2(). Just change

residue= AverageSquare(residueframe)

To

residue= AverageSquare(residueframe.ReduceBy2())

foxyshadis
25th October 2005, 00:47
I would tend to prefer Tdecimate; simply removing the frame would work, but I'm afraid all the scene changes would add up and throw off audio sync. Maybe a random distribusion would keep the sync to within +- 2 frames? Static scenes might do the same, but the filter is probably sensitive enough to ignore that.

Watching you is like sitting in on a good professor, very clear and always bubbling with new ideas. ;) I apologize for taking your time off your own projects though. I'm off to test this.

Okay, I understand how it works now, I'm going to look for ways to tweak it for better accuracy. There's some obvious ways (you're right, it needs a stronger differencing, but levels helps there) and some that'll be a bit tougher (pattern matching with realignment). I should be able to massage momonster's script into that. Is it bad that I like working on the method more than the video? >.> Must be my lack of time-consuming projects lately.

Just curious, but is there a way to get at the actual numeric value, rather than a boolean lessthan/morethan? I'd like to compare with nearby frames; if it has the lowest residue with a 4 frame radius, assume it is the correct and then put in sanity checks for pattern changes, and vice versa for others. Unless a localminimum would be better implemented another way; to be honest I don't know enough about your celbackground tools and I should probably dig deeper into them.

MOmonster
25th October 2005, 15:21
@foxyshadis
I had a closer look on your examples and created this function:
newer version on the next page I hope there are no strange bugs in it, because I tested it on another Pc and I couldnīt copy it, so I written what I know :D .
Your second example is really a nightmare. Also this function donīt detect the blends at the beginning of a scenechange (edit), but the result seems to be accurate enough. The quality could be a little bit better, maybe you can add your ideas, also it seems to be better just using two frames for restoring.
Instead of tweak you should set a deblocker or another spatial filter, but there has to be a filter, else you canīt use decimate or tdecimate after. Maybe I can use the decimation method of Crestore to avoid the use of a slow decimater. Weīll see.

@Clouded
Sorry I couldnīt test your filter, there was a burning problem. Iīll try it once more. :D

Edit: Ok, this version wasnīt free of bugs, hoply this one is it now. I add YPlaneMinMaxDifference to get the frames with the better quality, also deblock() from DGdecode.dll is used. The blenddetection is the same as before, but quality and speed (because tdecimate isnīt necessary anymore, wonīt give better results!) is better. :D
I wonīt do much more against this problem, because the function works good and I still never had a similar problem source.

Edit2: I was able to copy the code, it should now really be bugfree.

mg262
29th October 2005, 19:54
I'm really sorry I have taken so long to reply -- I woke up in a coding mood on Tuesday and this thread somehow slipped my attention.

@foxyshadis,
I'm really embarrassed now! Don't underestimate how much I learn from you guys -- my approach to things is very much to throw maths at it; sometimes it works, sometimes it doesn't, but it's not a proper substitute for the intuition for video that you scripters have -- I marvel at some of the things that are accomplished with scripts. For that reason, I particularly enjoy writing things to be used in complex scripts... and I learn a lot from seeing how they are used. So, please don't worry about distracting me from my 'own projects'!

Is it bad that I like working on the method more than the video?Believe it or not, I have yet to back up a DVD per se :p

I'll add functions called Minimum (taking any number of arguments), Maximum, and IsEqualTo -- that should let you do what you need? (The idea behind these number-per-frame and boolean-per-frame pseudo-clips is that it is very easy to code new functions to process them -- so do list anything that might conceivably possibly be useful and I will throw it in. Incidentally, don't worry about the delving into Cel Background -- it set up the framework for these pseudo-clips, but it's not finished or properly documented yet.) If that isn't enough to deal with the issue, I can try and look up how to expose things to/read information back from ConditionalFilter/ScriptClip -- but I find the weird back-to-front inside-out syntax of these very unwieldy, so I prefer to use things that behave like clips where possible.

@MoMonster,

At the time I started writing assembly, I had no decent references in front of me so I didn't know what was needed to allow things to run on non-SSE2 boxes (turns out that the answer is very easy -- just don't use 128-bit registers), and also because I was used to being on the low-end of the technology scale I underestimated how many people couldn't use SSE2. I am now writing iSSE as standard for new plug-ins, and I will rewrite the blend reversal to deal with that. Sorry for the inconvenience. I'll reply to your PM shortly.

Edit:
ReverseBlend, 29 October 2005 (http://people.pwf.cam.ac.uk/mg262/posts/blend/ReverseBlend_29Oct05.dll)

Contain functions Minimum, Maximum, IsEqualTo as promised. Usage example:

next = residue.trim(1, 0)
WriteNumber(maximum(residue, next, next.Trim(1, 0)), "maximum.txt")

[I just added the file name argument to WriteNumber as well -- thought it was already there, but obviously I missed it... .]

Min and Max can be used as synonyms for Minimum and Maximum.

foxyshadis
30th October 2005, 00:30
Don't worry about time, I was actually pretty busy at work myself and then working on testing whether my minimum pattern would really help in a real function. Thank you for taking the time to implement my suggestion though. =D

Avisynth supports overloading functions based on argument types, right, so jdl's min/max for int/float types won't be affected?

I actually switched to yv12lut ("x 128 - 3 ^ 2 / 128 +", ie, x^3) and lumadifference with momonster's framework for the time being, and it really made a difference on accuracy once I added minimum-finding. My method is to take the 5-clip average to find the blend, then combine the two two-frame averages in the same way I did the others to clean them up a bit more than a direct 4-frame average. Definitely faster with average, less intermediate operations.

I'll rewrite for your min/max. The best thing about it is that there are no arbitrary thresholds (aside from a maximum sanity check), it should be able to work on segments with high or low noise without much problem. I'll post the current one once I put some finishing touches on it and then the next one later when I can get around to it.

foxyshadis
30th October 2005, 04:52
Okay, I've replaced the first post with the updated function, using momonster's framework, clouded's residuals, and my weighted pattern-matching. It all comes together with extremely high accuracy and only one noticed false positive (in a static scene). It could be trivially modified to support other patterns.

Maybe a small speedup would be a dup detection for "blends" across duplicates, at least save the effort of testing and unblending; I avoided keeping all frame lumadiffs so random access is sort of reliable. Rewriting for clouded's numeric-clips will give a much greater speedup, without all the lumadiffs. Random access is very slow now since it has to compute all ten frames around one, and it and moving backwards will use bad patterns because of the volatile variables, but going forward corrects things.

(Any way of avoiding these (isblendx) in non-conditional functions? Idempotence is important. I'm thinking a numeric clip that could be set to true/false (ie, isabove(1) maybe) and shifted around to look for a pattern start. I need it because it's a hard rule that no pattern can start less than 4 frames after the last, otherwise the last one wouldn't be detectable.)

I want to think about whether anything else could be included, maybe logged output, and generate a few more clips as examples before I move on to the next version.

Usage is just fx_unblendTC().

If anyone wants to hammer at the detection to see if you can tweak the thresholds for better results, you should replace d99 with:

d99=scriptclip(source, """(isblend1 == true ? unblended.subtitle("blend",align=9) : (isblend2 == true ? unblended.duplicateframe(0).subtitle("blend",align=9) : source)).subtitle(string(residue)).subtitle(string(frametesta + frametestz),align=4,y=-1)""")

Basically it's just a debug that shows whether the fame is blended, the absolute residual difference, and the final result of the tests.

(I considered a per-test debug mode but the last thing I need is even more variables.)

I'm so happy to get this done, I learned so much but I want to get back to actual encoding now. ;p

MOmonster
31st October 2005, 12:52
Nice function foxyshadis. Not so easy to understand, but Iīll have a closer look on it this evening (I canīt understand all the LumaDifference calls for now). Have you testet it allready with Fdecimate? If not, please donīt give the advice to use. In general it works not good together with the coditional enviroment.

@mg262
Thanks for the filter modification and your helpful pm. Iīll draw on your offer if its time, thanks.

foxyshadis
31st October 2005, 20:46
Thanks, I hadn't actually tested! If it accesses the frames slightly out of order then it will cause a few problems. I'll test it out and report back.

All the lumadifference calls just estimate the diff. between a frame and flat grey (which is theoretical perfect blending pattern match), for the 4 frames on either side of it, as well as an extra check for those 4 compared to the fifth. framezx/diffzx are frames before the current, and framex/diffx are after. (Sorry I couldn't come up with better names!)

FredThompson
1st November 2005, 00:41
Where are the samples?

mg262
1st November 2005, 00:47
Post 17: http://forum.doom9.org/showthread.php?p=727409#post727409

FredThompson
1st November 2005, 01:23
Ah, I was thinking before/after but these are a nice addition to my bag o' test samples.

foxyshadis
1st November 2005, 05:41
Momonster: Thanks for alerting me; 4, 5, and 6 work just fine with fdecimate while 2 and 3 failed pretty badly. All default settings. I think that partly has to do with short samples, but I made a recommendation to write a temp file anyway. (I have yet to test tdec.)

Fred: Samples are up now, apologies for being lazy. ;)

FredThompson
1st November 2005, 06:23
Thanks for the samples, very impressive.

MOmonster
1st November 2005, 08:23
I canīt load your function. This is the problem:
# unblend output and various post-processing measures
unblend1 = Average(sframe3, -1.0, sframe4, 2.0)
unblend2 = Average(sframe5, 2.0, sframe6, -1.0)
edgemerge = fx_unblend_edges(unblend1,unblend2)
Avisynth doesnīt know the function fx_unblend_edges, of course there isnīt a function like this. Can you also give this function?
They all only give the difference to a grey flat, but than you donīt have to use 10 times LumaDifference every frame. Only one time, thatīs the advantage of frameevaluate, also if this mean that the first 10 frames arenīt treated correct. In general the first frames are black. The other thing is that PlaneMinMaxDifference is similar, not far so accurat, but similar and it seems to work. I just say that because it is faster and can be used outside the enviroment (just faster). Bart S give us this possibility.

@mg262
The filter still doesnīt work on my Pc (only these two, all your other filters work). I donīt know why, but it isnīt that important, Iīll test it on another Pc in two weeks or so.

EDIT:
@foxyshadis
The deblended xvid files, are they made from the blended xvid files or from the huffyuv files you linked earlier. Itīs important for the quality comparison.

foxyshadis
1st November 2005, 13:16
You're kidding, did I really forget to post that? Eek. I totally realized I needed to earlier , I wonder how it slipped my mind. Posted in the main post too, it's just a little helper function.


function fx_unblend_edges(clip sup1, clip sup2) {
edgemask1 = sup1.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special").levels(96,1,160,0,255,coring=false)
edgemask2 = sup2.edgemask(thY1=2,thy2=2,thC1=4,thC2=4,type="special").levels(96,1,160,0,255,coring=false)
diffedgemask1 = overlay(edgemask1, edgemask2, mode="subtract").inflate().blur(.7)
diffedgemask2 = overlay(edgemask2, edgemask1, mode="subtract").inflate().blur(.7)
edgemerge1 = MaskedMerge(sup1,sup2,diffedgemask1)
edgemerge2 = MaskedMerge(sup2,sup1,diffedgemask2)
return interleave(edgemerge1,edgemerge2)
}


They're made from the huffyuvs. Any filtering, compression, or changes to the source will weaken the detection (and the reversal), except crop-type and levels (since it's a linear transform). I hate to think what mpeg->xvid would do to it. (Interesting stress test possibility though.)

I used a lot of lumadiffs so I could skip around without having to wait for new values to reload, and to leave an extra step out of development, but there's probably an intelligent way I didn't think of to shift around or dump and refresh all data on random access. (If I had done it one per loop, it's almost guaranteed the chained fdecimate results, for one, would look a lot worse.) If I could find that way there'd be no need for temp files or cautious random access. I'll look into planeminmaxdiff too.

I had a think about this while I was napping, and the best solution would be to use current_frame and a last_frame. Then you do something like:
frame5 = (cf - lf > 0 && cf - lf < 10) ? select(cf - lf,frame5,frame4,frame3....) : lumadifference(...)
You would change the bounds as necessary for each frame ([0,-10] and [10,0]), so that any and only frames that are required are calculated, enabling random access while being as efficient as the standard "shuffle" that most conditional chains have.

On the other hand, it's a mess, isn't it?

(For instances like this I've always wished programming languages would have a ( 5 < cf - lf < 15 ) condition syntax which would be cleaner than (cf - lf > 5 && cf - lf < 15) and avoid explicit temp vars for functions with side effects. If wishes were fishes...)

mg262
2nd November 2005, 11:01
foxyshadis,

It would have to be a function, but it would be easy enough to write something that took three numbers (or any number of numbers) and told you whether or not they were arranged in increasing order. That's either for built in AVISynth types or the things I gave you to play with. Do you want one?

MOmonster,

I'm really sorry the filter isn't working -- it's definitely something I want to look at. (Though I'm a bit buried in Motion at the moment.) I think that it might be that it makes use of SSE2... . In any case, if you can give me a minimal crashing script I will try and sort it out (but let's not hijack this thread).

foxyshadis
2nd November 2005, 12:03
That would be kind of neat as a curiosity, but I mostly run into it in other languages. Thanks though!

By the way, have you decided what you are going to call those clips? I call them numeric, but I'm sure there's a pithier name.

MOmonster
7th November 2005, 13:30
@foxyshadis
I tested your script and yes it gives a better output than my FixBlendIVTC function. But because Iīm ambitious, I build a high quality version of my function. FixBlendIVTC_HQ detects some more blends and has a counter variable to avoid wrong blend detections, but much more important for the most reversed Blends the quality is far better than with my last version and also better than with your function. So, itīs worth a try. I put the both scripts (little tweaked FixBlendIVTC + HQ version) in the attachment. You need Average and Masktools to run it (for the simple version only Average). I recommed to use it that way.FixBlendIVTC_HQ()
decimate(cycle=5, quality=0)
The decimate filter from the decomb package is fast, tested a lot and does absolutly what it should do, so there is no reason to use another decimater or another qualitymode.

Edit:
Sorry, I gave you an older tryout and not the last version. I changed the important things I remember and uploaded the updated one (the last will come tomorrow). With better quality I donīt mean that all pictures looks better. My function has no artifact protection, so especially on the first and your last clip the output of your function looks better. But the blend reversing itself seems to be better (especially on other higher quality samples, I created for tests). Just have a look on your second sample. The crows show good what I mean. For your special clip it would be nice to combine your artifact protection with my reversing.
Maybe if I have some more time :D .

Edit2: Attachments removed to a later post.

MOmonster
9th November 2005, 11:18
Ok, I uploaded the last version. After a closer look to your function I recognize that the HQ version works really similar. If you take a look at the luma channel my function gives a nice output, but the simple chroma reversing is worse than your output. It shouldnīt be hard to change this :) .

foxyshadis
10th November 2005, 03:59
I downloaded them and I'll test them out, but it'll probably be a few days before I really can. Thanks though! More fullproof blenddetection is more important anyway, and it's really the harder problem, any improvements in that area are welcome.

MOmonster
11th November 2005, 09:23
I allready find a more accurate blenddetection. Itīs slower, but works really nice. I wonīt have time to complete the function this weekend, but the next week I think Iīll upload it. So, donīt waste your time with testing these versions :) .

foxyshadis
11th November 2005, 12:47
Will do. Aha, you've been bitten by the bug, haven't you? ;)

MOmonster
11th November 2005, 12:52
I couldnt test it with longer clips and recognized a small problem with the counter, but nothing much important. Is this the bug you mean or is there another I donīt know about. :confused:

foxyshadis
11th November 2005, 17:10
Sorry, the phrase must not have translated, I meant you've become a bit addicted to finding the perfect solution too. I hadn't actually tested yet. ^^;

MOmonster
16th November 2005, 11:41
Ok, yes I know what you mean. Sorry for my bad English.
I finished the blenddetection and it does what it should do. The big problem left is the chromamasking. It seems that MaskedMerge just take the chroma of the first clip and doesnīt mask it. Also with chroma linking of the mask (FitY2UV()) I have no luck. If I change U2Y and create a second Masked clip and use this chroma channel, it looks better. But this is not really effective and gave me only one nice chromaplane. Have you any ideas how to link the chroma to the luma? Make I something wrong with MaskedMerge?

mg262
16th November 2005, 11:51
MaskTools 2.0a mt_merge with u=v=3 might do it...

Didée
16th November 2005, 12:20
MOmonster, please elaborate on your problem. I can't see any problem.

As Clouded pointed out, you have to specify "U=3,V=3" in MaskedMerge to also process chroma. This is nothing new new in MaskTools' alpha, but is the very same in MaskTools v1.5.x.

A frame:
http://img356.imageshack.us/img356/998/frame7bu.th.jpg (http://img356.imageshack.us/my.php?image=frame7bu.jpg)


edge = o .prewitt() .greyscale() :
http://img356.imageshack.us/img356/2908/yedge6zx.th.png (http://img356.imageshack.us/my.php?image=yedge6zx.png)


edge2 = o .prewitt() .fity2uv() :
http://img356.imageshack.us/img356/5595/yedge2uv3sw.th.png (http://img356.imageshack.us/my.php?image=yedge2uv3sw.png)


show = stackvertical( stackhorizontal(edge2.UtoY(),edge2.VtoY()), edge2.greyscale() ) :
http://img85.imageshack.us/img85/5581/showyuvedge2sz.th.png (http://img85.imageshack.us/my.php?image=showyuvedge2sz.png)


Everything is fine.


edit: there's a minor problem with fitY2UV producing an offsett of 0.5 pixel horizontal and vertical. Probably FitY2UV is using the same code as Avisynth's ReduceBy2, which has the very same offset problem.
But supposely that's not the problem you were facing.

BTW, I never liked Horizontal/Vertical/ReduceBy2 for just this reason. And if creation of halfsized/quartersized/... clips is done in scripts, where these reduced clips are blown up to fullsize again later on, then the shrinking should never be done with ReduceBy2. (It's a rather common mistake.)

foxyshadis
16th November 2005, 16:18
momonster, I have another clip sitting unprocessed, I could strip off the audio and give you two or three minutes of it, so that you have a longer testbed if you want it?

Here it is: Niea (http://foxyshadis.slightlydark.com/random/Niea's_Life.m1v)

MOmonster
17th November 2005, 08:23
@Didee & Clouded
Thanks for the fast help. I think I have an older documentation, thatīs why I donīt know of these parameters.

@foxyshadis
Thanks for the clip, Iīll test it soon.

MOmonster
18th November 2005, 09:58
So, I updated FixBlendIVTC_HQ to version 0.5. It gives a really nice output, has a much better single-blend-detection and a better postprocessing. The negative point is that itīs so heavy specialized for your first samples. I also didnīt make internal values changeable by parameters. Also with these parameters the functions fails a lot on your new clip. The motions is in many cases just to low.
I have allready a idea to avoid this problem. A mix of this singe-blend-detection with the Cdeblend algo and maybe using unblend for preprocessing should handle also these sources much better. I think Iīll create such a function the next days, but it will take some time (many things to do in reallife :) ).

Edit: Attachment moved to a later post.

foxyshadis
18th November 2005, 18:46
Thanks for taking the time to work on this. =D I'll grab it and see if I can offer any useful tweaks to help it along. I tested using unblend and reverseblend as a preprocessor to older versions, they proved rather too dumb to make effective use of, because they screw up all the double-blends and sometimes pick the wrong frame to replace a single-blend with, but if you think you can marshall them into form it'd be nice to see.

I have another source with motion much much lower than that too. It might be better to try a manual on it, but I won't be working on it for a few weeks so I'll deal with that when I get there.

MOmonster
21st November 2005, 10:45
@foxyshadis
I had a closer look at your new source and recognized something strange. I donīt know how it came to this, but the blendweights are very different. A good blenddetection and this blendreversing we do now isnīt possible that way. Unblend gives here better results than my function. Sorry, but I donīt how to restore this source. :(
But still my function will get some little improvments next time.

foxyshadis
21st November 2005, 19:18
Really? Eeek! I'm so sorry! I should have checked to make sure, it was from the same guy so I assumed it was the same thing without closely examining it.

I'll find you another one, if you'd still like, and this time make sure it is what I say it is (although frankly, just compressing a hand-made clip into mpeg-1 or 4 should be enough to give 'real-world' conditions).

MOmonster
22nd November 2005, 12:31
I'll find you another one, if you'd still like, and this time make sure it is what I say it is (although frankly, just compressing a hand-made clip into mpeg-1 or 4 should be enough to give 'real-world' conditions).
Of course I like. I donīt have so much time, but Iīm really interested in further improvements. ;)

LogicDeLuxe
24th November 2005, 20:58
What plugins do I need for this to work? You only mention MaskTools in your first post, and I'm a bit confused about all the many posts. I'd really like to give this a try.

foxyshadis
24th November 2005, 21:07
Masktools and Average. Did I not mention Average when I edited? I'll fix that now.

Same for mine or Momonster's. (Although like he says, his is somewhat better and faster than mine, though I haven't had a chance to full test it, since I'm on vacation.)

LogicDeLuxe
25th November 2005, 15:26
I loaded those plugins. Now I get a Script error: there is no function named "min"
([ScriptClip], line 3)What did I do wrong?

MOmonster
25th November 2005, 17:07
@LogicDeLuxe

Foxyshadis function needs also this (http://forum.doom9.org/showthread.php?t=72999&highlight=deleteevery) (the Min/Max filter) I think, but Iīm not sure, because for tests I write the function into the script. My function doesnīt need this. But Average and Masktools is so or so needed. :)

LogicDeLuxe
25th November 2005, 20:52
Thanks. Works great now. It doesn't even seem to harm hybrids, ie. scenes with those blend crap together with clean 30p scenes. That's even better.

Now dealing with such a hybrid, I can't just decimate the result to 24 fps.
What I'd like to do is a PAL speedup, ie. converting it to a hybrid with 25p scenes and fieldblended 50i scenes from the 31.25p parts.
Any idea, how to achive this?

MOmonster
25th November 2005, 21:36
@LogicDeLuxe

Maybe I can create a function that reads the range of this blended parts, if this would help you.
It would be good if you can upload two short samples (one 30p and the other blended). I like to have a look at it.

LogicDeLuxe
25th November 2005, 22:39
I thought about something like this:video=fx_unblendTC()

video
decimate
AssumeFPS(25.00)
vid_progressive=Lanczos4Resize(720,576)

video
AssumeFPS(31.25)
Lanczos4Resize(720,576)
ConvertFPS(50)
SeparateFields
SelectEvery(4,1,2)
vid_interlaced=Weave

ConditionalFilter(vid_progressive, vid_interlaced, "is_30p", "=", "true")
If I had an expression for "is_30p" that should do it.

MOmonster
25th November 2005, 23:20
I think something like this is possible. Give me some days. I donīt have the time for this now. :)

MOmonster
29th November 2005, 14:12
I thought about something like this:video=fx_unblendTC()

video
decimate
AssumeFPS(25.00)
vid_progressive=Lanczos4Resize(720,576)

video
AssumeFPS(31.25)
Lanczos4Resize(720,576)
ConvertFPS(50)
SeparateFields
SelectEvery(4,1,2)
vid_interlaced=Weave

ConditionalFilter(vid_progressive, vid_interlaced, "is_30p", "=", "true")
If I had an expression for "is_30p" that should do it.

Sorry, but it isnīt that easy like I thought.
I created a function that preanalyse the next five frames and can decide to restore or use a given clip. The problem with the conditional enviroment is the different speedup.
A solution can be to output the frames where the source change to 30p and then back (similar to my interlacing_reader), but maybe this function is just ok.

Use higher thresholds to recognice more 30p parts. The pp parameter can be 0 (non), 1(medium), 2(max). The nblength says the function after how many frames (with no detected blends) it should use the nbclip. Nice tryout. ;)

p = last.ConvertFPS(23.976*2) # or changefps()
p = p.separatefields().selectevery(4,1,2).weave().changefps(29.970)

FixBlendIVTC_Hybrid(nbclip=p, pp=2, nblength=11, hthresh=5.2, lthresh=2.3)
decimate(cycle=5,quality=0)
assumefps(25.000)
It is absolutly not proof that this works. I tested only a mask clip, but theoretical :confused: .
Just give a report back, I can try to make it better.

Edit: Sorry, of course it should be "changefps(29.970)" after weave. Is changed. ;)

LogicDeLuxe
1st December 2005, 19:42
The detection seems to work fine with the default parameters. I don't really understand how I should tweak the parameters exactly.

But I get glitches at some scene changes. Looks like it subtracs the last frame of one scene from the first frame of the next scene, which looks much more distracting then blended frames since it tends to flash. I think, it has to do with poor edits, which you find in so many TV series, ie. there are scene changes where there is only one field of a frame left.
In such a case, the frames around a detected scene change should be passed untouched. An option allowing this would be great.

Also, I wonder, is there a ConvertFPS replacement which works in YV12? I'm not that happy with the ChangeFPS result, and I certainly don't want to convert the colorspace more than neccesary.

foxyshadis
1st December 2005, 22:17
I think clouded's Motion filter includes one. Or maybe I'm thinking of another filter but I know I saw it in this forum recently.

Try lowering hthresh, I think that might help. But I haven't had a chance to play with the thresholds to see which do what just yet.

Oh, and I'm going to try it on the Blended Clip From Hell(tm) just to see if it works at all. It's double-blended like the rest... and heavily edited, so all the patterns are thrown way off but vaguely recognizable. This will be fun!

mg262
2nd December 2005, 12:49
Yes, it's called BlendFPS and its in Motion.

MOmonster
2nd December 2005, 13:03
Iīll create a function that have some more parameters and use the code of the Hq and the standard version this weekend, maybe itīs worth to wait until Monday before testing the function.

@LogicDeLuxe
It would be really nice if you could upload a small clip. I donīt have internet this weekend, but a small example would help me a lot to improve the function for your problem.
Such a scenechange detection parameter should be easy to implement, but with the source maybe I find a better solution for you. ;)

Edit:
The hthresh is used for the comparison with the next and the previous frame. If the blendvalue difference is that high, itīs detected as a blend. The lthresh is for the overall difference (the smallest of five values against the others). For the standard version this thresh is zero.
some artefacts can also be a result of the postprocessing. Try also 1 and 0.

LogicDeLuxe
2nd December 2005, 21:11
I just restored two clips without any wrong detection. Works really well. (I didn't try tweaking the threshs yet, though)

The problematic one I tried before has one difference as I can see it. It seems the clip comes from a source with 240 lines, probably the average of two NTSC fields. But as if that wasn't worse enough, the clip then was upscaled to 432 lines. Is it possible that those scaling artefacts can distract the proper scene detection? I wonder as I didn't have that problem at all on the two other clips, even though I scaled them up to PAL resolution before processing.
I'll try scaling it back to 240 lines in order to see if this helps detection. If not, I will prepare a short clip.

Anyways, it should be possible to pass separate clips for detection and processing to FixBlendIVTC_Hybrid(). The way it is now, you have to scale the clip to 576 lines which might make the detection more difficult, I guess. On the other hand, if I do the scaling afterwards, I wouldn't be able to properly interlace the 30p parts.

LogicDeLuxe
2nd December 2005, 21:24
Scaling it to 240 lines did in fact fix my detection problem. I guess separate clips for detection and processing is the right way to go.
That is, I would scale the detection clip to 240 lines and the processing clip to 576 lines.
Then things would be perfect, I think.

foxyshadis
2nd December 2005, 22:19
If you want, I can add a clip2 parameter to it really quick. It's not too hard to separate final output from blend-detection, since they're pretty much entirely separate.

LogicDeLuxe
2nd December 2005, 22:29
Sorry, my fault. The scaling didn't really fix it.
I disabled decimate(), which I usually do when previewing since it is much faster that way. It turned out that those gliches only appear when decimate() is in the chain. Also Could decimate() produce such a glitch? Strange, isn't it? Even more strange is the fact that I didn't have that problem with the other two clips at all.

I tried saving it without decimate() into a new clip. When I then just loaded that intermediate clip and decimate() it, I don't get those glitches any more. Does this make any sense to you?

LogicDeLuxe
3rd December 2005, 14:39
Maybe decimate() throws the detection algorithm out of order, thus screwing the counter variables.
At least I found a workaround without the need of an intermediate file (which gets pretty big with a huffman codec):
I just left the decimate() out of it and opend the restored clip in another avs file like this:DirectShowSource("Fixed.avs")
decimate(cycle=5,quality=0,mode=0)
AssumeFPS(25)

foxyshadis
3rd December 2005, 19:58
Anything that requests frames from a conditional function out of order (which fdecimate and tdecimate do, and apparently decimate with yours) will farge up the function. Normally decimate wouldn't but maybe in this case something causes it to.

But the second avs is very cool, I'll have to try that next time.

On a development front, I'm trying to tweak both mine and momonster's to try to get them to deal with runs of identical frames without killing the pattern. (Oh, this video is hurting. It's been edited to place slices of video on top of each other, or 30p on top of 24p w/ 2 blends, so I have to go crazy on editing or just skip big chunks...)

LogicDeLuxe
3rd December 2005, 21:10
(Oh, this video is hurting. It's been edited to place slices of video on top of each other, or 30p on top of 24p w/ 2 blends, so I have to go crazy on editing or just skip big chunks...)I just stumbled on such composed scenes as well. I also spotted 24p on top of 30p, sometimes with those blends, sometimes without blends, ie. just every 4th frame (the 24p part of it) doubled. Any chance, that could be smoothly interlaced to 50i? I guess, not. Fortunately such scenes are pretty rare in my clips, were handled like any 30p parts, and I don't have much hope that they'll get any better.

It's amazingly enough, that I didn't saw a crossfading breaking the pattern so far, which certainly would be another pain in this matter.

MOmonster
5th December 2005, 10:57
@foxyshadis & logicdeluxe

You speak about heavy sources with edits and pattern problems. The decimating could be easily tweaked with a different singleblenddetection and the clip2 parameter for bad quality sources could also be easy implemented to softing the detection clip. But I would like to have some source to test with. The modified source I work with shows perfect patterns and so on, so itīs not that comparable.
I finished the next version, wrote a readme and opened many more parameters. If useful the hybridversion can be also easily changed.
Edit: The decimating problems are normal with the evaluate enviroment, only tdecimate(mode=7) and smartdecimate works fine with such things at this moment. I use a unnecessary tweak(hue=0.25) for the dupframes. Often a resizing after the function also helps, but logicdeluxeīs idea looks nice.

Edit:
attachment removed to later post.

foxyshadis
5th December 2005, 14:31
You don't want my evil parts, I'm just going to chop up the video frames, process, and then remerge them, voila, corrected segments. (Such is the hope.)

The less evil parts I'm going to analyse more to see if I can find out what's pathological and what's worth posting. I do think that it gets confused when 4 identical frames occur, then of course it looks like a blend. It's not common but when it happens things go bad. I'm still trying to figure out why one segment that looks like it should be easy to recognize isn't, I'll probably post it for you too.

Would using a halfsized or denoised clip for blend-detection work better, you think? I know pre-filtering didn't work for me before, but it's changed quite a bit in yours. I haven't tried yet, but I'll probably give it a shot.

By the way, you are awesome.

MOmonster
6th December 2005, 12:55
@foxyshadis
Thanks :)
I still would like to see the sources. Mostly I learn more from bad sources.
For many sources the preprocessing has a bad effect, only for some bad quality samples it can help. Also, it has to be stupid preprocessing (resizing or simple bluring, bilinear mostly helps a bit). Deblocking and so on mostly make the detection worse than before. :(

Edit:
To tweak my function for your sources you should play a little bit with this parameter:
YV12LUTxy(unblend1, unblend2, yexpr="x y - 2 ^ 6 /", uexpr="x", vexpr="x") It has a big influence on the blenddetection. For a working singleblenddetection it has to be the same for blenddiffm.
I think Iīll open this parameter in the next version. Maybe also a motionthreshold is useful for you, because of the many still scenes. Maybe I`ll find the time for this the next days. ;)

MOmonster
12th December 2005, 12:12
So, the next version is ready. New is the mthresh and sprotect. Maybe it helps in some sources. :)

foxyshadis
12th December 2005, 13:20
I'm sorry I haven't been testing as much as I wanted to, I've been dragged into and involving myself in too many projects lately. ^^; It was better when I played with it, but I haven't had time to make real encodes or test cases.

I think I'd definitely better replace mine in front with yours, it's so much better now. Aww, I feel bad that my first really important filter is useless now. :p

Is this integrated into C_Deblend at all, or are they still entirely separate?

MOmonster
13th December 2005, 11:24
FixblendIVTC and Cdeblend are totally different functions. I donīt think that this will ever get a part of Cdeblend.
Sorry. that you think your function is useless now. You give me some ideas with it, especially for so postprocessing.
So, thanks you very much. ;)

Anonymouses
14th December 2005, 23:07
I have this really nasty clip that I've been trying to use the FixBlendIVTC but I'm not getting any decent results. I'm not sure if it's just too screwed up to fix or if I'm just doing something wrong. The clip is here (http://rapidshare.de/files/7585928/Patlabor.m2v.html). Any help is appreciated.

MOmonster
15th December 2005, 09:02
I have this really nasty clip that I've been trying to use the FixBlendIVTC but I'm not getting any decent results. I'm not sure if it's just too screwed up to fix or if I'm just doing something wrong.
Iīm not able to have a closer look on it (only vlc here), but this is no source for these doubleblendremovers here. The blendweights are different. So itīs more a source for Cdeblend or Cdeblend_mod. Tomorrow I can have a closer look on it and give you more informations.

LogicDeLuxe
15th December 2005, 22:47
I have this really nasty clipThis here is for blended progressive video. Your's is interlaced. You can try restore24 on it.

foxyshadis
16th December 2005, 07:46
I had time to pick through the next bebop video (sorry about overusing the show...) and found a few interesting segments, numbered according to how I split it up.

s9 (http://foxyshadis.slightlydark.com/random/be_blendtest_s9.avi) and s14 (http://foxyshadis.slightlydark.com/random/be_blendtest_s14.avi) show pulsing artifacts, I have no idea what might cause that.

s19 (http://foxyshadis.slightlydark.com/random/be_blendtest_s19.avi) shows a few artifacts, notably frames 189, 308, and 576. It only seems to catch about half the blends, as well; they're all on obvious edits, so if you don't want to deal with that I'm cool. (It took some editing but I restored some of the patterns myself and it works a lot better.)

Adding removeblend after helps catch some straggling single-blends though.

MOmonster
16th December 2005, 18:04
I have this really nasty clip that I've been trying to use the FixBlendIVTC but I'm not getting any decent results. I'm not sure if it's just too screwed up to fix or if I'm just doing something wrong.
Oh yes, nasty and screwed up are the right words. Another totaly overblended anime. I have modified Cdeblend a little bit for this. Itīs still not very good, but these sources arenīt worth much more time working (too bad and too seldom). Have a look here (http://forum.doom9.org/showthread.php?p=751063#post751063).

MOmonster
20th December 2005, 09:51
@foxyshadis
Yesterday I took a look at the s14 sample (couldnīt find the others on my pc, sorry). What do you mean, with pulsing. I get a wrong detection and saw cruel artefacts (Iīll fix it in the next version), but get no pulsing (maybe because the wrong detection). Show pp=0 or pp=1 also this pulsing. Iīll try to improve the singleblenddetection in the next version. Maybe a motioninfluence (similar to Cdeblend) can also tweak the blenddetection. Iīll see, but give me some time (Iīm ill :( ). ;)

foxyshadis
20th December 2005, 11:46
Oh, by pulsing I just meant the artifacts kept showing up in a cycle.

Anyway, I made a couple of mods to your function, let me know what you think:


global lastframe = -1000
global frameskip = false
global diffclipf = interleave(source.trim(1,0),unblend2.trim(1,0))
global revdiffclipf = interleave(unblend1.trim(2,0),unblend2.trim(2,0))


d3=FrameEvaluate(d4, " blenddiff1 = max <= 0 ? 0.01 : (fdetect == false ? AverageLuma(blenddiffm.trim(1,0)) : CFrameDiff(diffclip,prevf=false))
revdiff2 = fdetect == false ? AverageLuma(revdiffm.trim(2,0)) : CFrameDiff(revdiffclip,prevf=false)
revtemp = frameskip ? 1.0 : revdiff0")

d2=FrameEvaluate(d3, " blenddiff0 = frameskip ? 1.0 : blenddiff1
revdiff1 = frameskip ? 1.0 : revdiff2
revdiffb = frameskip ? 1.0 : revtemp
global diffclip = diffclipf.trim(current_frame,0)
global revdiffclip = revdiffclipf.trim(current_frame,0)")

d1=FrameEvaluate(d2, " global blenddiffb = frameskip ? 1.0 : blenddiff0
global revdiff0 = frameskip ? 1.0 : revdiff1
global revdiffbb = frameskip ? 1.0 : revdiffb
lastframe = current_frame")
d0=FrameEvaluate(d1, "frameskip = lastframe != current_frame-1")
return(d0)

The frameskip is there to prevent random access (such as joining normal and unblended sections of clip) from playing total havok with it, it resets everything if it detects it. Not very bright but it works. And proves that adding removeblend after it screws things up.... I'll have to find a good way to work that.

CFrameDiff (from TIVTC) was an attempt to fix the artifacts, it didn't do that, but it does seem to give better detection of not-blends (ie, actual 30p). The numbers it returns are normalized the same as LumaDiff. Probably not worth adding a new dependancy, but I thought you'd be interested.

I also tweaked the counters, but my mods only tended to make things worse, so I'll leave any of that up to you. :p

MOmonster
21st December 2005, 11:12
A nice idea, really. :D
I donīt know, if Iīll add it to the next version, just because the next version will have a lot of significant changes (hoply improvments), but I keep it in mind.

MOmonster
19th January 2006, 08:50
Yesterday I got the time to finish version 0.6. There are many changes like:
- different, more useful parameters
- blenddetection with motioninfluence
- variable postprocessing mode
- better motionthresholding
- different, faster singleblenddetection

I think about much more improvments especially on the postprocessing, but there are other projects more important at the moment and less time for all the things, so donīt wait for the next release.;)

foxyshadis
25th January 2006, 13:29
Thanks for taking the time! It must have been a lot of work improving it that much. It took me a while to puzzle it all out (there also seems to be a lot of dead code... most of the scriptclip as well as frdiff0/frdiffb/frtemp never actually getting assigned to anything but themselves, was that intentional? they're certainly used often enough.), and had to wait for a bug in another filter to be fixed, but I think I kind of got the hang of most of it.

I've made a few modifications, if you'd like to take a look and comment you're welcome to. For one, I converted to masktools 2 (all of my stuff is, faster plus I occasionally find bugs for manao =p), as well as a couple of other optimizations. I also took out some unused code, added my "frameskip" test. Also created a new is12p test, because I found that no sbf caused bad artifacts and sbf>.7 stopped them but caused many missed blends with my sources. mil helps but not always. It tests two frames on either side and if they're the same, triples the SBF. Also included is optional use of CFrameDiff instead of YDiffToNext, with parameter cdiff, which makes single-blend even more reliable, but doesn't affect double-blend detection yet. I modified the readme accordingly. I'm thinking of changing the double-blend too, but I haven't yet had any serious inspiration. ^.~ I do have a few ideas for postprocessing I'll look into though.

Of course that means a few more dependancies: Avisynth 2.56a+, Masktools 1.5x, Masktools 2a22+, Average, Removegrain (plus optional 1.0a optimizations, maybe I should just add them in directly? too bad there's no way to test filter version), and TIVTC RC1 optional.

I also talked to tritical, and he may change TDecimate for in-order access soon, so I can use it directly for my purposes (too many 24/30 hybrid clips), plus it's much faster now.

MOmonster
26th January 2006, 11:24
Really nice modification.;)
The last weeks I had really less freetime, so I only concentrated on corechanges.
I miss the FitY2UV() in version 2, but this changed with the last update. Through I donīt have a good feeling using both masktools version in one script, because version 2 has no YV12subtract anymore. Maybe the simple differencing with mt_lutxy wonīt cost speed (I have to test it). So or so a really useful modification, many improvments.:D Iīm interested in your idea for a better blenddetection. The doubleblenddetection can be tweaked easy with a difflimitation in the lutprocessing. If I find some other ideas Iīll post you.

Edit: frtemp and frdiff1 are just there to get frdiff0 and frdiffb, used for the singleblenddetection.
Edit2: Yes, after some more testing, the variable postprocessing wasnīt the goal, it was a try.
I still donīt worked with the inofficial last removegrain version. Is there somewhere a documentation around?

MOmonster
9th February 2006, 10:27
New version (FixBlendIVTC v 0.8a) is ready.:D
And it clearly superior all my previous versions.

Changes are:
- improved speed (faster double- and singleblenddetection, faster postprocessing)
- new more accurate doubleblenddetection
- different singleblenddetection (12fps detection)
- easier use and less global variables
- new postprocessing (sharper and faster -> post 2 and 5)
- use mt_masktools instead of the older masktools version

Needed filters are included in the zip. RemovegrainS.dll works on all my tested systems, but of course for a better speed you can use the faster versions.
I wasnīt satisfied with the results of v0.7, but this version is much better. You should update your last version.

@foxyshadis
There shouldnīt be much scope for useful modifications. This time I also gone a little bit more into detail, but of course another modification would be more than appreciated.
A better 30p treating iīll maybe add next version.

Edit: I packed a wrong plugin into the zip. Is changed now.

foxyshadis
9th February 2006, 17:53
Wow, nice. I see in your detection you were going down a similar road I was, but I like your results better. =D I still have a feeling that AverageLuma is the weakest link. YPlaneMinMaxDifference is only slightly better. That's why I've replaced it with CFrameDiff in different ways each time, and always improved its functionality. (It gives you the highest averageluma out of all 8x8 blocks.) If only it had the ability to compare against a second clip I wouldn't have to hack it in, which is why I've toyed with writing a filter consisting of nothing but Dup's mmx 8x8 difference function.

Does that interest you at all?

MOmonster
10th February 2006, 09:54
Oh, Iīm really interested in this idea. Theoretical a matrix wise operation should give better results than the simple pixel operations without regard to the other values.
But if this will practical tweak the detection, I donīt know. Bobbing artefacts and so on can have a bad effect on this methode, more than on the simple pixel operation. Weīll see.
So or so, I think such a filter would be of much use also for different projects.
Keep on your good work. ;)

jmac698
16th February 2006, 19:28
Hello,
looking forward to trying your script. Read some of the thread, seems very interesting and exactly what I'm looking for.
This is a (probably, as BBC) pal-land source on ntsc. Possibly film -> pal -> ntsc.
Anyhow, it goes like this:
progressive, progressive, top field blending with previous field, top field blended with previous field, bottom field blended with previous field, bottom field blended with previous field, and repeat.
Just to be clear, when the top field is blended, the bottom field is fine. Is the blending with the last other field or other same field? I have to look for edges jumping up and down, I will have to look again.

So the model and arithmetic in your terms, with x1 x2 being top/bot fields of frame x:
A1=u1
A2=u2
B1=v1
B2=v2
C1=(w1+v1)/2
C2=w2
D1=(x1+w1)/2
D2=x2
E1=y1
E2=(y2+x2)/2
F1=z1
F2=(z2+y2)/2

So I need to do u=A1&A2,v=B1&B2,w=(C1-B1)*2&C2,x=(D1-x1')*2&D2,y=E1&(E2-D2)*2,
z=F1&(F2-y2')*2

You can see some of the differences are twice removed, which will probably look terrible.
I would like to suggest generalized parameters as (a,b,c,d,e,f...)
which could take up to cycle6 (12 parameters) or even 25, and each number is the number of fields back this field is blended with. So my case would be:
(0,0,0,0,-2,0,-2,0,0,-2,0,-2). Or maybe the -2 are all -1. You would also need blend ratio, threshold parameters, and anything else. Of course, it's best to autodetect blends, but a hint could form a weighting system.

Even more general is a set number of blend types, in my case there is either none or -2 blending. If there were a deblend function deblend(prevfield,weight,thresh) with the result of currfield'=(currfield-(1-weight)*prevfield)*1/weight if diff>thresh else currfield'=currfield. Diff could be the squared difference as discussed. By calling this function with different weights you could give a hint to the function. But it would also be good to get a value for diff back so you can adapt at a higher level. To be really good you would need to supply also some interpolation fields for better recovery, but then it gets complicated.
Is this making any sense? :)
I think we need tools that a user can determine their cycle type, the blend ratio, and then know what to put in some parameters.

I'll try your script and see what happens. Thanks for all the work!

[edit] one other problem, on non-stable sources like VCR the fields could be relatively shifted a few pixels, this would leave ghosted edges only. And of course mpeg artifacts and noise too :(

foxyshadis
16th February 2006, 21:44
It's not really designed for 3+2 blend pattern, anymore, I use it on crazily edited blended shows with no pattern at all with fair success (course, nothing's perfect, but it's close). And that's with mpeg artifacts and all. With a VCR's artifacts a preliminary reconstruction would be a better method, I've seen a few ideas here on fixing it.

You should probably use "separatefields().selecteven().FixBlendIVTC()" and selectodd, then reweave. Since you can't run two copies in parallel, you'd have to put each in its own avs, then a third avs with "Interleave(avisource("even.avs"),avisource("odd.avs"))". At least, that sounds like the cleanest solution with the current script.

Momonster, in testing I found a few tweaks that helped a tiny bit, or not at all, but this one made a noticeable difference by reducing the effect of compression noise:


global rev_diff = mt_lutxy(f_diff.trim(1,0), f_plus, yexpr="x y - 2 ^ x 0.3 ^ /", uexpr="x", vexpr="x")
\ .mt_inpand().DeGrainMedian(limitY=20,limitUV=0,mode=0)
global single = mt_lut(f_diff, yexpr="x 128 - abs 4 < 0 x 128 - 2 ^ ?", uexpr="x", vexpr="x")
\ .mt_inpand().DeGrainMedian(limitY=20,limitUV=0,mode=0)

MOmonster
17th February 2006, 02:13
@jmac698
Could you please upload a small sample? It would be nice for me to have a look on it.
The idea for version 0.9 is allready in my head, but of course all ideas, problems and samples are welcome.;)

@foxyshadis
Yes something similar is also planned for v 0.9, but only optional, because it kills fine movements and give worse results for good sources. But for anime, yes really good. I tried it and it seems to work just a little bit better. maybe a better alternative to the clip2 option. Weīll see. The next version should work better with low motion scenes, but Iīll need some time, because other things.

foxyshadis
17th February 2006, 02:29
You're right, of course. All of my samples are anime, except two I made up myself, but I have no idea if those are representative of "clean" sources at all. Thanks for the clarification. You're the brains behind the operation after all, I'm just a tweaker. :p

Edit: Howabout replacing single-blend with an "anime" bool? Then you can have difference optimized defaults for film vs. cartoons.

jmac698
19th February 2006, 23:25
Hello,
as requested,
http://rapidshare.de/files/13662957/sample.avi.html (25 frames, xvid, 450kb)

I wasn't able to get good results with your script yet. Bit of a newbie as scripting.
I did use something which works well, but I would still like to try the deblend idea.

AVISource("C:\sample.avi")
TDeint(Mode=1,order=1)#or LeakKernelBob(Order=1)
RePAL(quality=3)

Anyhow, if you get a chance to try my sample I would be very interested in the script you used. I hope this can help you tweak your future release. Thanks.

jmac698
20th February 2006, 01:13
success!
MOmonster:
even.avs:
Import("C:\Program Files\AviSynth 2.5\plugins\FixBlendIVTC.avs")
AVISource("c:\sample.avi")
separatefields().selecteven().FixBlendIVTC(sbd=false)
#separatefields().selecteven()

odd.avs:
Import("C:\Program Files\AviSynth 2.5\plugins\FixBlendIVTC.avs")
AVISource("c:\sample.avi")
separatefields().selectodd().FixBlendIVTC()

deblend.avs:
interleave(avisource("even.avs"),avisource("odd.avs"))
assumefieldbased()
AssumeTFF()
weave()

looking at even.avs by itself, without FixBlend (uncomment line),
I see 10,11,16,17,22,23 fields are blended (of 0-25). Ie, field 10 is blended with field 9 (of only even fields).
With your function, only 22,23 are blended. I'm guessing you need some frames ahead to perform your function? Or there is some lag, or something.
So, it seems to remove all blends quite well, and they are close to 50%.
But when I put them together, there is combing.
Which frame do you output when it is blended? And it seems some frames are decimated? I think it would be easier for me to have duplicates, that may be why I can't weave it back together.
Thanks for your help, this is very close...

MOmonster
22nd February 2006, 12:10
@jmac698
FixBlendIVTC is not the right function for you, what you need is restore24 or Cdeblend.
Your source is a pal->ntsc norm conversion. There are all clear fields you need for a good restoring I think. We just have to pick up the clear fields. Cdeblend works fine for me with this settigns:
leakkernelbob(order=1,sharp=false,twoway=true,threshold=4)

a = last.bilinearresize(480,352)

Cdeblend(dmode=1, omode=3, dthresh=70, perc=2, thresh=111, clip2=a)
Of course you can use tdeint for better bobbing results. After this you have to decimate the source back to 25fps with smartdecimate() or changefps() + decimate() (with other decimators you can sometimes get strange results).
I didnīt test restore24, but it should also work for your source.

The blendweights are near to 50% every pattern end. But this idea can only used for this one of five fields and I donīt think that this will higher the quality. But Iīll test it this weekend.

Edit: A longer sample would be nice, yes.

jmac698
22nd February 2006, 17:14
Mo,
New sample http://rapidshare.de/files/13872642/sample1.avi.html 1mb xvid
from your own postings, I got these ideas:

tdeint(mode=1) #bobbing to double rate
Cdeblend() #tweak higher thresh and include clip2 is useful
smartdecimate() #or changefps() decimate()

leakkernelbob(order=1,sharp=false,twoway=true,threshold=4)
a = last.bilinearresize(480,352) #or tdeint
#cdeblend replaces blended frames
Cdeblend(dmode=1, omode=3, dthresh=70, perc=2, thresh=111, clip2=a)
smartdecimate() #or changefps() decimate()

#order TFF,guess bottom field (unused), bob, kernel deint, tryweave means use clean frames
TDeint(order=1,field=1,mode=1,type=2,tryweave=true)
RePal(quality=3) #discard blended frames
AssumeFPS(25,1,true) #change playback speed to 25/1, audio rate to match
SSRC(48000) #resample back to sane samplerate

I don't know why you had field=1? I don't quite understand the cdeblend/smart or repal operations.

If I wanted to go all the way to do a full 24p restore, is there a function smart enough to find that 1 repeated frame in 25 despite editing? Or will I sometimes lose a random frame to keep up the sync?
It seems to be that editing in pal-format could ruin the 24p...

How do you use restore24()?

MOmonster
21st December 2006, 09:04
I took up time for FixBlendIVTC v0.9, but yesterday I decided to finish my work. I included it to the R_pack, so you can download it here (http://forum.doom9.org/showthread.php?t=95924).
changes:
- faster and saver detection
- completely rewritten code
- new, faster postprocessing modes