Log in

View Full Version : Generate broken frames from neighbour frames using MVFlow


Pages : [1] 2

absence
13th February 2010, 01:21
I have some video digitized from analogue tape. Due to bad tape occational frames are full of garbage/noise. Is it possible to use MVTools to estimate motion of nearby frames, and MVFlow to calculate a new frame that I can replaced a broken one with? How would such a script look? (Assume that I'll deinterlace the video first, since I imagine interlaced video will only cause trouble.) I've only used MVFlow with complete videos and have limited understanding of how to work on just a few frames in Avisynth. :)

wonkey_monkey
13th February 2010, 01:54
This is taken straight from the MVTools 2 doc page:


AVISource("c:\test.avi") # or MPEG2Source, DirectShowSource, some previous filter, etc
super = MSuper()
backward_vectors = MAnalyse(super, isb = true, delta=2)
forward_vectors = MAnalyse(super, isb = false, delta=2)
inter = MFlowInter(super, backward_vectors, forward_vectors, time=50, ml=70)
# Assume bad frames are 50 and 60
trim(0,49) ++ inter.trim(49,-1) \
++ trim(51,59) ++ inter.trim(59,-1) ++ trim(61,0)


If you have to use MVTools 1, it's this:


backward_vectors = source.MVAnalyse(isb = true, truemotion=true, pel=2, delta=2, idx=1)
forward_vectors = source.MVAnalyse(isb = false, truemotion=true, pel=2, delta=2, idx=1)
inter = source.MVFlowInter(backward_vectors, forward_vectors, time=50, ml=70, idx=1)
# Assume bad frames are 50 and 60
source.trim(0,49) ++ inter.trim(49,-1) \
++ source.trim(51,59) ++ inter.trim(59,-1) ++ source.trim(61,0)


:readfaq:

absence
14th February 2010, 16:34
This is taken straight from the MVTools 2 doc page:
Oh, you're right! And I've even visited that page... :P Sorry for the obvious question, and thanks for pointing it out. :)

wonkey_monkey
14th February 2010, 18:15
No worries, it's not very obvious - I often wish the MVTools pages were a little more navigable. I only went there to look at the individual filters myself, and was lucky to spot the examples.

David

2Bdecided
16th February 2010, 08:50
Didn't someone turn this into a simple function? (i.e. just provide clip and bad frame numbers) - or am I dreaming?!

Cheers,
David.

absence
2nd March 2010, 15:53
Didn't someone turn this into a simple function? (i.e. just provide clip and bad frame numbers) - or am I dreaming?!
No idea, but that would be nice. :)

I have another question too: What if there are two consecutive broken frames? I thought it would be logical to increase delta by 1, like this:

super = src.MSuper
bvec = super.MAnalyse(isb=true, delta=3)
fvec = super.MAnalyse(isb=false, delta=3)
inter = src.MFlowInter(super, bvec, fvec, time=50, ml=70)
src.trim(0,10264) ++ inter.trim(10264,-2) ++ src.trim(10267,0)

However, this only fixes frame 10265. 10266 is still broken, but looks different than the original. What do I need to write to get this right? And, why? :) (so I can understand how it works and help myself in the future)

MatLz
2nd March 2010, 17:26
function rbf(clip rbfin,int ftr)
{
rbfin
sup=msuper()
bv=manalyse(sup,isb=true,delta=2)
fv=manalyse(sup,isb=false,delta=2)
inter=mflowinter(sup,bv,fv,time=50,ml=70)
trim(0,ftr-1)++inter.trim(ftr-1,-1)++trim(ftr+1,0)
}I changed the time value, I find it more natural in motion.
When I will have more time, I will modify it because there are exeptions (start or end of scenes with or without motion/scrolling...)
Edit:I'm wrong, it is my insertion for missing function where the time value is 33.

pbristow
2nd March 2010, 20:34
Hmmm... Thinking about Absence's query about how to regenerate 2 consecutive frames, I tried to unpick what the original example does... At first I thought I'd found an error, then realised I was getting confused because of the way manalyse is used twice to get both forward and backward vectors, both of which have to be passed to MFlowInter, even though for a simple linear interpolation only one set of vectors is needed. (I'd love to know what MFlowInter actually does with the extra vectors, if anything! Perhaps they're only needed for when "time" is negative (e.g. -50% instead of +50%)? )

In the case of recovering one bad frame between two good ones, the value of delta is two, because we're comparing a frame just before the glitch with the one two frames later. The target frame N is created by interpolating a point halfway between N-1 and N+1 (using time=50 - It's a percentage). A stream of candidate frames is created by interpolating the source clip 50% forward along the vectors, and then frame N of the source is replaced with frame N-1 of this stream of replacement candidates.

Now let's move on to the problem of recovering two consecutive frames, N and O, where O=N+1, from good frames N-1 (aka M) and N+2 (aka P):

M N O P
N-1 N N+1 N+2
good bad bad good

The data we want to use for frame N is an interpolation 33.3% of the way from M to P. The data we want for frame O (= N+1) is an interpolation 66.7% of the way from M to P.


Script, with explanatory comments:


function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1 will be replaced.

Source
Sup=msuper()

bv=manalyse(Sup, isb=true, delta=3)
# Looks 3 frames ahead and calculates vectors backward
# to present frame.
fv=manalyse(Sup, isb=false, delta=3)
# Looks 3 frames behind and calculates vectors forward
# to present frame.

CandidatesForN = mflowinter(sup, bv, fv, time=33.3, ml=70)
# Produces a stream of frames interpolated 1 frame
# ahead of the source, based on data from 0 and 3 frames
# ahead of the source. To find the correct candidate for
# replacing frame N of the source, we want the N-1th
# frame of this stream. ( (N-1) + 1 = N )

CandidatesForO = mflowinter(sup, bv, fv, time=66.7, ml=70)
# Produces a stream of frames interpolated 2 frames
# ahead of the source, based on data from 0 and 3 frames
# ahead of the source. To find the correct candidate for
# replacing frame N+1 of the source, we want the N-1th
# frame of *this* stream. ( (N-1) + 2 = (N+1) )

Source.trim(0,FrameN-1) ++ CandidatesForN.trim(N-1,-1) \
++ CandidatesForO.trim(N-1,-1) ++ Source.trim(FrameN+2,0)
}


Howzatt? :)

Gavino
3rd March 2010, 11:02
Howzatt? :)
Fine, apart from the typos in the last line where you have written 'FrameN' instead of 'N'. ;)

absence
3rd March 2010, 23:35
Howzatt? :)
Perfect, thanks! :)

New problems just keep appearing though: I'm trying to clean up video from analogue tape that is slightly damaged in some places, causing broken scanlines to "roll" down the picture over time (e.g. in one frame scanlines 10-15 are broken, in the next 12-17 are broken, in the next 14-19, and so on). The entire sequence is too long to throw away and interpolate, and if I try to interpolate a shorter part of it, MVTools detects the broken scanlines as motion and puts them back in. Is this possible to handle?

pbristow
14th March 2010, 15:52
I can suggest an approach for that, but getting it to work will probably be a lot of work. It's a useful approach for all sorts of tricky problems, and it goes like this:

1. Work out how to detect when, and where, the problem is occuring.
(In this case:
- Are the broken scanlines partcularly bright, compared to the rest of the frame?
- One thing that should distinguish them is that they're horizontal, so some sort of horizontal edge-detection might do the trick. )
Using this you can create a mask to switch your "Problem solving magic" on and off in the right places.

2. Create a copy of the source where the effects of the problem are somehow reduced or obscured, so that they won't confuse your main processing. (In this case, motion estimation. E.g., use the trick of a blurred pre-filtered clip (as shown in the MVTools documentation), but with a lot more blurring keyed in (using the mask from step 1) wherever the break-up is detected on the original.)

3. Apply your main processing.
- i.e., use MVtools to create motion-compensated copies, from which you can patch-in replacement picture detail.
As to *how* to use MVTools, I would suggest using MDegrain3, with a large block size (16), "truemotion" on, and lots of overlap (8). As long as the blocksize is significantly bigger than the width of the damaged area, then the motion estimator has a better chance of locking onto real picture detail, rather than the movement of the problem. You might also gets some benefit from pushing he lambda higher than normal (thereby telling the algorithm "if one block seems to be behaving weirdly compared to its neighbours, then trust the neighbours, not the odd one!")

4. Look at the result, compare it with the original, and decide whether to use it as it is or refine it further (e.g. by keying in the MVDegrain output only where the problem was detected, using the mask from (1). You might get a more uniform and pleasing result, though, if your use it over the whole frame... I'm finding MVDegrain really useful for averaging out all sorts of temporary glitches and fluctuations, not just "noise".)

Good luck! :)

pirej
17th March 2010, 16:11
deleted by me, pirej

Alex_ander
17th March 2010, 17:28
You can apply MFlowFPS (to double framerate) to frames created from healthy fields only (either with NNEDI2 or simply by removing each other frame after separatefields.assumeframebased with further resizing), then re-interlace. Or simply leave it progressive (without using MFlowFPS) if your material give artifacts after MFlowFPS.

um3k
17th March 2010, 18:55
Is this what you're looking for?

##Insert MVFlow stuff here
Interleave(SelectEven(mvflowoutput), SelectOdd(premvflowclip))

Switch selecteven and selectodd if it gives the wrong frames.

pirej
17th March 2010, 21:28
Tried to do it me self, but.. no luck(knowledge) :)
i'm using a script like this
AVISource("D:\test.avi")
AssumeTFF()
separatefields()

super = MSuper()
backward_vectors = MAnalyse(super, isb = true, delta=2)
forward_vectors = MAnalyse(super, isb = false, delta=2)
inter = MFlowInter(super, backward_vectors, forward_vectors, time=50, ml=70)

trim(0,410) ++ inter.trim(410,-1) \
++ trim(412,412) ++ inter.trim(412,-1) \
++ trim(414,414) ++ inter.trim(414,-1) \
++ trim(416,416) ++ inter.trim(416,-1) ++ trim(418,0)


And it's doing a great job, but its not just couple of frames like in the example, its most part of the video..
So, how to adapt this script so that it does it's job (automatically) on every second field???
I tried MFlowFPS to double framerate from the upperfields, but it gives me a lot of artifact's.
And i couldn't follow um3k's instruction.. excuse me if i'm bordering you all.
By.

Alex_ander
17th March 2010, 22:08
AVISource("D:\test.avi")
AssumeTFF()
SeparateFields()
SelectEven()# or Odd to keep right fields
AssumeFrameBased()
LanczosResize(720,576)# if PAL
#__end__# enable this line for progressive output if you get artifacts
super = MSuper(pel=2)
backward_vec = MAnalyse(super, isb = true)
forward_vec = MAnalyse(super, isb = false)
MFlowFps(super, backward_vec, forward_vec, num=50, den=1, ml=100)# PAL, for NTSC num=60000, den=1001
AssumeTFF()
SeparateFields()
SelectEvery(4,0,3)
Weave()

It even appeared to work with my random NTSC test video and converted it to true PAL.

pirej
18th March 2010, 00:30
Thank you Alex_ander, but let me tell you all how "smart" i am.. :(
In meanwhile, i cleaned the (2)head's on my old vcr, and i did some scrubbing.. with a piece of white paper and 70% alcohol, waited for some 1/2 hour, and i did another test capture.
And guess what.. most of the error's disappeared, and there is some more color and... it's much better.


p.s. this is second time im cleaning the vcr-heads, but now i pressed the paper little harder while cleaning...

pirej
18th October 2010, 11:53
Hi, i was using pbristow's function example for "RecoverFramePair", and i did modified it to get another function for recovering ONE frame just to make it simple, and more practical for me.
So the script is something liek this:
function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1(O) will be replaced.

Source
Sup=msuper()
bv=manalyse(Sup, isb=true, delta=3)
fv=manalyse(Sup, isb=false, delta=3)
CandidatesForN = mflowinter(sup, bv, fv, time=33.3, ml=100)
CandidatesForO = mflowinter(sup, bv, fv, time=66.7, ml=100)

Source.trim(0,N-1) ++ CandidatesForN.trim(N-1,-1) \
++ CandidatesForO.trim(N-1,-1) ++ Source.trim(N+2,0)
}

function RecoverOneFrame(clip Source, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.
Source
Sup=msuper()
bv=manalyse(Sup, isb=true, delta=3)
fv=manalyse(Sup, isb=false, delta=3)
CandidatesForN = mflowinter(sup, bv, fv, time=50.0, ml=100)

Source.trim(0,N-1) ++ CandidatesForN.trim(N-1,-1) ++ Source.trim(N+1,0)

}

RecoverOneFrame(7)
RecoverFramePair(26)
RecoverOneFrame(30)
RecoverFramePair(50)

So, i'm using "manalyse" twice in the same script.. is it making any sense?
Does it slow down the script?
Does it generate some kind of problems?
I did not try to encode using the script yet, but the preview in avsp looks ok.
By.

Didée
18th October 2010, 12:17
It is very inefficient to make the MVTools-stuff inside such a function. Not a problem when you have to fix only a few random frames in a stream. But imagine a longer source, and there are, say, 100 frames to fix. Technically, you need one superclip, and one pair of vectorclips. But with these functions, the script would create one hundred superclips, and one hundred pairs of vectorclips.

In this scenario, the script most likely will crash because it runs out of memory.

A memory-efficient way is to do the MVTools-stuff one time at the top level, and use the functions only for replacing.

function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1(O) will be replaced.

Source.trim(0,N-1) ++ CandidatesForN.trim(N-1,-1) \
++ CandidatesForO.trim(N-1,-1) ++ Source.trim(N+2,0)
}

function RecoverOneFrame(clip Source, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

Source.trim(0,N-1) ++ CandidatesForC.trim(N-1,-1) ++ Source.trim(N+1,0)
}

Source

Sup = msuper()
bv = manalyse(Sup, isb=true, delta=3)
fv = manalyse(Sup, isb=false, delta=3)
global CandidatesForN = mflowinter(sup, bv, fv, time=33.3, ml=100)
global CandidatesForO = mflowinter(sup, bv, fv, time=66.7, ml=100)
global CandidatesForC = mflowinter(sup, bv, fv, time=50.0, ml=100)

RecoverOneFrame(7)
RecoverFramePair(26)
RecoverOneFrame(30)
RecoverFramePair(50)

(Yes, usage of global variables is a bit hack-ish ... it would be more sane to hand the CandidateX clips as arguments.)

pirej
18th October 2010, 13:25
Thanks Didée, i was thinking of doing it that(your's) way, but i didn't know how-to.
Now, with your script i get error for the "source", like (i don't know what "source" means) if i live the script as is, or (invalid arguments to function "msuper") if i write source=avisource(...)
It only "works" if i feed it with source.avs as source.. like source=import("C:\source.avs"), and then it doesent work as it should, i.e. the source.avs is avi.separatedfields and the script preview gives me interlaced-full resolution clip... ???

Source
Sup = msuper()
bv = manalyse(Sup, isb=true, delta=3)
fv = manalyse(Sup, isb=false, delta=3)
global CandidatesForN = mflowinter(sup, bv, fv, time=33.3, ml=100)
global CandidatesForO = mflowinter(sup, bv, fv, time=66.7, ml=100)
global CandidatesForC = mflowinter(sup, bv, fv, time=50.0, ml=100)

I dont have this problem with my version of the script...?!??

Didée
18th October 2010, 13:39
Issuing basic Avisynth syntax/grammar. ;)

WhateverSourceFilter("thesource.ext")

Source = last

Sup = msuper()
bv = manalyse(Sup, isb=true, delta=3)
fv = manalyse(Sup, isb=false, delta=3)

[..etc..]

Or to make everything ultimately explicit:

source = WhateverSourceFilter("thesource.ext")

Sup = source.msuper()
bv = manalyse(Sup, isb=true, delta=3)
fv = manalyse(Sup, isb=false, delta=3)

[..etc..]

source = source.RecoverOneFrame(7)
source = source.RecoverFramePair(26)
source = source.RecoverOneFrame(30)
source = source.RecoverFramePair(50)

pirej
18th October 2010, 14:00
Well.. thanks for the basic Avisynth syntax/grammar :)
Anyway.. Source = last worked, thanks.

Jenyok
28th November 2011, 06:13
Didee
Are you correct in Code, see below ?
.

function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1(O) will be replaced.

Source.trim(0,N-1) ++ CandidatesForN.trim(N-1,-1) ++ CandidatesForO.trim(N-1,-1) ++ Source.trim(N+2,0)
}

function RecoverOneFrame(clip Source, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

Source.trim(0,N-1) ++ CandidatesForC.trim(N-1,-1) ++ Source.trim(N+1,0)
}

.
or maybe Code else
.

function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1(O) will be replaced.

Source.trim(0,N-1) ++ CandidatesForN.trim(N,-1) ++ CandidatesForO.trim(N+1,-1) ++ Source.trim(N+2,0)
}

function RecoverOneFrame(clip Source, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

Source.trim(0,N-1) ++ CandidatesForC.trim(N,-1) ++ Source.trim(N+1,0)
}

.
Wait answer from you...

Gavino
28th November 2011, 10:58
Are you correct in Code, see below ?
The original code is correct.
The 'candidate' clips are produced by MFlowInter and frame N-1 is the interpolation between the original N-1 and N+1 or N+2 to give the replacement frame N or N+1.

But actually there is a bug here:
Sup = msuper()
bv = manalyse(Sup, isb=true, delta=3)
fv = manalyse(Sup, isb=false, delta=3)
global CandidatesForN = mflowinter(sup, bv, fv, time=33.3, ml=100)
global CandidatesForO = mflowinter(sup, bv, fv, time=66.7, ml=100)
global CandidatesForC = mflowinter(sup, bv, fv, time=50.0, ml=100)
The CandidatesforC should be done using vectors with a delta of 2, not 3.

Gavino
28th November 2011, 20:16
Another problem with this code (also in original by pirej) is that the functions don't work for N=1 (ie when replacing frame 1 by interpolating between frame 0 and frame 2 or 3).
function RecoverFramePair(clip Source, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N+1(O) will be replaced.

Source.trim(0,N-1) ++ CandidatesForN.trim(N-1,-1) \
++ CandidatesForO.trim(N-1,-1) ++ Source.trim(N+2,0)
}
Because of the special meaning of 0 as the 2nd argument to Trim, this will give the wrong result when N=1.
It should be written instead as Source.Trim(0, -N), and similarly in RecoverOneFrame.

(See stickboy's classic Caveats of using Trim in functions.)

Jenyok
30th November 2011, 13:58
I wrote some restore bad frame functions with MFlowInter with following parameters (big number functions - 10)
.
delta=11 # 10 frames
time=9.09
.
Also I wrote Backdoor restore functions.
All functions work fine.
I really restored 10 continious bad frames in video with motions.

sven_x
2nd December 2011, 10:18
I wrote some restore bad frame functions with MFlowInter with following parameters (big number functions - 10) [...]
Also I wrote Backdoor restore functions.

Please post your script.
I am searching for a script that can do this interpolations basing on a ConditionalReader file, that the following script produces.


# perhaps ydiffp can be replaced by last value of ydiffn to speed up the analysis pass.

#0.6b:
#Writing ConditionalReader() Type files dups_pl.txt, dups_pre.txt, dups_post.txt


global source1=AVISource("test79400.avi")
#DirectshowSource("....avi",30,true,false,true)
#global source1=SegmentedAVISource("....avi")

last=source1
ConvertToYV12() # YV12 needed for MVTools and for CCE Basic

global diffp=0
global diffn=0
global fp1=0

global dup_thresh=0.0001 #threshold, below threshold is considered as duplicate frame
global gap_pos=0 #Gap start
global gap_l=0 #Gap length
global pregap=0 #Gap YDifference before gap
global postgap=0 #Gap YDifference after gap
global gap_end=false # Bolean, triggers writing of gap properties into dup.txt file
global gapmarker="=" #Visual Gap length marker
global ydiffp=1
global ydiffn=1

#Test function: display parameter results visually
#..................................................

#ScriptClip("""Subtitle("frame_number: "+String(fp1)+", YdiffP: "+String(diffp)+", YdiffN: "+String(diffn)) """)

#~ ScriptClip("""Subtitle(x=8, Y=20,text_color=$FF4422,\
#~ "pos: "+String(gap_pos)+", gap_l: "+String(gap_l)+", pregap: "+String(pregap)\
#~ +", postgap: "+String(postgap)+", gapmarker: "+String(gapmarker) ) """)



#Display frame number and diffp, diffn
#...................................................................

ScriptClip("f1()")
ScriptClip("f3()")
ScriptClip("f4()")

function f1(clip c) {
c=FrameEvaluate(c,"fp1=current_frame")
return(c)
}

function f3(clip c) {
c=FrameEvaluate(c,"diffp=YDifferenceFromPrevious(source1)")
return(c)
}

function f4(clip c) {
c=FrameEvaluate(c,"diffn=YDifferenceToNext(source1)")
return(c)
}

#Search gaps with duplicate frames and write dups_report.txt + txt-files
#......................................................................
ScriptClip("fg1a()")
ScriptClip("fg1b()")
ScriptClip("fg1c()")
ScriptClip("fg2()")
ScriptClip("fg3a()")
ScriptClip("fg3b()")
ScriptClip("fg3c()")

colon=" " #define colon

WriteFileStart("dups_report.txt", """ "frame number : gap-length : Ydiffpregap : Ydiffpostgap : marker" """)
WriteFileIf("dups_report.txt", "gap_end== true", "gap_pos", "colon", "gap_l", "colon", "pregap", "colon","postgap", \
"colon", """LeftStr("===========",gap_l)""")

WriteFileStart("dups_pl.txt", """ "Type int" """,false) #position, gap lenght
WriteFileStart("dups_pl.txt", """ "Default 0" """,true)
WriteFileStart("dups_pre.txt", """ "Type float" """,false) #position, Ydiff pre gap
WriteFileStart("dups_pre.txt", """ "Default 0.0" """,true) #append
WriteFileStart("dups_post.txt", """ "Type float" """,false) #position, Ydiff post gap
WriteFileStart("dups_post.txt", """ "Default 0.0" """,true) #append

WriteFileIf("dups_pl.txt", "gap_end== true", "gap_pos", "colon", "gap_l") #position, gap lenght
WriteFileIf("dups_pre.txt", "gap_end== true", "gap_pos", "colon", "pregap") #position, Ydiff pre gap
WriteFileIf("dups_post.txt", "gap_end== true", "gap_pos", "colon", "postgap") #position, Ydiff post gap


#gapmarker=LeftStr("=========",gap_l) #visually marking gap length

#begin gap: gap_pos=current_frame, gap_l=1
#YDifferenceFromPrevious() > dup_thresh && YDifferenceToNext() < dup_thresh ?

function fg1a(clip c) {
c=FrameEvaluate(c,"gap_pos= ydfp > dup_thresh && ydfn < dup_thresh ? current_frame+1 : gap_pos" )
return(c)
}

function fg1b(clip c) {
c=FrameEvaluate(c,"gap_l= ydfp > dup_thresh && ydfn < dup_thresh ? 0 : gap_l" )
return(c)
}

function fg1c(clip c) {
c=FrameEvaluate(c,"pregap= ydfp > dup_thresh && ydfn < dup_thresh ? ydfp : pregap" )
return(c)
}


#middle gap: gap=gap+1
#YDifferenceFromPrevious() < dup_thresh && YDifferenceToNext() < dup_thresh ?

function fg2(clip c) {
c=FrameEvaluate(c,"gap_l= ydfp < dup_thresh && ydfn < dup_thresh ? gap_l+1 : gap_l" )
return(c)
}


#end gap: gap=gap+1 , call writefileif,
#YDifferenceFromPrevious() < dup_thresh && YDifferenceToNext() > dup_thresh ?

function fg3a(clip c) {
c=FrameEvaluate(c,"gap_l= ydfp < dup_thresh && ydfn > dup_thresh ? gap_l+1 : gap_l" )
return(c)
}

function fg3b(clip c) {
c=FrameEvaluate(c,"gap_end= ydfp < dup_thresh && ydfn > dup_thresh && current_frame > 0 ? true : false" )
return(c)
} # recognize and of gap, but exclude frame 0


function fg3c(clip c) {
c=FrameEvaluate(c,"ydfp=YDifferenceFromPrevious(source1)"\
+"ydfn=YDifferenceToNext(source1)" \
+"postgap= ydfp < dup_thresh && ydfn > dup_thresh ? ydfn : postgap" )
return(c)
}


#Cropping to increase encoding speed
#..............................................................................
Crop(500, 360, -0, -0)
#cropping increases speed up to 400% for first pass if you run the script by encoding


The ConditionalReader file dups_pl.txt looks like this:
Type int
Default 0
57 10
104 1
107 1
110 1
118 1

Which is: Position LengthOfGap

The report file dups_report.txt looks like this:
frame number : gap-length : Ydiffpregap : Ydiffpostgap : marker
57 10 3.217846 10.803629 ==========
104 1 4.960470 4.838520 =
107 1 7.204895 4.491889 =
110 1 7.093846 4.452096 =
118 1 5.184397 5.302520 =

Where the "===" are a visual marker that helps to find faster long traces of duplicate frames in that list. In very long gaps the interpolation results may be bad.

When there are scene changes inside the gap, an interpolation of that gap makes no sense. They can be recognized by a great value of Ydiffn. therefore the script also writes another ConditionalReader file dups_post.txt which contains this value for each gap.

Type float
Default 0.0
57 10.803629
104 4.838520
107 4.491889
110 4.452096
118 5.302520

Gavino
2nd December 2011, 12:59
Mug Funky wrote a generic function that will replace a specified range of frames (of any length) by MVTools interpolation between the start and end points. See this post (and my comments following it).

@sven_x

...
ScriptClip("f1()")
ScriptClip("f3()")
ScriptClip("f4()")
...
ScriptClip("fg1a()")
ScriptClip("fg1b()")
... etc ...
You are invoking the run-time environment recursively here. There is no need for these function calls to be inside ScriptClip - they can be called directly, since FrameEvaluate is itself a run-time filter.

Also, none of the variables need to be global (as can be seen since you have global variables ydiffp and ydiffn, but you actually use variables called ydfp and ydfn in the script).

Jenyok
3rd December 2011, 15:29
sven_x
.
See addited ZIP file...
There are some comments in Russian in AVS file.
There is NO anything check Code done.

Gavino
3rd December 2011, 21:44
See addited ZIP file...
Can you explain the purpose of the XXXBackFrames functions?
It seems to me, for example, that PairBackFrames(N) replaces frames N-2 and N-1 with new frames interpolated between N and N+3, which doesn't seem right.

Also, you should use Trim(0, -N) everywhere instead of Trim(0, N-1), which gives the wrong result for N=1 (as I explained in post #25).

Jenyok
4th December 2011, 16:12
Gavino
.
Thank you for your critic.
Please, write correct Code, how you think, in example of function TenBackFrames(clip clp, int N) .
See Code below.
Thankful in advance to you for your cooperation.
.

function TenBackFrames(clip clp, int N)
{
# N is number of the last frame in Source that needs replacing.
# Frames N - 10 and N - 9 and N - 8 and N - 7 and N - 6 and N - 5 and N - 4
# and N - 3 and N - 2 and N - 1 (O) will be replaced.

clp.trim(0, N - 11) ++ interTen1.trim(N, -1) ++ interTen2.trim(N, -1) ++ \
interTen3.trim(N, -1) ++ interTen4.trim(N, -1) ++ interTen5.trim(N, -1) ++ \
interTen6.trim(N, -1) ++ interTen7.trim(N, -1) ++ interTen8.trim(N, -1) ++ \
interTen9.trim(N, -1) ++ interTen10.trim(N, -1) ++ clp.trim(N, 0)
}

Gavino
4th December 2011, 16:41
I don't understand the purpose of your 'Back' functions.
Is TenBackFrames(N) supposed to do the same thing as TenFrames(N-10)? If so, why not just use TenFrames instead?

If you really want two separate functions for convenience, just make TenBackFrames simply a call to TenFrames.

2Bdecided
14th December 2011, 14:42
What I would love is a generic function that lets me just list the bad frames, and returns a clip with those frames replaced with motion-interpolated versions.

If it works properly for frame number 1, and also for any number of consecutive bad frames, so much the better.

So, something like Badframeinter(1,5,6,7,1000,1001,1205). Option to just hand it a text file with frame numbers (one on each line) would be cool too.

Shall I ask Santa? ;)

Seriously, I could hack to together myself, in the most inefficient way possible, but I would make all the mistakes described in this thread, and more.

Cheers,
David.

Gavino
14th December 2011, 14:57
What I would love is a generic function that lets me just list the bad frames, and returns a clip with those frames replaced with motion-interpolated versions.
I did this (restricted to replacing single frames) a while back:
http://forum.videohelp.com/threads/322848-Scripts-and-filters-for-an-Opera-%28sample-videos-included%29?p=2089696#post2089696

StainlessS
14th December 2011, 14:58
ClipClop() would be of assistance in developing something if Santa does not show up.

EDIT: Just saw that Gavino beat me to it, was meaning something pretty much the
same as in the Gavino link.

EDIT:, it is my intent to at some stage put up a collection of frame fix options and use ClipClop
to select the best particular option for a frame. Eg using Bi-directional predicton,
PredictFromPrevious, PredictFromNext and then using eg ClipClop Command file:

1 10 # replace frame 10 using Bidirectional prediction
2 20 # replace frame 20 using PredictFromPrevious
3 30 # replace frame 30 using PredictFromNext

Clip 0 would be the original clip, 1 bidir,2 fromPrev, 3 fromNext
Quite easy to knock it up yourself.

EDIT: You could also make a couple of replacement clips for eg CopyFromPrevious and CopyFromNext
just by shifting the frames over by 1 frame.

Emulgator
17th December 2011, 17:11
And here is my Unipolator.
I decided to release it into the wild today, Santa is close and 2011 ran as hell.

Can do motion-based interpolation of 0-7 consequent missing frames in 0-52 places at once.
Especially designed for in-place repair of heavily damaged frames and/or recalculation and reinsertion of missing frames.

It is walkthrough-documented,
helps with tailored assertions to check against certain parameter violations
and has a nice switchable and resolution and widescreen-dependent overlay.

I guess the conditional splicer could be straightened out and forged into a function,
the whole beast could be a function as well (a Gavino case?), but my time is too limited right now.
--------------
Oops.
The text that you have entered is too long (157793 characters). Please shorten it to 16000 characters long.

A .7z is coming soonish...

Maybe this post missed the thread, because Unipolator uses MFlowInter, not MVFlow.
I will open a new thread.

http://forum.doom9.org/showthread.php?p=1547405

This could help the attachment approval as well.

Mounir
18th December 2011, 17:26
I am waiting for the approval to clear, upload to mediafire if you can

StainlessS
20th December 2011, 21:24
@Moderator, I hope that Emulgator's attachment can be approved soon, please,
and merry xmas to one & all.

bizz & buzz
26th December 2011, 19:28
can someone please approve Emulgator's attachment?

Mounir
27th December 2011, 11:02
i co-sign its been 10 days and we're still waiting...

Emulgator
27th December 2011, 16:59
Maybe my post missed the thread, because Unipolator uses MFlowInter, not MVFlow.
I will open a new thread.

http://forum.doom9.org/showthread.php?p=1547405

This could help the attachment approval as well.

Paazabel
31st December 2011, 06:16
I'm a bit confused by where this thread leaves off. I'll say that my need matches the OP: I have been capturing analog tape (my God, will this stuff all just die, already?) and some of the sections of tape are not so great. I've got a top-notch VCR and know about head cleaning, but I'm still getting handfuls of herky-jerky dropped and/or inserted frames from time to time. A few spots, this is pretty disturbing, but in most cases, it is limited to one damaged field or frame at a time.

I have 160+ hours of this tape. Yeah. I really, really don't want to have to mark each bad frame and figure out what to do with it. I already have AVIsynth stuff set up to crop the garble off the bottom, do some VHS noise filtering, yadda, yadda, yadda. Would be nice if I had a method that says, "Oh, hey, that's a bad frame. How about we repeat the last one." Interpolating between frames is great, but just finding several hundred frames in the bazillion I'm going to be running into and making them not look like Max Headroom is plenty good enough for me.

Is that what this filter we are waiting for does?

Generating a list is okay, I guess. Doesn't this do what 2Bdecided is asking for? http://avisynth.org.ru/badframes/badframes.html

Jenyok
27th January 2012, 18:42
One more Script...


#
#
# File: Interpolate_Bad_Frames.avs
# License GNU
# AviSynth 2.5.8
# VirtualDub 1.9.11
#
# Restore bad frames with interpolation
#
#
# Needed plugins and libruaries:
# MVTools2
# GScript
# AVSLib (Array structure)
#
#
# You could write interpolation functions, see script code, up to 60 frames inc.
# This is the limit of the Array structure in the AVSLib.
#
#
# !!! No any checked in interpolate functions are done (Trim() function, see script code).
#
#



LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\MVTOOLS-V2_5_11_3\mvtools2.dll")
LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\GSCRIPT_11\gscript.dll")
LoadPackage("avslib", "array")



AVISource("01-build_avi_2000_Zelenograd_AVI.avi") # Your input file is here


ConvertToYUY2()


Audio=GetChannel(last, 1, 2)
KillAudio()


function Interpolate(clip clp, int FrameNumber, int FrameInterpolate)
{
# Constants
# Change those constants to tune for the best result of interpolation
#
searchp = 2 # 2
blks = 32 # 8
blksV = 32 # 8
hpad = 2 # 4
vpad = 2 # 4
pel = 4 # 4

tCD1 = 300 # 1500
tCD2 = 128 # 130
iml = 70 # 70

# Restore bad frames with interpolation with MFlowInter
# Prepare functions
#
# function MSuper(clip, int "hpad", int "vpad", int "pel", int "levels", bool "chroma", \
# int "sharp", int "rfilter", clip "pelclip", bool "isse", bool "planar")
#
super = MSuper(clp, \
hpad = hpad, \
vpad = vpad, \
pel = pel, \
levels = 0, \
chroma = true, \
sharp = 2, \
rfilter = 4, \
isse = true, \
planar = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
backward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = true, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
forward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = false, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

# Create an empty Array of clips
#
Array2 = ArrayCreate()

# Fill an Array with the MFlowInter() clips with different times
#
GScript("""
for (i=0, FrameInterpolate-1) {
itime = (100.0 / Float(FrameInterpolate + 1)) * Float(i + 1)
inter = MFlowInter(clp, \
super, \
backward_vectors, \
forward_vectors, \
time = itime, \
mL = iml, \
blend = true, \
thSCD1 = tCD1, \
thSCD2 = tCD2, \
isse = true, \
planar = false)
Array2 = Array2.ArrayInsert(inter, index=i)
} # End of For ()
""") # End of GScript ()

# Get MFlowInter() clips with different times from array to do interpolated frames
#
GScript("""
for (i=0, FrameInterpolate-1) {
if (i == 0) {
inter = Array2.ArrayGet(i).Trim(FrameNumber, -1)
}
else {
inter = inter ++ Array2.ArrayGet(i).Trim(FrameNumber, -1)
}
} # End of For ()
""") # End of GScript ()

# Delete an Array of interpolate clips
#
GScript("""
for (i=FrameInterpolate-1, 0, -1) {
Array2 = Array2.ArrayDelete(index=i)
} # End of For ()
""") # End of GScript ()

return (inter)
}



function OneFrame(clip clp, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 1) ++ clp.trim(N + 1, 0)
}

function PairFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function TwoFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function ThreeFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 3) ++ clp.trim(N + 3, 0)
}

function FourFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 4) ++ clp.trim(N + 4, 0)
}

function FiveFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 5) ++ clp.trim(N + 5, 0)
}

function SixFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 6) ++ clp.trim(N + 6, 0)
}

function SevenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 7) ++ clp.trim(N + 7, 0)
}

function EightFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 8) ++ clp.trim(N + 8, 0)
}

function NineFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 9) ++ clp.trim(N + 9, 0)
}

function TenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 10) ++ clp.trim(N + 10, 0)
}

function SeventeenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 ... N + 17 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 17) ++ clp.trim(N + 17, 0)
}



# Restore bad frames (only for example)
#
OneFrame(10) # 10 is bad frame
TwoFrames(20) # 20, 21 are bad frames
ThreeFrames(30) # 30, 31, 32 are bad frames
FourFrames(40) # 40, 41, 42, 43 are bad frames
FIverames(50) # 50, 51, 52, 53, 54 are bad frames
SixFrames(60) # 60, 61, 62, 63, 64, 65 are bad frames
SevenFrames(70) # 70, 71, 72, 73, 74, 75, 76 are bad frames
EightFrames(80) # 80, 81, 82, 83, 84, 85, 86, 87 are bad frames
NineFrames(90) # 90, 91, 92, 93, 94, 95, 96, 97, 98 are bad frames
TenFrames(100) # 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 are bad frames
SeventeenFrames(120) # 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 are bad frames



AudioDub(last, Audio)

Jenyok
30th January 2012, 19:13
Restore "bad frames" with interpolation MFlowInter().
New version.


#
#
# Ver. 1.1
# 30.01.2012 year
#
#
# File: Interpolate_Bad_Frames.avs
# License GNU
# AviSynth 2.5.8
# VirtualDub 1.9.11
#
#
# Restore bad frames with interpolation
#
#
# Needed plugins and libruaries:
# MVTools2
# GScript
# AVSLib (Array structure)
#
#
# You could write interpolation functions, see script code, up to 60 frames inc.
# This is the limit of the Array structure in the AVSLib.
#
#
# !!! No any checked in interpolate functions are done (Trim() function, see script code).
#
#



LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\MVTOOLS-V2_5_11_3\mvtools2.dll")
LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\GSCRIPT_11\gscript.dll")
LoadPackage("avslib", "array")



AVISource("01-build_avi_2000_Zelenograd_AVI.avi") # Your input file is here


ConvertToYUY2()


Audio=GetChannel(last, 1, 2)
KillAudio()


function Interpolate(clip clp, int FrameNumber, int FrameInterpolate)
{
# Constants
# Change those constants to tune for the best result of interpolation
#
searchp = 2 # 2
blks = 32 # 8
blksV = 32 # 8
hpad = 2 # 4
vpad = 2 # 4
pel = 4 # 4

tCD1 = 300 # 1500
tCD2 = 128 # 130
iml = 70 # 70

# Restore bad frames with interpolation with MFlowInter
# Prepare functions
#
# function MSuper(clip, int "hpad", int "vpad", int "pel", int "levels", bool "chroma", \
# int "sharp", int "rfilter", clip "pelclip", bool "isse", bool "planar")
#
super = MSuper(clp, \
hpad = hpad, \
vpad = vpad, \
pel = pel, \
levels = 0, \
chroma = true, \
sharp = 2, \
rfilter = 4, \
isse = true, \
planar = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
backward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = true, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
forward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = false, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

GScript("""
if (FrameInterpolate == 1) {
inter = MFlowInter(clp, \
super, \
backward_vectors, \
forward_vectors, \
time = 50, \
mL = iml, \
blend = true, \
thSCD1 = tCD1, \
thSCD2 = tCD2, \
isse = true, \
planar = false)
inter = inter.Trim(FrameNumber, -1)
} # End of If-Then
else {
# Create an empty Array of clips
#
Array2 = ArrayCreate()

# Fill an Array with the MFlowInter() clips with different times
#
for (i=0, FrameInterpolate-1) {
itime = (100.0 / Float(FrameInterpolate + 1)) * Float(i + 1)
inter = MFlowInter(clp, \
super, \
backward_vectors, \
forward_vectors, \
time = itime, \
mL = iml, \
blend = true, \
thSCD1 = tCD1, \
thSCD2 = tCD2, \
isse = true, \
planar = false)
Array2 = Array2.ArrayInsert(inter, index=i)
} # End of For ()

# Get MFlowInter() clips with different times from array to do interpolated frames
#
for (i=0, FrameInterpolate-1) {
if (i == 0) {
inter = Array2.ArrayGet(i).Trim(FrameNumber, -1)
}
else {
inter = inter ++ Array2.ArrayGet(i).Trim(FrameNumber, -1)
}
} # End of For ()

# Delete an Array of interpolate clips
#
for (i=FrameInterpolate-1, 0, -1) {
Array2 = Array2.ArrayDelete(index=i)
} # End of For ()
} # End of If-Else
""") # End of GScript ()

return (inter)
}



function OneFrame(clip clp, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 1) ++ clp.trim(N + 1, 0)
}

function PairFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function TwoFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function ThreeFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 3) ++ clp.trim(N + 3, 0)
}

function FourFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 4) ++ clp.trim(N + 4, 0)
}

function FiveFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 5) ++ clp.trim(N + 5, 0)
}

function SixFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 6) ++ clp.trim(N + 6, 0)
}

function SevenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 7) ++ clp.trim(N + 7, 0)
}

function EightFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 8) ++ clp.trim(N + 8, 0)
}

function NineFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 9) ++ clp.trim(N + 9, 0)
}

function TenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 10) ++ clp.trim(N + 10, 0)
}

function SeventeenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 ... N + 17 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 17) ++ clp.trim(N + 17, 0)
}



# Restore bad frames (only for example)
#
OneFrame(10) # 10 is bad frame
TwoFrames(20) # 20, 21 are bad frames
ThreeFrames(30) # 30, 31, 32 are bad frames
FourFrames(40) # 40, 41, 42, 43 are bad frames
FIverames(50) # 50, 51, 52, 53, 54 are bad frames
SixFrames(60) # 60, 61, 62, 63, 64, 65 are bad frames
SevenFrames(70) # 70, 71, 72, 73, 74, 75, 76 are bad frames
EightFrames(80) # 80, 81, 82, 83, 84, 85, 86, 87 are bad frames
NineFrames(90) # 90, 91, 92, 93, 94, 95, 96, 97, 98 are bad frames
TenFrames(100) # 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 are bad frames
SeventeenFrames(120) # 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 are bad frames



AudioDub(last, Audio)

Jenyok
30th January 2012, 19:43
One more and more script.
Very new version.


#
#
# Ver. 1.2
# 30.01.2012 year
#
#
# File: Interpolate_Bad_Frames.avs
# License GNU
# AviSynth 2.5.8
# VirtualDub 1.9.11
#
#
# Restore bad frames with interpolation
#
#
# Needed plugins and libruaries:
# MVTools2
# GScript
#
#
# You could write interpolation functions, see script code, up to 60 frames inc.
# This is the limit of the Array structure in the AVSLib.
#
#
# !!! No any checked in interpolate functions are done (Trim() function, see script code).
#
#



LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\MVTOOLS-V2_5_11_3\mvtools2.dll")
LoadPlugin("C:\PROGRAM FILES\AVISYNTH 2.5\PLUGINS\GSCRIPT_11\gscript.dll")



AVISource("01-build_avi_2000_Zelenograd_AVI.avi") # Your input file is here


ConvertToYUY2()


Audio=GetChannel(last, 1, 2)
KillAudio()


function Interpolate(clip clp, int FrameNumber, int FrameInterpolate)
{
# Constants
# Change those constants to tune for the best result of interpolation
#
searchp = 2 # 2
blks = 32 # 8
blksV = 32 # 8
hpad = 2 # 4
vpad = 2 # 4
pel = 4 # 4

tCD1 = 300 # 1500
tCD2 = 128 # 130
iml = 70 # 70

# Restore bad frames with interpolation with MFlowInter
# Prepare functions
#
# function MSuper(clip, int "hpad", int "vpad", int "pel", int "levels", bool "chroma", \
# int "sharp", int "rfilter", clip "pelclip", bool "isse", bool "planar")
#
super = MSuper(clp, \
hpad = hpad, \
vpad = vpad, \
pel = pel, \
levels = 0, \
chroma = true, \
sharp = 2, \
rfilter = 4, \
isse = true, \
planar = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
backward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = true, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

# function MAnalyse(clip super, int "blksize", int "blksizeV", int "level", int "search", int "searchparam", \
# int "pelsearch", bool "isb", int "lambda", bool "chroma", int "delta", bool "truemotion", \
# int "lsad", int "plevel", bool "global", int "pnew", int "pzero", int "pglobal", int "overlap", \
# int "overlapV", string "outfile", int "dct", int "divide", int "sadx264", int "badSAD", \
# int "badrange", bool "isse", int "full", bool "meander", bool "temporal")
#
forward_vectors = MAnalyse(super, \
blksize = blks, \
blksizeV = blksV, \
levels = 0, \
search = 4, \
searchparam = searchp, \
pelsearch = 2, \
isb = false, \
lambda = 0, \
chroma = true, \
delta = FrameInterpolate + 1, \
truemotion = true, \
lsad = 1200, \
plevel = 0, \
global = true, \
pnew = 50, \
pzero = 50, \
pglobal = 0, \
overlap = 0, \
overlapV = 0, \
dct = 0, \
divide = 0, \
sadx264 = 0, \
badSAD = 10000, \
badrange = 24, \
isse = true, \
meander = true, \
temporal = false, \
trymany = false)

GScript("""
if (FrameInterpolate == 1) {
inter2 = MFlowInter(clp, \
super, \
backward_vectors, \
forward_vectors, \
time = 50, \
mL = iml, \
blend = true, \
thSCD1 = tCD1, \
thSCD2 = tCD2, \
isse = true, \
planar = false)
inter = inter2.Trim(FrameNumber, -1)
} # End of If-Then
else {
# Fill an Inter variable with the MFlowInter() clips with different times
# Times are calculated in each step
#
for (i=0, FrameInterpolate-1) {
itime = (100.0 / Float(FrameInterpolate + 1)) * Float(i + 1)
inter2 = MFlowInter(clp, \
super, \
backward_vectors, \
forward_vectors, \
time = itime, \
mL = iml, \
blend = true, \
thSCD1 = tCD1, \
thSCD2 = tCD2, \
isse = true, \
planar = false)
if (i == 0) {
inter = inter2.Trim(FrameNumber, -1)
} # End of If-Then
else {
inter = inter ++ inter2.Trim(FrameNumber, -1)
} # End of If-Else
} # End of For ()
} # End of If-Else
""") # End of GScript ()

return (inter)
}



function OneFrame(clip clp, int N)
{
# N is number of the frame in Source that needs replacing.
# Frame N will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 1) ++ clp.trim(N + 1, 0)
}

function PairFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function TwoFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 2) ++ clp.trim(N + 2, 0)
}

function ThreeFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 3) ++ clp.trim(N + 3, 0)
}

function FourFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 4) ++ clp.trim(N + 4, 0)
}

function FiveFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 5) ++ clp.trim(N + 5, 0)
}

function SixFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 6) ++ clp.trim(N + 6, 0)
}

function SevenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 7) ++ clp.trim(N + 7, 0)
}

function EightFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 8) ++ clp.trim(N + 8, 0)
}

function NineFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 9) ++ clp.trim(N + 9, 0)
}

function TenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 10) ++ clp.trim(N + 10, 0)
}

function SeventeenFrames(clip clp, int N)
{
# N is number of the first frame in Source that needs replacing.
# Frames N and N + 1 and N + 2 and N + 3 and N + 4 and N + 5 and N + 6
# and N + 7 and N + 8 and N + 9 ... N + 17 (O) will be replaced.

clp.trim(0, N - 1) ++ Interpolate(clp, N - 1, 17) ++ clp.trim(N + 17, 0)
}



# Restore bad frames (only for example)
#
OneFrame(10) # 10 is bad frame
TwoFrames(20) # 20, 21 are bad frames
ThreeFrames(30) # 30, 31, 32 are bad frames
FourFrames(40) # 40, 41, 42, 43 are bad frames
FIverames(50) # 50, 51, 52, 53, 54 are bad frames
SixFrames(60) # 60, 61, 62, 63, 64, 65 are bad frames
SevenFrames(70) # 70, 71, 72, 73, 74, 75, 76 are bad frames
EightFrames(80) # 80, 81, 82, 83, 84, 85, 86, 87 are bad frames
NineFrames(90) # 90, 91, 92, 93, 94, 95, 96, 97, 98 are bad frames
TenFrames(100) # 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 are bad frames
SeventeenFrames(120) # 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 are bad frames



AudioDub(last, Audio)

2Bdecided
1st February 2012, 13:53
Doesn't this do what 2Bdecided is asking for? http://avisynth.org.ru/badframes/badframes.htmlNo, because though it says blend is "interpolation", it's really just a blend - i.e. overlaying the two frames either side of the bad one. No mvtools or motion compensation involved.


The scripts from Emulgator and Jenyok both seem to do what's required, using different syntaxes. Neither matches the generic "list the frames you want replacing" syntax of badframes. If they did, they would be ideal.

Cheers,
David.

Gavino
1st February 2012, 14:04
2Bdecided, how about my solution from post #34 (http://forum.doom9.org/showpost.php?p=1544940&postcount=34)?
Admittedly, it does not deal intelligently with consecutive bad frames, as each frame is interpolated only from its previous and next neighbours.

2Bdecided
2nd February 2012, 12:04
2Bdecided, how about my solution from post #34 (http://forum.doom9.org/showpost.php?p=1544940&postcount=34)?
Admittedly, it does not deal intelligently with consecutive bad frames, as each frame is interpolated only from its previous and next neighbours.I overlooked that as I was working on something with consecutive bad frames. But now I'm working on something with isolated bad frames, that's great! Thanks Gavino.

Cheers,
David.

pbristow
7th February 2012, 12:51
I have 160+ hours of this tape. Yeah. I really, really don't want to have to mark each bad frame and figure out what to do with it. I already have AVIsynth stuff set up to crop the garble off the bottom, do some VHS noise filtering, yadda, yadda, yadda. Would be nice if I had a method that says, "Oh, hey, that's a bad frame. How about we repeat the last one."


Yeah, there's basically two steps to the problem, and we have lots of options for how to tackle step 2 (creating a replacement frame), and none for step 1 (how to *detect* a frame that needs replacing).

The problem here is that there is no generalised meaning of the phrase "bad frame". Frames can go bad in so many different ways: Dissolving into white noise; Jumping up and down; going blank; or being replaced by a copy of the last "good" frame (which might not be *that* good anyway) because the capture device lost the incoming analog signal; and so on.

So you need to look at your source tape/capture and figure out: What is the most common way that frames go "bad" on this one? How can I build a detector for that situation, that won't misinterpret perfectly legitimate frames as bad ones?

For example, if the main problem is vertical off-locks, then you could use MVTools2 to detect cases where the picture information suddenly moves upward/downward in one frame, and back again a frame or two later. (We added the "one dimensional" search modes to MVTools2 specifically to speed up jobs like that. There's one that looks for vertical-only movement and one for horizontal-only; They're much faster than the general movement detection modes).

The closest I can get to a generalised approach to "bad frame" detection is really "unique" or "very unusual" frame detection: You basically compare each frame with it's immediate neighbours in various ways and raise a flag if it seems very different to *both*. (If it's different to one neighbour but very similar to the other, then it's a probably just a scene change.)

Maybe there would be value in a "FindWeirdFrame" function, with options to tell it to look for various common types of weirdness? It could either output a list of suspect frames, to be checked manually (if you have time) and then passed to the other tools mentioned in this thread, or it could be coded to use appropriate techniques to tackle each type of "weirdness" that it finds.

I will ponder upon this...
:cool:

Jenyok
7th February 2012, 14:17
pbristow

Only human eye(s) could see "bad frame(s)",
only human brain could decide which frame(s) is bad or not...