View Full Version : Blend duplicate frames?
bcn_246
11th April 2016, 19:08
Hey, I have some footage with quite a few duplicate frames. I have found a number of scripts that use interpolation (FillDrops, MorphDups, DoubleDropFix, GameDropFix) however a simple blend (like that used in ConvertFPS) would be preferable. Does such a script exist, and if not, would it be possible to modify something like the following to use a simple blend rather than interpolation with MVTools/SVP?
TIA
# filldrops3 based on MugFunky's filldrops from 19.December 2005, extended by Emulgator on 26.Feb.2012 to accommodate interpolation of Doupledrops
# http://forum.doom9.org/showthread.php?p=753779#post753779
# "...so i wrote a little function to replace all frames that are identical to the previous one with a motion-interpolation of the adjacent frames.
# it could be useful for captures that you can't get again, but are full of drops..."
# Needs MVTools2, deviation now tunable.
function filldrops3 (clip c, float "dev")
{
blksz=16 # Blocksize for Motion search. Default = 8. My Default 16: Delivers a smoother picture. 4: Gives too many artefacts with poorer source.
searchp=32 # Radius for Motion search. Default = 2, My Default = 32
bld=true # Decides what to do if a Scenechange is detected by the following parameters: true will blend, false will repeat previous frame.
SCDpb=800 # Default = 400. thSCD1. SAD (pixels*luma values) Threshold per Block. A Block exceeding this SAD is considered changed.
## SAD = Sum of Absolute Differences = Number of pixels per 8x8 block (=64) multiplied with their luma difference.
## SCDpb is always given related to 8x8 blocks and scaled internally to match other block sizes. SCDbp is thSCD1 and is evaluated before SCDpf=thSCD2
SCDpf=200 # 0-255, Default=130. thSCD2. Changed Blocks percentage threshold per frame. 0=0%, 127=50%, 255 = 100%.
## This Threshold sets which minimal percentage of changed blocks a frame has to contain to be considered as a scene change.
dev=default(dev, 2.0)
super=MSuper(c,pel=2)
back_vec=MAnalyse(super, blksize=blksz, search=5, searchparam=searchp, isb=true, delta=1, temporal=false, dct=0, divide=0, trymany=false)#delta=framedistance;isb=IS Backward
# Looks 1 frame ahead and calculates vectors backward to reference frame.
forw_vec=MAnalyse(super, blksize=blksz, search=5, searchparam=searchp, isb=false, delta=1, temporal=false, dct=0, divide=0, trymany=false)#search 3:=Exhaustive; 4:=Hex(default); 5:=UMH
# Looks 1 frame behind and calculates vectors forward to reference frame.
dblback_vec=MAnalyse(super, blksize=blksz, search=5, searchparam=searchp, isb=true, delta=2, temporal=false, dct=0, divide=0, trymany=false)#delta=framedistance;isb=IS Backward
# Looks 2 frames ahead and calculates vectors backward to reference frame. To be used when reference frame + 1 has to be excluded.
dblforw_vec=MAnalyse(super, blksize=blksz, search=5, searchparam=searchp, isb=false, delta=2, temporal=false, dct=0, divide=0, trymany=false)#search 3:=Exhaustive; 4:=Hex(default); 5:=UMH
# Looks 2 frames behind and calculates vectors forward to reference frame. To be used when reference frame -1 has to be excluded.
global fillsingdrops = MFlowInter(c,super,back_vec,forw_vec,time=50, blend=bld, thSCD1=SCDpb, thSCD2=SCDpf)
global filldoubdrops33 = MFlowInter(c,super,dblback_vec,dblforw_vec,time=33, blend=bld, thSCD1=SCDpb, thSCD2=SCDpf)
global filldoubdrops67 = MFlowInter(c,super,dblback_vec,dblforw_vec,time=67, blend=bld, thSCD1=SCDpb, thSCD2=SCDpf)
global oric=c
global devthresh=dev
#ConditionalFilter(c, c, fillsingdrops, "YDifferenceFromPrevious()", ">", "devthresh", show=true)##works for mending of single framerepeats
#ConditionalFilter(c, c, filldoubdrops33, "YDifferenceFromPrevious()>devthresh", "&&", "YDifferenceToNext()>devthresh", show=true)##wrong syntax
c.scriptclip("""(YDifferenceFromPrevious<devthresh) && (YDifferenceToNext<devthresh) ? (filldoubdrops33++filldoubdrops67.Trim(1,0)) : (YDifferenceFromPrevious<devthresh) ? fillsingdrops : oric""")
}
LoRd_MuldeR
11th April 2016, 22:13
Doesn't Dup with "blend=true" do exactly that?
http://rationalqm.us/dup/dupnew.html
bcn_246
11th April 2016, 23:21
Doesn't Dup with "blend=true" do exactly that?
http://rationalqm.us/dup/dupnew.html
It does... kind of... however with very poor results (the threshold has to be set high to detect duplicates, and ends up blending a lot of good frames also). I have tried de-noising prior to running Dup and things don't get much better. The aforementioned interpolation scripts, while not perfect, do a much better job of detecting what to interpolate. The issue is with the artefacts...
The script posted seems to do the best job when it comes to detecting duplicates, just the artefacts are way to much (thus a simple blend, like that used in Dup, would be much preferred).
johnmeyer
11th April 2016, 23:56
I fully understand that motion estimation sometimes creates artifacts. Here is a version of filldrops that simply blends the current frame with the previous frame:
source=AVISource("e:\fs.avi").convertTOYV12()
merged=filldrops(source)
#stackhorizontal(source,merged)
return merged
function filldrops (clip c)
{
prev=trim(c,1,0)
global filldrops=merge(c,prev)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "0.1")
return fixed
}
I hardwired the threshold to "0.1". If that detects too few or too many duplicates, then change it.
Also, the simple motion-estimated version of filldrops() that I created a few years ago does a pretty good job with many clips. This is the same as MugFunky's original code for progressive video, but modified to use MVTools2 instead of the original MVTools. Feel free to try this out, if you don't like the ghosting that is inherent in blending adjacent frames (as the above code does):
function filldrops (clip c)
{
super=MSuper(c,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1)
vbe=manalyse(super,truemotion=true,isb=true,delta=1)
filldrops = mflowinter(c,super,vbe,vfe,time=50)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "0.1")
return fixed
}
bcn_246
12th April 2016, 00:22
I fully understand that motion estimation sometimes creates artifacts. Here is a version of filldrops that simply blends the current frame with the previous frame:
source=AVISource("e:\fs.avi").convertTOYV12()
merged=filldrops(source)
#stackhorizontal(source,merged)
return merged
function filldrops (clip c)
{
prev=trim(c,1,0)
global filldrops=merge(c,prev)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "0.1")
return fixed
}
I hardwired the threshold to "0.1". If that detects too few or too many duplicates, then change it.
Also, the simple motion-estimated version of filldrops() that I created a few years ago does a pretty good job with many clips. This is the same as MugFunky's original code for progressive video, but modified to use MVTools2 instead of the original MVTools. Feel free to try this out, if you don't like the ghosting that is inherent in blending adjacent frames (as the above code does):
function filldrops (clip c)
{
super=MSuper(c,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1)
vbe=manalyse(super,truemotion=true,isb=true,delta=1)
filldrops = mflowinter(c,super,vbe,vfe,time=50)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "0.1")
return fixed
}
Thanks!
Would it be hard to create a simple threshold variable for the function (rather than editing the .avsi)?
I tried function filldrops (clip c, float "dev")
{
dev=default(dev, 0.1)
prev=trim(c,1,0)
global filldrops=merge(c,prev)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "dev")
return fixed
} But threw up an error, I think I am pretty close though...
Gavino
12th April 2016, 00:46
I tried function filldrops (clip c, float "dev")
{
dev=default(dev, 0.1)
prev=trim(c,1,0)
global filldrops=merge(c,prev)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "dev")
return fixed
} But threw up an error, I think I am pretty close though...
Try changing it to this:
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", string(dev))
I don't think 'filldrops' needs to be global either, as it's not referenced by name at run-time.
bcn_246
12th April 2016, 00:51
Thanks :)
Is there any way of implementing a set of rules using the ConditionalFilter that prevent it from blending at scene change points (like that found in filldrops3)?
Thanks a bunch for all your help!
StainlessS
12th April 2016, 00:58
Here something, not much tested.
Code REMOVED See post #20.
johnmeyer
12th April 2016, 01:10
I don't think 'filldrops' needs to be global either, as it's not referenced by name at run-time.
I know you don't like me using globals, but it most definitely did not work until I added it (the variable cannot be used inside a conditional without it).
I did try, but it didn't work until I added Global.
P.S. for StainlessS
I only tested on video that had a single duplicate at a time (i.e., I did not test it on three duplicates in a row). It worked exactly as expected, although I only did enough testing to make sure that it passed through original frames except when a duplicate was detected, and that the replaced frame was a 50/50 merge of the duplicate and the previous frame.
johnmeyer
12th April 2016, 01:13
Is there any way of implementing a set of rules using the ConditionalFilter that prevent it from blending at scene change points (like that found in filldrops3)?Probably, but it's a lot more work, especially since scene detection logic screws up a lot.
StainlessS
12th April 2016, 01:19
John you misunderstand, Blended frame should come from those either side of dupe, see edit to prev post.
EDIT: Although I guess if curr is dupe of prev then using curr is not so different.
But Prev variable name in quoted code snippit is at least misleading (should read Next).
EDIT:
especially since scene detection logic screws up a lot
The Th2 arg in BlendDupes() is not so much scenechange detection, but detecting whether blend produced would look bad,
but to a certain extent that would also include scenechanges. If blend would look bad, then duplicate will not be replaced with blend.
StainlessS
12th April 2016, 02:20
Oops bug fix in post #8
Th = Float(Default(Th,0.5))
Th2 = Float(Default(Th,8.0)) # Th should have read Th2
Few other small mods.
johnmeyer
12th April 2016, 02:54
John you misunderstand, Blended frame should come from those either side of dupe, see edit to prev post.I saw your post. I did actually run the script before I posted, and when I viewed the original and the modified version side-by-side, the script did put the blended frame at the correct spatial location (at least that's how it appeared to me). So I think it does what the OP asked for.
StainlessS
12th April 2016, 03:18
John, yes but the blended frame is a blend of current and Next frame, if that is what you intended, I was suggesting that variable name is misleading as named
Prev rather than Next and also questioning whether should be using Prev and Next rather than Curr and Next. (but if Curr is dupe of Prev then not much different).
Trim(1,0) shifts the clip Next (not Prev) frame to align with current.
Post #8 update, Added MinUniq. Allows restriction on consecutive blends replaced.
EDIT: Post #8 Updated. Removed MinUniq arg, Changed Th default to 0.25. Change in detection logic. Assigned v1.0.
johnmeyer
12th April 2016, 07:32
John, yes but the blended frame is a blend of current and Next frame, if that is what you intended, I was suggesting that variable name is misleading as named
Prev rather than Next and also questioning whether should be using Prev and Next rather than Curr and Next. (but if Curr is dupe of Prev then not much different).
Trim(1,0) shifts the clip Next (not Prev) frame to align with current,I copy/pasted from several scripts and put this together in one minute. I didn't even look at the variable names. Sorry about the prev/next confusion. Hey, doesn't everything in AVISynth work backwards (start at end of script and work backwards)?
OK, lame excuse for sloppy work ...
,,, but speaking of "work," it does do what the OP asked for ... I think ...
Gavino
12th April 2016, 08:54
I know you don't like me using globals, but it most definitely did not work until I added it (the variable cannot be used inside a conditional without it).
I did try, but it didn't work until I added Global.
Neither of the functions in post #4 use the variable 'filldrops' inside the conditional (ie in the string arguments, which are evaluated at run-time). In both functions, the variable is simply passed as a normal argument to ConditionalFilter, which is no problem. (And in the second function, it is not declared 'global'.)
StainlessS
12th April 2016, 09:16
Sorry John, I was not getting at you, just being a bit pedantic I guess, call your variables eg 'MoonbaseAlpha' if you like.
bcn_246
12th April 2016, 13:24
Thanks StanlessS... I tired using the earlier version of your script (reposted below) and got really great results. With "MinUniq = 0" and "Th2 = 16" it did exactly what I had in mind.
Can you expand a bit on what exactly the "Th" variable does? It is "Th2" that seems to be the biggest modifier for detection sensitivity. Also can I ask why you removed the MinUniq variable? On my source I had some blocks of 2 or 3 dropped frames.
Again, really appreciate all the time you guys have given :)
(Below is the version I had good results from)
Function BlendDupes(clip c,Float "Th",Float "Th2",Int "MinUniq",bool "Show") {
# BlendDupes() by StainlessS : http://forum.doom9.org/showthread.php?p=1764219#post1764219
# PROGRESSIVE. Req RT_Stats, Grunt.
# Replace dupes with a frame blended from those either side.
# Th, Default 0.5, YDifference Prev->Curr <= Th Then current frame is Dupe.
# Th2, Default 8.0, YDifference Prev->Next <= Th2 Then dif between frames either side of current is not so far
# apart that would produce bad blend (eg not scene change).
# MinUniq default 1, Minimum number of Unique frames between dupes replaced with blends. 0 or more.
# 0 = Replace ALL dupes even consecutive ones.
# 1 = consecutive dupes not replaced, at least 1 original frame left between blended replacements.
# Etc.
# Show: Puts indicator on fixed frames.
c
Th = Float(Default(Th,0.5))
Th2 = Float(Default(Th2,8.0))
MinUniq = Default(MinUniq,1)
Show=Default(Show,False)
Assert(MinUniq>=0,"BlendDupes: 0 <= MinUniq")
Function BlendDupes_lo(clip c,clip BlendC,int n,Float Th, Float Th2,Int MinUniq,Bool Show) {
c
dif_p = RT_YDifference(delta=-1) # Diff Prev <-> Curr
dif_pn = RT_YDifference(n-1,delta=2) # Diff Prev <-> Next (either side of current)
Blend = (n-GLB_BlendDupes_LastBlend>MinUniq && dif_p <= Th && dif_pn <= Th2)
Last = (Blend) ? BlendC : Last
(Blend) ? RT_IncrGlobal("GLB_BlendDupes_BlendCount") : NOP
(Show) ? RT_subtitle("%d] Blends=%d : LastBlend=%d : Uniq=%d\n Prev->Curr : Prev->Next : Blend\n %7.3f %7.3f %s",
\ n,GLB_BlendDupes_BlendCount,GLB_BlendDupes_LastBlend,n-GLB_BlendDupes_LastBlend-1,dif_p,dif_pn,Blend) : NOP
(Show) ? RT_Subtitle("Th=%.3f : Th2=%.3f : MinUniq=%d",Th,Th2,MinUniq,Align=1) : NOP
Global GLB_BlendDupes_LastBlend = (Blend) ? n : GLB_BlendDupes_LastBlend
Return Last
}
PrevC = DeleteFrame(FrameCount-1).DuplicateFrame(0) # Or SelectEvery(1,-1), I but prefer identical length clips ALWAYS.
NextC = DuplicateFrame(FrameCount-1).DeleteFrame(0) # Or SelectEvery(1,1)
BlendC = Merge(PrevC,NextC)
BlendC = (Show) ? BlendC.Subtitle("FRAME FIXED",size=30,text_color=$0000FF,align=5) : BlendC
Global GLB_BlendDupes_BlendCount = 0 Global GLB_BlendDupes_LastBlend = 0
Return Last.Scriptclip("BlendDupes_lo(Last,BlendC,current_frame,Th,Th2,MinUniq,Show)",Args="BlendC,Th,Th2,MinUniq,Show")
}
StainlessS
12th April 2016, 13:37
I deliberately changed function to cater for low motion scenes (ie not replace low motion), unfortunately it is intended that it should be for
single dupe detection only (what I would mostly have to deal with). I guess I could put back MinUniq functionality, somehow, when I figure out
what the rules are :)
What am I supposed to use for the blends where multiple consecutive dupes exist ?
StainlessS
17th April 2016, 22:29
Here, MorphDupes_MI.avs, Should fit the bill nicely.
EDIT: Previous scripts were without having a test clip, capped some webcam footage at night and because of low light conditions
had plenty of dupes, so this script tested and working very well, I think.
MorphDupes_MI.avs Part 1 of 2 (Too big, Copy/Paste together)
Function MorphDupes_MI(clip c, Int "DifbyN",Float "Th",Int "DifbyN2",Float "Th2",Float "CW",Int "MaxInterp",
\ Bool "Stack", bool "Show", Bool "ForceProcess",Bool "Verbose",
\ int "pel",int "sharp",int "rfilter",Float "ml",Int "SC_thSCD1",Int "SC_thSCD2") {
/*
MorphDupes_MI, by StainlessS. Req MvTools (c) Manoa/Fizick & Others : GScript and Grunt (c) Gavino : RT_Stats, TWriteAVI v2.0, CallCmd, (c) StainlessS.
http://forum.doom9.org/showthread.php?p=1764865#post1764865
Finds runs of duplicates and replaces them with either Interpolated or blended frames.
Planar, YUY2. Audio, no change. Multi-Instance capable.
MorphDupes_MI(clip c, Int "DifbyN"=-1,Float "Th"=0.0,Int "DifbyN2"=-1,Float "Th2"=16.0,Float "CW"=1.0/3,Int "MaxInterp"=3,
\ Int "Stack"=False, bool "Show"=False,Bool "ForceProcess"=False,Bool "Verbose"=False,
\ int "pel"=2,int "sharp"=2,int "rfilter"=2,Float "ml"=100.0,Int "SC_thSCD1"=400,Int "SC_thSCD2"=130)
There are two Difference measuring options to measure whether a frame is a duplicate or not and switched via DifByN, if DifByN is -1 (default),
then uses RT_FrameDifference function (together with CW=ChromaWeight setting, default 1.0/3, 0.0=Luma only) and Th threshold to determine
duplicate status. RT_FrameDifference returns the average pixel difference for the two comparison frames.
If DifByN is >= 0, then switches to using RT_LumaPixelsDifferent(Thresh=DifByN) where DifByN is also a control arg to
RT_LumaPixelsDifferent. RT_LumaPixelsDifferent returns the percentage of pixels where the luma difference between corresponding pixels is
greater than a threshold (DifByN). If the difference measure between current frame and it's predecessor (measured via RT_Framedifference or
RT_LumaPixelsDifferent) is <= Th, then it is deemed a duplicate frame.
Elsewhere we use the term 'Unique Start' frame, this is the frame at head of run of dupes [the frame of which others are a copy], and unique in
that it is different from its predecessor.
Frames Determined to be Duplicates:
For frames that are determined to be duplicates, there are two modes of operation, Interpolation, and Blend, the two modes are partly user
adjustable and partly automatic. MaxInterp (default 3) governs the greatest number of duplicate frames that can be Interpolated, setting it to 0
will be always in Blend mode. If a Scene change is detected via mvtools MSCDetection(thSCD1=SC_thSCD1,thSCD2=SC_thSCD2) on the last frame in
duplicate run, and the frame following a run of duplicates, then it will also drop down to Blend
mode, using the Start Unique frame and frame BEFORE End Unique frame as the source frames of blend. In addition, if the End Unique frame is NOT
a scene change, but it is too different to the Start Unique frame (via DifByN2 and Th2), then it will again drop to blend mode but using the
End Unique frame as a blend source frame (DifByN2 and Th2 work in exactly the same way as previously noted for DifByN and Th).
Args:-
DifByN, Default -1. -1 or greater. Frame comparison mode selection and thresh arg to RT_LumaPixelsDifferent() function (when DifByN >= 0).
Th, Default 0.0, A difference Threshold for value returned by either RT_FrameDifference or RT_LumaPixelsDifferent() to determine duplicate
status of a frame.
DifByN == -1 : Uses RT_FrameDifference as measure.
DifByN >= 0 : Uses RT_LumaPixelsDifferent as measure.
DifByN and Th are used to establish duplicate status of a frame, if result of above DifByN selected function is <= Th, then frames are
judged to be same (dupe).
By default it looks for Indentical frame dupes.
DifByN2, Default -1. -1 or greater. Frame comparison mode selection and thresh arg to RT_LumaPixelsDifferent() function (when DifByN2 >= 0).
Th2, Default 16.0, 0.0 or more. Th2 MUST be greater than Th if DifByN2 comparison mode selection is the same as DifByN.
DifByN2 and Th2 work in exactly the same way as DifByN and Th.
Th2 is a difference Threshold for value returned by either RT_FrameDifference or RT_LumaPixelsDifferent() to determine
if the duplicate run Unique Start frame is too different to the Unique End frame (that follows a run of duplicates).
If the Unique End frame IS too different to the Unique Start frame, then switches down to blend mode for the current run of dupes.
CW, Default 1.0/3.0, 0.0->1.0. ChromaWeight arg to RT_FrameDiffernce (if DifbyN or DifByN2 are -1), 0.0 = Luma only.
MaxInterp, Default 3, 0 -> 9. Maximum number of frames that may be Interpolated.
Stack, default False, If True show StackVertical the difference between current frame and its predecessor. Switched off if Show is false.
Show, Default False. Show some metrics stuff if true. Switched off if ForceProcess = true.
ForceProcess, Default false. If true then scan entire clip doing the dupe blend replacement automatically, and then return result when
completed. Will take time to scan entire clip. Auomatically switches OFF Show and Stack when ForceProcess = true.
Verbose, Default False. Show some args if true and Show=True.
pel, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=1 or 2 or 4
sharp, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=0 -> 2
rfilter, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=0 -> 4
ml Default 100.0, MvTools arg to MFlowInter() for interpolation. See MvTools. range=greater than 0.0.
SC_thSCD1 Default 400, MvTools arg to MSCDetection(thSCD1) for scene change detection. See MvTools.range = 0->(8*8)*255
SC_thSCD2 Default 130, MvTools arg to MSCDetection(thSCD2) for scene change detection. See MvTools.range = 0-> 255
######
Metrics shown:-
nnnn] UDSIB {a/b} : RunCount=c : RunMax=d
Prev->Curr = fff.ffffff
FrameDif = fff.ffffff (Unique<->n, DifByN)
RunDif = fff.ffffff (Unique<->Unique, DifByN2)
BlendWeight= fff.ffffff
Where,
nnnn, = Frame Number
Flags UDSIB (where hi-lited)
U = Unique frame (not at duplicate)
D = Duplicate.
S = Scene Change follows duplicate run.
I = Interpolate mode used.
B = Blend mode used.
{a/b} = a'th frame in run of b dupes.
RunCount=c, = Number of duplicate runs encountered so far.
RunMax =d, = length of longest duplicate run encountered so far.
Prev->Curr = DifByN metric difference between current frame and its predecessor.
FrameDif = DifByN metric difference between Unique Start frame and current duplicate frame. (Only shown for Duplicates)
RunDif = DifByN2 metric difference between Unique Start frame and Unique End frame following duplicate run. (Only shown for Duplicates)
BlendWeight = Weight arg to Merge() two frames in blend mode. (Only shown for Blended Duplicates)
*/
EDIT: Added stuff in BLUE
EDIT: I'm not sure how useful the DifByN>=0 (not the DifByN2) mode will be, consider it experimental, no harm to leave it
as it is. DifByN2 mode though is possibly of some use, eg DifByN2=8, Th=50.0, would switch down to Blend mode
when 1/2 of End Unique frame pixels are different to the Start Unique frame by 8 or more luma levels.
StainlessS
17th April 2016, 22:29
MorphDupes_MI.avs Part 2 of 2 (Too big, Copy/Paste together)
c
myName="MorphDupes_MI: "
Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337")
Assert(RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846")
Assert(RT_FunctionExist("CallCmd"),myName+"Essential CallCmd plugin installed, http://forum.doom9.org/showthread.php?t=166063")
Assert(RT_FunctionExist("ForceProcessAVI"),myName+"Essential TWriteAVI plugin installed, http://forum.doom9.org/showthread.php?t=172837")
Assert(RT_FunctionExist("MSuper"),myName+"Essential MvTools v2 plugin installed, http://forum.doom9.org/showthread.php?t=131033")
DifByN = Default(DifByN,-1)
Th = Float(Default(Th, 0.000))
DifByN2= Default(DifByN2,-1)
Th2 = Float(Default(Th2,16.000))
CW = Float(Default(CW,1.0/3.0))
MaxInterp= Default(MaxInterp,3)
ForceProcess = Default(ForceProcess, false)
Show = !ForceProcess && Default(Show, false)
Stack = Show && Default(Stack, false)
Verbose= Show && Default(Verbose, false)
pel = Default(pel,2)
sharp = Default(sharp,2)
rfilter= Default(rfilter,2)
ml = Float(default(ml,100.0))
SC_thSCD1=Default(SC_thSCD1,400)
SC_thSCD2=Default(SC_thSCD2,130)
Assert(!IsRGB,RT_String("%sYUV only",myName))
Assert(DifByN>=-1,RT_String("%s-1 <= DifByN(%d)",myName,DifByN))
Assert(Th>=0.0,RT_String("%s0.0 <= Th(%f)",myName,Th))
Assert(DifByN2>=-1,RT_String("%s-1 <= DifByN2(%d)",myName,DifByN2))
Assert(Th2>Th || DifByN2 > DifByN || (DifByN<0&&DifByN2>0)||(DifByN>0&&DifByN2<0),RT_String("%sTh < Th2(%f) when similar type Thresholds",myName,Th2))
Assert(CW>=0.0 && CW <= 1.0,RT_String("%s0.0 <= CW <= 1.0(%f)",myName,CW))
Assert(MaxInterp>=0 && MaxInterp<=9,RT_String("%sMaxInterp 0 -> 9(%d)",myName,MaxInterp))
In = c
c = Stack ? StackVertical(c,c) : c
DB = RT_GetFullPathName("~"+RT_LocalTimeString+".DB")
/* Fields
0) Status, 0=Unknown (unvisited), 1 = Unique frame, 2 = Duplicate of prev frame.
1) 1 = Replace Duplicate (valid for Status Dupe Frames only), else 0.
2) Dupe Start Unique, (valid for Status Dupe Frames only). Set ALWAYS when Status is 2 (Dupilcate) All following dupes are duplicate of THIS.
3) Dupe End Unique, (valid for Status Dupe Frames only). Set ALWAYS when Status is 2 (Dupilcate)
Either end of both Unknown and Duplicate, are ALWAYS partitioned with at least a single Unique frame. Frames 0 and FrameCount-1
are always Unique.
*/
RT_DBaseAlloc(DB,FrameCount,"iiii")
RT_DBaseSetField(DB,0,0,1) RT_DBaseSetField(DB,FrameCount-1,0,1) # Set first and Last Frames to Unique Frame
FmtU = "%d] U\aGDSIB\a- \aG{1/1}\a- : RunCnt=%d : RunMax=%d\nPrev->Curr = %f"
FmtV = RT_string("DifByN =%d : Th =%f\nDifByN2 =%d : Th2=%f\nMaxInterp=%d",DifByN,Th,DifByN2,Th2,MaxInterp)
FmtDBS="%d] \aGU\a-DS\aGI\a-B {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\nFrameDif =%10.6f (Unique<->n, DifByN)\n" +
\ "RunDif =\a%c%10.6f\a- (Unique<->Unique, DifByN2)\nBlendWeight=%10.6f"
FmtDB="%d] \aGU\a-D\aGSI\a-B {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\nFrameDif =%10.6f (Unique<->n, DifByN)\n" +
\ "RunDif =\a%c%10.6f\a- (Unique<->Unique, DifByN2)\nBlendWeight=%10.6f"
FmtDI="%d] \aGU\a-D\aGS\a-I\aGB\a- {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\n" +
\ "FrameDif =%10.6f (Unique<->n, DifByN)\nRunDif =%10.6f (Unique<->Unique, DifByN2)"
FuncS="""
Function Fn@@@(clip clp,String DB,Int DifByN,Float Th,Int DifByN2,Float Th2,Float CW,Int MaxInterp,Bool Stack,Bool Show,Bool Verbose,
\ String FmtU,String FmtV,String FmtDBS,String FmtDB,String FmtDI) {
clp = Stack ? clp.Crop(0,0,-0,clp.Height/2): clp
clp n = current_frame
Status = RT_DBaseGetField(DB,n,0)
if(Show || Status != 1) { # In here if Show or NOT Unique Frame (ie dupe or unvisited)
if(Show || Status==0) { # Show or Unknown Status
# Diff Prev <-> Curr
fd_p = (DifByN<0)
\ ? RT_FrameDifference(Last,Last,n=n,n2=n-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=n,n2=n-1,Thresh=DifByN)
if(fd_p > Th) { # Is Unique frame
if(Status != 1) { # Unvisited
# Assert(Status==0,RT_String("Status Not 0(%d:%f)",Status,fd_p))
RT_DBaseSetField(DB,n,0,1) # Set Unique Status
Status = 1
}
} else { # Dupe
FC=FrameCount
# Assert(Status!=1 || n==0 || n==FC-1,RT_String("Status Is 1 (%d:%f)",Status,fd_p))
if(Status==0) {
# We MUST first scan backwards to find frame that is Unique to its predecessor (we are not necessarily a dupe of that frame)
StartU=n
for(i=n-1,0,-1) { # Exit with i==-1 (should NEVER HAPPEN, frame 0 is Unique)
Stat = RT_DBaseGetField(DB,i,0)
# Assert(Stat==0 || Stat==1,"Stat out of bounds (not 0 or 1)")
StartU = i
if(Stat==0) { # Status Unknown
fd = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=i,n2=i-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=i,n2=i-1,Thresh=DifByN)
if(fd > Th) {
RT_DBaseSetField(DB,i,0,1) # Set Unique Status, Following frames are dupe of this
i = -1 # Break, Exit with i==-2
}
} Else {
i = -2 # Break, Exit with i==-3
}
}
# Assert(i!=-1,"Stat Not Found backwards")
EndU = n
for(i=n+1,FC-1) { # Exit with i==FC (should NEVER HAPPEN, last frame is Unique)
Stat = RT_DBaseGetField(DB,i,0)
# Assert(Stat==0 || Stat==1,"Stat out of bounds (not 0 or 1)")
EndU = i
if(Stat==0) { # Status Unknown
fd = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=i,n2=i-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=i,n2=i-1,Thresh=DifByN)
if(fd > Th) {
RT_DBaseSetField(DB,i,0,1) # Set Unique Status
i = FC # Break, Exit with i==FC=+1
}
} Else {
i = FC+1 # Break, Exit with i==FC+2
}
}
# Assert(i > FC,"Stat Not Found forwards")
for(i=StartU+1,EndU-1) {
RT_DBaseSet(DB,i,2,1,StartU,EndU) # Set Dupe of Predecessor Status
}
}
Status=2
}
}
Replace = RT_DBaseGetField(DB,n,1)
if(Replace==1) {
StartU = RT_DBaseGetField(DB,n,2)
EndU = RT_DBaseGetField(DB,n,3)
frames = EndU-StartU-1
Global RunCnt@@@=(n==StartU+1) ? RunCnt@@@+1 : RunCnt@@@
Global RunMax@@@=Max(RunMax@@@,frames)
Pos = n-StartU
SC = (SC@@@.RT_AverageLuma(n=EndU,W=1,H=1) != 0) # EndU is Scene Change Start Of New Scene
FrmDif = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=StartU,n2=n,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=StartU,n2=n,Thresh=DifByN)
Dif2 = (DifByN2<0)
\ ? RT_FrameDifference (Last,Last,n=StartU,n2=EndU,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=StartU,n2=EndU,Thresh=DifByN2)
TooDif=(Dif2>Th2)
Blend = (SC || TooDif|| Frames > MaxInterp)
if(Blend) {
if(SC) {
Weight = 1.0 * Pos / Frames
Last = Merge(clp.Trim(StartU,-1),clp.Trim(EndU-1,-1),Weight)
(Show)?RT_Subtitle(FmtDBS,n,pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,TooDif?33:45,Dif2,Weight) : NOP
} else {
Weight = 1.0 * Pos / (Frames+1)
Last = Merge(clp.Trim(StartU,-1),clp.Trim(EndU,-1),Weight)
(Show)?RT_Subtitle(FmtDB,n,Pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,TooDif?33:45,Dif2,Weight) : NOP
}
} else {
Eval(RT_String("Last = I%0.2d_%0.2d@@@.Trim(%d,-1)",Frames,n-StartU,StartU))
(Show)?RT_Subtitle(FmtDI,n,Pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,Dif2) : NOP
}
}
if(Show) {
(Replace!=1) ? RT_subtitle(FmtU,n,RunCnt@@@,RunMax@@@,fd_p) : NOP
(Verbose) ? RT_Subtitle("%s",FmtV,Align=1) : NOP
(Stack) ? StackVertical(Last, Subtract(clp.Trim(n-1,-1),clp.Trim(n,-1))) : Last
}
} # End (Show || Status)
Return Last
}
#######################################
# Unique Global Variables Initialization
#######################################
Global RunMax@@@=0 Global RunCnt@@@=0
thSCD1=(8*8)*255 thSCD2=255 BLEND=False bs=(In.width>960) ? 16 : 8
supFilt = In.Blur(0.6).MSuper(pel=2,sharp=sharp,rfilter=rfilter,hpad=16, vpad=16)
sup = In.MSuper(pel=2,sharp=sharp,rfilter=rfilter,hpad=16, vpad=16, levels=1)
SC_fv=supFilt.MAnalyse(isb=false, delta=1,blksize=bs,overlap=bs/2)
SC_fv=MRecalculate(sup,SC_fv,blksize=bs/2,overlap=bs/4,thSAD=100)
Global SC@@@=In.MSCDetection(SC_fv,thSCD1=SC_thSCD1,thSCD2=SC_thSCD2)
For(Bad=1,MaxInterp) {
Eval(RT_String("I%0.2d_bv=supFilt.MAnalyse(isb=true, delta=%d,blksize=bs,overlap=bs/2)",Bad,Bad+1))
Eval(RT_String("I%0.2d_fv=supFilt.MAnalyse(isb=false,delta=%d,blksize=bs,overlap=bs/2)",Bad,Bad+1))
Eval(RT_String("I%0.2d_bv=MRecalculate(sup,I%0.2d_bv,blksize=bs/2,overlap=bs/4,thSAD=100)",Bad,Bad))
Eval(RT_String("I%0.2d_fv=MRecalculate(sup,I%0.2d_fv,blksize=bs/2,overlap=bs/4,thSAD=100)",Bad,Bad))
for(i=1,Bad) {
Eval(RT_String("Global I%0.2d_%0.2d@@@=In.MFlowInter(sup,I%0.2d_bv,I%0.2d_fv,time=100.0*%d/%d,ml=ml,Blend=BLEND,thSCD1=thSCD1,thSCD2=thSCD2)",
\ Bad,i,Bad,Bad,i,Bad+1))
}
}
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "DB,DifByN,Th,DifByN2,Th2,CW,MaxInterp,Stack,Show,Verbose,FmtU,FmtV,FmtDBS,FmtDB,FmtDI"
c.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS)
"""
#######################################
# Unique Identifier Definition
#######################################
GIFunc="MorphDupes_MI" # Function Name, Supply unique name for your multi-instance function.
GIName=GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(FuncS,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS)
GScript(InstS)
(ForceProcess) ? ForceProcessAVI : NOP
CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7) # Auto delete DB file on clip closure.
Return Last
}
bcn_246
8th August 2016, 08:09
Thankyou so much guys!
StainlessS
6th March 2018, 06:50
Bugfix in script 2 posts previous.
No effect really, as bug was in a commented out Assert.
Changes in blue
FC=FrameCount # Moved before next line
# Assert(Status!=1 || n==0 || n==FC-1,RT_String("Status Is 1 (%d:%f)",Status,fd_p)) # Blue added
Lirk
22nd July 2018, 09:08
StainlessS, can you optimize this script for x64 system? Some plugins from this script are not available for x64.
StainlessS
22nd July 2018, 09:28
As time (& capability) permits I am converting all to x64 (unfortunately, me gots bout 100 projects currently active :( )
Currently, I think only CallCmd not implemented in x64, and also TWriteAVI v2.0, CallCmd no real problem, in fact probably
just needs changed headers and a bit of fiddling, and should be OK.
TWriteAVI however, is beyond me, I identified about 4 problems in source, (1 fixed here locally), but other 3 I have no idea
how to approach, (2 I think were CPP related, I aint a CPP programmer), and 1 was the fact that there is a lot of x86
ASM used, me dont talk dat lingo, so no go. Maybe someone else more at home with CPP and x86 ASM could have a bash.
StainlessS
22nd July 2018, 10:21
Lirk, see below requirements for v1.10. [should be workable on x64]
EDIT: There were a couple of bug fixes in Duplicity script, here:- https://forum.doom9.org/showthread.php?t=175357&highlight=duplicity
MorphDupes_MI_1.10.avs Part 1 of 2 (Too big, Copy/Paste together)
Function MorphDupes_MI(clip c, Int "DifbyN",Float "Th",Int "DifbyN2",Float "Th2",Float "CW",Int "MaxInterp",
\ Bool "Stack", bool "Show", Bool "ForceProcess",Bool "Verbose",
\ int "pel",int "sharp",int "rfilter",Float "ml",Int "SC_thSCD1",Int "SC_thSCD2") {
/*
MorphDupes_MI v1.10, by StainlessS. http://forum.doom9.org/showthread.php?p=1764865#post1764865
Finds runs of duplicates and replaces them with either Interpolated or blended frames.
Planar, YUY2. Audio, no change. Multi-Instance capable.
Plugins:-
MvTools (c) Manoa/Fizick & Others :
GScript and Grunt (c) Gavino,
RT_Stats, TWriteAVI v2.0, CallCmd, (c) StainlessS.
Either AVS+ or GScript plugin required.
Can only use ForceProcess=True if TWriteAVI v2.0 is installed.
Will Auto Delete temp DBase file if CallCmd is installed, otherwise user has to delete manually.
MorphDupes_MI(clip c, Int "DifbyN"=-1,Float "Th"=0.0,Int "DifbyN2"=-1,Float "Th2"=16.0,Float "CW"=1.0/3,Int "MaxInterp"=3,
\ Int "Stack"=False, bool "Show"=False,Bool "ForceProcess"=False,Bool "Verbose"=False,
\ int "pel"=2,int "sharp"=2,int "rfilter"=2,Float "ml"=100.0,Int "SC_thSCD1"=400,Int "SC_thSCD2"=130)
There are two Difference measuring options to measure whether a frame is a duplicate or not and switched via DifByN, if DifByN is -1 (default),
then uses RT_FrameDifference function (together with CW=ChromaWeight setting, default 1.0/3, 0.0=Luma only) and Th threshold to determine
duplicate status. RT_FrameDifference returns the average pixel difference for the two comparison frames.
If DifByN is >= 0, then switches to using RT_LumaPixelsDifferent(Thresh=DifByN) where DifByN is also a control arg to
RT_LumaPixelsDifferent. RT_LumaPixelsDifferent returns the percentage of pixels where the luma difference between corresponding pixels is
greater than a threshold (DifByN). If the difference measure between current frame and it's predecessor (measured via RT_Framedifference or
RT_LumaPixelsDifferent) is <= Th, then it is deemed a duplicate frame.
Elsewhere we use the term 'Unique Start' frame, this is the frame at head of run of dupes [the frame of which others are a copy], and unique in
that it is different from its predecessor.
Frames Determined to be Duplicates:
For frames that are determined to be duplicates, there are two modes of operation, Interpolation, and Blend, the two modes are partly user
adjustable and partly automatic. MaxInterp (default 3) governs the greatest number of duplicate frames that can be Interpolated, setting it to 0
will be always in Blend mode. If a Scene change is detected via mvtools MSCDetection(thSCD1=SC_thSCD1,thSCD2=SC_thSCD2) on the last frame in
duplicate run, and the frame following a run of duplicates, then it will also drop down to Blend
mode, using the Start Unique frame and frame BEFORE End Unique frame as the source frames of blend. In addition, if the End Unique frame is NOT
a scene change, but it is too different to the Start Unique frame (via DifByN2 and Th2), then it will again drop to blend mode but using the
End Unique frame as a blend source frame (DifByN2 and Th2 work in exactly the same way as previously noted for DifByN and Th).
Args:-
DifByN, Default -1. -1 or greater. Frame comparison mode selection and thresh arg to RT_LumaPixelsDifferent() function (when DifByN >= 0).
Th, Default 0.0, A difference Threshold for value returned by either RT_FrameDifference or RT_LumaPixelsDifferent() to determine duplicate
status of a frame.
DifByN == -1 : Uses RT_FrameDifference as measure.
DifByN >= 0 : Uses RT_LumaPixelsDifferent as measure.
DifByN and Th are used to establish duplicate status of a frame, if result of above DifByN selected function is <= Th, then frames are
judged to be same (dupe).
By default it looks for Indentical frame dupes.
DifByN2, Default -1. -1 or greater. Frame comparison mode selection and thresh arg to RT_LumaPixelsDifferent() function (when DifByN2 >= 0).
Th2, Default 16.0, 0.0 or more. Th2 MUST be greater than Th if DifByN2 comparison mode selection is the same as DifByN.
DifByN2 and Th2 work in exactly the same way as DifByN and Th.
Th2 is a difference Threshold for value returned by either RT_FrameDifference or RT_LumaPixelsDifferent() to determine
if the duplicate run Unique Start frame is too different to the Unique End frame (that follows a run of duplicates).
If the Unique End frame IS too different to the Unique Start frame, then switches down to blend mode for the current run of dupes.
CW, Default 1.0/3.0, 0.0->1.0. ChromaWeight arg to RT_FrameDiffernce (if DifbyN or DifByN2 are -1), 0.0 = Luma only.
MaxInterp, Default 3, 0 -> 9. Maximum number of frames that may be Interpolated.
Stack, default False, If True show StackVertical the difference between current frame and its predecessor. Switched off if Show is false.
Show, Default False. Show some metrics stuff if true. Switched off if ForceProcess = true.
ForceProcess, Default false. If true then scan entire clip doing the dupe blend replacement automatically, and then return result when
completed. Will take time to scan entire clip. Auomatically switches OFF Show and Stack when ForceProcess = true.
Verbose, Default False. Show some args if true and Show=True.
pel, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=1 or 2 or 4
sharp, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=0 -> 2
rfilter, Default 2, MvTools arg to MSuper() for interpolation. See MvTools. range=0 -> 4
ml Default 100.0, MvTools arg to MFlowInter() for interpolation. See MvTools. range=greater than 0.0.
SC_thSCD1 Default 400, MvTools arg to MSCDetection(thSCD1) for scene change detection. See MvTools.range = 0->(8*8)*255
SC_thSCD2 Default 130, MvTools arg to MSCDetection(thSCD2) for scene change detection. See MvTools.range = 0-> 255
######
Metrics shown:-
nnnn] UDSIB {a/b} : RunCount=c : RunMax=d
Prev->Curr = fff.ffffff
FrameDif = fff.ffffff (Unique<->n, DifByN)
RunDif = fff.ffffff (Unique<->Unique, DifByN2)
BlendWeight= fff.ffffff
Where,
nnnn, = Frame Number
Flags UDSIB (where hi-lited)
U = Unique frame (not at duplicate)
D = Duplicate.
S = Scene Change follows duplicate run.
I = Interpolate mode used.
B = Blend mode used.
{a/b} = a'th frame in run of b dupes.
RunCount=c, = Number of duplicate runs encountered so far.
RunMax =d, = length of longest duplicate run encountered so far.
Prev->Curr = DifByN metric difference between current frame and its predecessor.
FrameDif = DifByN metric difference between Unique Start frame and current duplicate frame. (Only shown for Duplicates)
RunDif = DifByN2 metric difference between Unique Start frame and Unique End frame following duplicate run. (Only shown for Duplicates)
BlendWeight = Weight arg to Merge() two frames in blend mode. (Only shown for Blended Duplicates)
*/
StainlessS
22nd July 2018, 10:23
MorphDupes_MI_1.10.avs Part 2 of 2
c
myName="MorphDupes_MI: "
IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
HasCallCmd=RT_FunctionExist("CallCmd") HasTWriteAVI=RT_FunctionExist("ForceProcessAVI")
Assert(IsAvsPlus || HasGScript,RT_String("%sNeed either GScript or AVS+",myName))
Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337")
Assert(RT_FunctionExist("MSuper"),myName+"Essential MvTools v2 plugin installed, http://forum.doom9.org/showthread.php?t=131033")
DifByN = Default(DifByN,-1)
Th = Float(Default(Th, 0.000))
DifByN2= Default(DifByN2,-1)
Th2 = Float(Default(Th2,16.000))
CW = Float(Default(CW,1.0/3.0))
MaxInterp= Default(MaxInterp,3)
ForceProcess = Default(ForceProcess, false)
Show = !ForceProcess && Default(Show, false)
Stack = Show && Default(Stack, false)
Verbose= Show && Default(Verbose, false)
pel = Default(pel,2)
sharp = Default(sharp,2)
rfilter= Default(rfilter,2)
ml = Float(default(ml,100.0))
SC_thSCD1=Default(SC_thSCD1,400)
SC_thSCD2=Default(SC_thSCD2,130)
Assert(!IsRGB,RT_String("%sYUV only",myName))
Assert(DifByN>=-1,RT_String("%s-1 <= DifByN(%d)",myName,DifByN))
Assert(Th>=0.0,RT_String("%s0.0 <= Th(%f)",myName,Th))
Assert(DifByN2>=-1,RT_String("%s-1 <= DifByN2(%d)",myName,DifByN2))
Assert(Th2>Th || DifByN2 > DifByN || (DifByN<0&&DifByN2>0)||(DifByN>0&&DifByN2<0),RT_String("%sTh < Th2(%f) when similar type Thresholds",myName,Th2))
Assert(CW>=0.0 && CW <= 1.0,RT_String("%s0.0 <= CW <= 1.0(%f)",myName,CW))
Assert(MaxInterp>=0 && MaxInterp<=9,RT_String("%sMaxInterp 0 -> 9(%d)",myName,MaxInterp))
Assert(!ForceProcess || HasTWriteAVI,myName+"TWriteAVI v2.0 plugin required for ForceProcess.")
In = c
c = Stack ? StackVertical(c,c) : c
DB = RT_GetFullPathName("~"+RT_LocalTimeString+".DB")
/* Fields
0) Status, 0=Unknown (unvisited), 1 = Unique frame, 2 = Duplicate of prev frame.
1) 1 = Replace Duplicate (valid for Status Dupe Frames only), else 0.
2) Dupe Start Unique, (valid for Status Dupe Frames only). Set ALWAYS when Status is 2 (Dupilcate) All following dupes are duplicate of THIS.
3) Dupe End Unique, (valid for Status Dupe Frames only). Set ALWAYS when Status is 2 (Dupilcate)
Either end of both Unknown and Duplicate, are ALWAYS partitioned with at least a single Unique frame. Frames 0 and FrameCount-1
are always Unique.
*/
RT_DBaseAlloc(DB,FrameCount,"iiii")
RT_DBaseSetField(DB,0,0,1) RT_DBaseSetField(DB,FrameCount-1,0,1) # Set first and Last Frames to Unique Frame
FmtU = "%d] U\aGDSIB\a- \aG{1/1}\a- : RunCnt=%d : RunMax=%d\nPrev->Curr = %f"
FmtV = RT_string("DifByN =%d : Th =%f\nDifByN2 =%d : Th2=%f\nMaxInterp=%d",DifByN,Th,DifByN2,Th2,MaxInterp)
FmtDBS="%d] \aGU\a-DS\aGI\a-B {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\nFrameDif =%10.6f (Unique<->n, DifByN)\n" +
\ "RunDif =\a%c%10.6f\a- (Unique<->Unique, DifByN2)\nBlendWeight=%10.6f"
FmtDB="%d] \aGU\a-D\aGSI\a-B {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\nFrameDif =%10.6f (Unique<->n, DifByN)\n" +
\ "RunDif =\a%c%10.6f\a- (Unique<->Unique, DifByN2)\nBlendWeight=%10.6f"
FmtDI="%d] \aGU\a-D\aGS\a-I\aGB\a- {%d/%d} : RunCnt=%d : RunMax=%d\nPrev->Curr =%10.6f\n" +
\ "FrameDif =%10.6f (Unique<->n, DifByN)\nRunDif =%10.6f (Unique<->Unique, DifByN2)"
FuncS="""
Function Fn@@@(clip clp,String DB,Int DifByN,Float Th,Int DifByN2,Float Th2,Float CW,Int MaxInterp,Bool Stack,Bool Show,Bool Verbose,
\ String FmtU,String FmtV,String FmtDBS,String FmtDB,String FmtDI) {
clp = Stack ? clp.Crop(0,0,-0,clp.Height/2): clp
clp n = current_frame
Status = RT_DBaseGetField(DB,n,0)
if(Show || Status != 1) { # In here if Show or NOT Unique Frame (ie dupe or unvisited)
if(Show || Status==0) { # Show or Unknown Status
# Diff Prev <-> Curr
fd_p = (DifByN<0)
\ ? RT_FrameDifference(Last,Last,n=n,n2=n-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=n,n2=n-1,Thresh=DifByN)
if(fd_p > Th) { # Is Unique frame
if(Status != 1) { # Unvisited
# Assert(Status==0,RT_String("Status Not 0(%d:%f)",Status,fd_p))
RT_DBaseSetField(DB,n,0,1) # Set Unique Status
Status = 1
}
} else { # Dupe
# Assert(Status!=1 || n==0,RT_String("Status Is 1 (%d:%f)",Status,fd_p))
if(Status==0) {
# We MUST first scan backwards to find frame that is Unique to its predecessor (we are not necessarily a dupe of that frame)
StartU=n
for(i=n-1,0,-1) { # Exit with i==-1 (should NEVER HAPPEN, frame 0 is Unique)
Stat = RT_DBaseGetField(DB,i,0)
# Assert(Stat==0 || Stat==1,"Stat out of bounds (not 0 or 1)")
StartU = i
if(Stat==0) { # Status Unknown
fd = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=i,n2=i-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=i,n2=i-1,Thresh=DifByN)
if(fd > Th) {
RT_DBaseSetField(DB,i,0,1) # Set Unique Status, Following frames are dupe of this
i = -1 # Break, Exit with i==-2
}
} Else {
i = -2 # Break, Exit with i==-3
}
}
# Assert(i!=-1,"Stat Not Found backwards")
FC=FrameCount
EndU = n
for(i=n+1,FC-1) { # Exit with i==FC (should NEVER HAPPEN, last frame is Unique)
Stat = RT_DBaseGetField(DB,i,0)
# Assert(Stat==0 || Stat==1,"Stat out of bounds (not 0 or 1)")
EndU = i
if(Stat==0) { # Status Unknown
fd = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=i,n2=i-1,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=i,n2=i-1,Thresh=DifByN)
if(fd > Th) {
RT_DBaseSetField(DB,i,0,1) # Set Unique Status
i = FC # Break, Exit with i==FC=+1
}
} Else {
i = FC+1 # Break, Exit with i==FC+2
}
}
# Assert(i > FC,"Stat Not Found forwards")
for(i=StartU+1,EndU-1) {
RT_DBaseSet(DB,i,2,1,StartU,EndU) # Set Dupe of Predecessor Status
}
}
Status=2
}
}
Replace = RT_DBaseGetField(DB,n,1)
if(Replace==1) {
StartU = RT_DBaseGetField(DB,n,2)
EndU = RT_DBaseGetField(DB,n,3)
frames = EndU-StartU-1
Global RunCnt@@@=(n==StartU+1) ? RunCnt@@@+1 : RunCnt@@@
Global RunMax@@@=Max(RunMax@@@,frames)
Pos = n-StartU
SC = (SC@@@.RT_AverageLuma(n=EndU,W=1,H=1) != 0) # EndU is Scene Change Start Of New Scene
FrmDif = (DifByN<0)
\ ? RT_FrameDifference (Last,Last,n=StartU,n2=n,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=StartU,n2=n,Thresh=DifByN)
Dif2 = (DifByN2<0)
\ ? RT_FrameDifference (Last,Last,n=StartU,n2=EndU,ChromaWeight=CW)
\ : RT_LumaPixelsDifferent(Last,Last,n=StartU,n2=EndU,Thresh=DifByN2)
TooDif=(Dif2>Th2)
Blend = (SC || TooDif|| Frames > MaxInterp)
if(Blend) {
if(SC) {
Weight = 1.0 * Pos / Frames
Last = Merge(clp.Trim(StartU,-1),clp.Trim(EndU-1,-1),Weight)
(Show)?RT_Subtitle(FmtDBS,n,pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,TooDif?33:45,Dif2,Weight) : NOP
} else {
Weight = 1.0 * Pos / (Frames+1)
Last = Merge(clp.Trim(StartU,-1),clp.Trim(EndU,-1),Weight)
(Show)?RT_Subtitle(FmtDB,n,Pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,TooDif?33:45,Dif2,Weight) : NOP
}
} else {
Eval(RT_String("Last = I%0.2d_%0.2d@@@.Trim(%d,-1)",Frames,n-StartU,StartU))
(Show)?RT_Subtitle(FmtDI,n,Pos,Frames,RunCnt@@@,RunMax@@@,fd_p,FrmDif,Dif2) : NOP
}
}
if(Show) {
(Replace!=1) ? RT_subtitle(FmtU,n,RunCnt@@@,RunMax@@@,fd_p) : NOP
(Verbose) ? RT_Subtitle("%s",FmtV,Align=1) : NOP
(Stack) ? StackVertical(Last, Subtract(clp.Trim(n-1,-1),clp.Trim(n,-1))) : Last
}
} # End (Show || Status)
Return Last
}
#######################################
# Unique Global Variables Initialization
#######################################
Global RunMax@@@=0 Global RunCnt@@@=0
thSCD1=(8*8)*255 thSCD2=255 BLEND=False bs=(In.width>960) ? 16 : 8
supFilt = In.Blur(0.6).MSuper(pel=2,sharp=sharp,rfilter=rfilter,hpad=16, vpad=16)
sup = In.MSuper(pel=2,sharp=sharp,rfilter=rfilter,hpad=16, vpad=16, levels=1)
SC_fv=supFilt.MAnalyse(isb=false, delta=1,blksize=bs,overlap=bs/2)
SC_fv=MRecalculate(sup,SC_fv,blksize=bs/2,overlap=bs/4,thSAD=100)
Global SC@@@=In.MSCDetection(SC_fv,thSCD1=SC_thSCD1,thSCD2=SC_thSCD2)
For(Bad=1,MaxInterp) {
Eval(RT_String("I%0.2d_bv=supFilt.MAnalyse(isb=true, delta=%d,blksize=bs,overlap=bs/2)",Bad,Bad+1))
Eval(RT_String("I%0.2d_fv=supFilt.MAnalyse(isb=false,delta=%d,blksize=bs,overlap=bs/2)",Bad,Bad+1))
Eval(RT_String("I%0.2d_bv=MRecalculate(sup,I%0.2d_bv,blksize=bs/2,overlap=bs/4,thSAD=100)",Bad,Bad))
Eval(RT_String("I%0.2d_fv=MRecalculate(sup,I%0.2d_fv,blksize=bs/2,overlap=bs/4,thSAD=100)",Bad,Bad))
for(i=1,Bad) {
Eval(RT_String("Global I%0.2d_%0.2d@@@=In.MFlowInter(sup,I%0.2d_bv,I%0.2d_fv,time=100.0*%d/%d,ml=ml,Blend=BLEND,thSCD1=thSCD1,thSCD2=thSCD2)",
\ Bad,i,Bad,Bad,i,Bad+1))
}
}
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "DB,DifByN,Th,DifByN2,Th2,CW,MaxInterp,Stack,Show,Verbose,FmtU,FmtV,FmtDBS,FmtDB,FmtDI"
c.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS)
"""
#######################################
# Unique Identifier Definition
#######################################
GIFunc="MorphDupes_MI" # Function Name, Supply unique name for your multi-instance function.
GIName=GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(FuncS,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS)
HasGScript ? GScript(InstS) : Eval(InstS) # Use GSCript if installed (loaded plugs override builtin)
(ForceProcess) ? ForceProcessAVI : NOP
# If CallCmd available then Auto delete DB file on clip closure, else user must delete.
(HasCallCmd) ? CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7) : NOP
Return Last
}
EDIT: Would be lovely if Avs+ supported Grunt stuff (GSCriptClip) builtin, long time needed :)
EDIT: Damn, it looks like it already does support (although under name Sciptclip instead of GScriptClip, [ie 'Args' & 'Local' args],
and also eg AverageLuma(clip c,int int i) for delta relative current_frame).
I'll do mod and update again in a little while to remove GRunt requirement for Avs+.
EDIT: Forget what I said about Grunt, seems we have problems with AVS+ replacing Grunt, will implement Gruntless script when possible.
Lirk
22nd July 2018, 14:53
StainlessS, I can't find TWriteAVI for x64. Can it run without this plugin?
StainlessS
22nd July 2018, 15:21
As I said in post #25, I dont know how to update TWriteAVI for x64, that aint likely to change.
However, as hi-lited in BLUE in post #26 [updated for you today]
Either AVS+ or GScript plugin required.
Can only use ForceProcess=True if TWriteAVI v2.0 is installed.
Will Auto Delete temp DBase file if CallCmd is installed, otherwise user has to delete manually.
So, dont need TWriteAVI, if not using ForceProcess=true.
You also dont need CallCmd, if not installed then will have to delete temp Dbase file manually.
All other plugins are available in x64, so you are pretty much good to go. :)
Lirk
22nd July 2018, 15:30
Script runs, but it doesn't work properly (threshold=0.1). Video has 2-3 dropped frames at once and metrics shows that they are detected but script return previous frame after dropped. Why by default threshold=0? Does this script generate blended frames as ConvertFPS, or interpolate it as SVPflow or MVTools?
Duplicity can only generate text file with dropped frames, or also can interpolate it?
It would be better to retain detection method from filldrops3 or gamedropfix_v5, but replace generation method from interpolate by MVTools to blend as in ConvertFPS.
StainlessS
23rd July 2018, 01:20
and metrics shows that they are detected but script return previous frame after dropped.
Can you clarify ? [works for me]
Why by default threshold=0?
Detects exact duplicates by default. [useful to me]
Does this script generate blended frames as ConvertFPS, or interpolate it as SVPflow or MVTools?
Can do either, as described in the docs (up to 9 [or MaxInterp, default 3] interpolated frames).
Metrics show what is being used.
nnnn] UDSIB {a/b}
Flags UDSIB (where hi-lited)
U = Unique frame (not at duplicate)
D = Duplicate.
S = Scene Change follows duplicate run.
I = Interpolate mode used.
B = Blend mode used.
{a/b} = a'th frame in run of b dupes.
This shows original frame, output frame, difference, and difference amplied.
# Return Clip Difference of input clips (amp==true = Amplified, show==true = show background)
Function ClipDelta(clip clip1,clip clip2,bool "amp",bool "show") {
amp=Default(amp,false)
show=Default(show,false)
c2=clip1.levels(128-32,1.0,128+32,128-32,128+32).greyscale()
c1=clip1.subtract(clip2)
c1=(amp)?c1.levels(127,1.0,129,0,255):c1
return (show)?c1.Merge(c2):c1
}
Import(".\MorphDupes_MI_1.10.avs")
AviSource(".\g.avi")
O=LAst
MorphDupes_Mi(Th=0.05,Show=true,Verbose=True)
D1=ClipDelta(Last,O)
D2=ClipDelta(Last,O,Amp=true)
TOP=StackHorizontal(O,Last)
BOT=StackHorizontal(D1,D2)
StackVertical(TOP,BOT)
/*
ORIGINAL # OUTPUT
##########################
OUT-ORG # OUT-ORG AMP'ed
*/
And by the way, CallCmd is actually available in 64 bit (did it back in April, forgot).
From Mediafire below in my sig,
EDIT: The purpose of MaxInterp (Default=3) and of Th2 (Default=16.0), is to prevent Interpolation and drop down to Blend mode.
I personally dont like when MvTools produces nasty swirly results due to differences between interpolation source frames being too
different from each other. If you dont care about producing the swirlies, then set MaxInterp=9 (max) and th2=255.0. then will use
Interpolation mode always (up to 9 interpolated frames, and drop down to blend mode if greater than 9 frames).
Setting MaxInterp=0, will always use blend mode.
(It kinda amazes me when people wanna interpolate 20 or 30 frames, blend mode is nearly always gonna be less awful result).
Lirk
24th July 2018, 09:51
Can you clarify ? [works for me]
https://www.mediafire.com/folder/qm6n7pp5x6udtq6,yc9tjtuu4hc68l5,7r9ypof5ejuvno8/shared
l-orig.mp4 - original
th(0).mp4 - th=0
th(0.1).mp4 - th=0.1
StainlessS
24th July 2018, 16:39
Thanks for the samples Lirk, a real pig of a clip I think.
MorphDupes_MI Frame 97 requires Th of at least 0.6, but then the very dark scene at beginning has no chance of being detected as moving.
Duplicity with ThG of 1.0 (will be new default) fairs better with your clip but only if ThL is bumped up from 8 to about 31,
frame 97 (although looks like dupe) has at least 1 luma pixel difference of about 30, thats a lot to accept as dupe.
EDIT: Even at Duplicity ThL of 8, there are 0.19% of pixels more than 8 luma levels different to corresponding pixels of prev frame.
EDIT: And 0.022% at ThL of 16.
Give me a little time to play with this.
StainlessS
5th August 2018, 16:13
Lirk, I see your there.
I have not forgotten you and had to mod Duplicity() to be able to cope with samples like the one you provided, when I've
got that in more final condition, I shall mod MorphDupes_MI and it should be way better than currently.
(RT_Stats v2.00 Beta_11 RT_FrameMovement is required for the better detection and so I could not really use it in earlier scripts, as not many would be
adventurous enough to use it, a real scaredy-cat bunch we got here).
StainlessS, is there any progress? :)
StainlessS
7th June 2019, 12:12
Lirk,
See Duplicity2, easily cope with your difficult clip.
https://forum.doom9.org/showthread.php?t=175357&highlight=Duplicity2
Lirk
11th June 2019, 14:28
Lirk,
See Duplicity2, easily copy with your difficult clip.
https://forum.doom9.org/showthread.php?t=175357&highlight=Duplicity2
And what parameters do I need to use?
StainlessS
11th June 2019, 20:35
Needed a little adjustment to ThB for your clip, (ThB=2.5, default ThG*2.0=2.0), your dupes are significantly different.
Frames showing higher than default,
57 block detect 2.035400
62 block detect 2.302979 # Block detect ThB must greater than this eg 2.5
Easiest probably to use MODE=0 for adjust settings, with STACK=True,Stack4=False.
ThG, never/almost never need change.
ThB, adjust higher if dupe is not flagged as dupe (a little higher than the metrics in Orange for aB).
ThP, probably never need change this emergency detect setting of 64 (for single moving pixel).
These setting detect your dupes perfectly.
Is set to detect up to 3 dupes. interpolating at most single dupe, blending if more than 1, you choose, Interpolations not brilliant especially lights glinting on very dark car bonnet.
Try with ShowDOT=true, to remove metrics and still show indicator on corrected frame.
Import(".\Duplicity2.Avsi")
######
FN = ".\Lirk.AVI" DBase = ".\Lirk_Det.DB"
######
Avisource(FN)
SRC=Last
###
Mode=2 # 0=Write Frames only : 1=Replace Dupes with Exact Dupes : 2= Interpolate/Blend Duplicates.
ThG=1.0 # 1.0, Primary Frame Global Detect
ThB=2.5 # ThG*2.0
ThP=64 # 64, Single Pixel Detect
MaxDupLen=3 # Max detected, if more then is considered static sequence not duplicate)
MaxInterp=1 # Max Interpolated frames when Mode=2 (More than MaxInterp & less or equal to MaxDupLen then uses Blend mode)
InterpFast=false
Show=True
ShowDot=false
ShowBlk=true
VERB=True
###
TITLE=true
STACK=True
STACK4=False
###
Result=SRC.Duplicity2(Mode=Mode,ThG=ThG,ThB=ThB,ThP=ThP,MaxDupLen=MaxDupLen,MaxInterp=MaxInterp,
\ Show=False,InterpFast=InterpFast,DBase=(STACK4||!SHOW)?DBase:"")
Metrics=SRC.Duplicity2(Mode=Mode,ThG=ThG,ThB=ThB,ThP=ThP,MaxDupLen=MaxDupLen,MaxInterp=MaxInterp,
\ Show=True,Verb=VERB,ShowBlk=ShowBlk,ShowDot=ShowDot,InterpFast=InterpFast,DBase=(STACK4||!SHOW)?"":DBase)
Dif=Subtract(Result,SRC)
SRC = (TITLE) ? SRC.TSub("Src") : SRC
Result = (TITLE) ? Result.TSub("Result") : Result
Metrics = (TITLE) ? Metrics.TSub("Metrics") : Metrics
Dif = (TITLE) ? Dif.TSub("Dif(Result,Src)") : Dif
LFT=StackVertical((STACK4||!SHOW)?Result:Metrics,SRC)
RGT=StackVertical(Metrics,Dif)
STK4=StackHorizontal(LFT,RGT)
(STACK4) ? STK4 : (STACK) ? LFT : (Show)?Metrics:Result
Return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo",Int "Col"){
c.BlankClip(height=20,Color=Default(Col,0))
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
All plugins available for x64.
I think I posted Duplicity2 script about 20 minutes after your last visit (which was maybe I think back in August 2018), so you just missed it.
EDIT: You might even want to try DropDeadGorgeous() with ScanAhead of about 5, might produce smoother result. (Use the same DBase as created by above script).
If you post on result, do it in Duplicity thread, thanx.
EDIT: The bad interpolations of black car in dark with bright glints, think maybe mvtools cannot lock well on scene (lots of black), so probably blending rather than interpolating,
maybe raise IthSCD2 from default 130 (although run risk of bad interp elsewhere when not dark scene).
If dont work, restore IthSC2 and try raise IthSC1.
EDIT: On 2nd thoughts, maybe just accept blends on the two black car lights glinting frames, best not mess up the others for the sake of two frames that will likely not get much[if any] better.
EDIT
Lirk, I see your there.
I have not forgotten you and had to mod Duplicity() to be able to cope with samples like the one you provided, when I've
got that in more final condition, I shall mod MorphDupes_MI and it should be way better than currently.
(RT_Stats v2.00 Beta_11 RT_FrameMovement is required for the better detection and so I could not really use it in earlier scripts, as not many would be
adventurous enough to use it, a real scaredy-cat bunch we got here).
Forget Morphdupes, Duplicity2 does all it does and better.
Lirk
12th June 2019, 13:29
Import(".\Duplicity2.Avsi")
######
FN = ".\Lirk.AVI" DBase = ".\Lirk_Det.DB"
######
Avisource(FN)
SRC=Last
###
Mode=2 # 0=Write Frames only : 1=Replace Dupes with Exact Dupes : 2= Interpolate/Blend Duplicates.
ThG=1.0 # 1.0, Primary Frame Global Detect
ThB=2.5 # ThG*2.0
ThP=64 # 64, Single Pixel Detect
MaxDupLen=3 # Max detected, if more then is considered static sequence not duplicate)
MaxInterp=1 # Max Interpolated frames when Mode=2 (More than MaxInterp & less or equal to MaxDupLen then uses Blend mode)
InterpFast=false
Show=True
ShowDot=false
ShowBlk=true
VERB=True
###
TITLE=true
STACK=True
STACK4=False
###
Result=SRC.Duplicity2(Mode=Mode,ThG=ThG,ThB=ThB,ThP=ThP,MaxDupLen=MaxDupLen,MaxInterp=MaxInterp,
\ Show=False,InterpFast=InterpFast,DBase=(STACK4||!SHOW)?DBase:"")
Metrics=SRC.Duplicity2(Mode=Mode,ThG=ThG,ThB=ThB,ThP=ThP,MaxDupLen=MaxDupLen,MaxInterp=MaxInterp,
\ Show=True,Verb=VERB,ShowBlk=ShowBlk,ShowDot=ShowDot,InterpFast=InterpFast,DBase=(STACK4||!SHOW)?"":DBase)
Dif=Subtract(Result,SRC)
SRC = (TITLE) ? SRC.TSub("Src") : SRC
Result = (TITLE) ? Result.TSub("Result") : Result
Metrics = (TITLE) ? Metrics.TSub("Metrics") : Metrics
Dif = (TITLE) ? Dif.TSub("Dif(Result,Src)") : Dif
LFT=StackVertical((STACK4||!SHOW)?Result:Metrics,SRC)
RGT=StackVertical(Metrics,Dif)
STK4=StackHorizontal(LFT,RGT)
(STACK4) ? STK4 : (STACK) ? LFT : (Show)?Metrics:Result
Return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo",Int "Col"){
c.BlankClip(height=20,Color=Default(Col,0))
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
Forget Morphdupes, Duplicity2 does all it does and better.
Why so many code in client script? Can it be replace to the main autoloading script?
StainlessS
12th June 2019, 15:14
Why so many code in client script?
To demo usage.
You only need set args that are not same as defaults autoload script.
If you dont want eg 4 window display, then create your own script without all the extra stuff.
Lirk
14th June 2019, 11:14
Is there way to use Duplicity2 just as function with parameters e.g. Duplicity2(show=true/false,...,other parameters)?
And I saw, this script interpolates only one dropped frame, but not 2-3 frames in a row.
StainlessS
14th June 2019, 15:43
Create your own script, set whatever parameters you wish, set to interpolate as many as you wish, (up to 9),
read the docs.
eg
Import(".\Duplicity2.Avsi") # or put it in your plugins.
Avisource(".\Lirk.AVI")
Duplicity2(Mode=2,ThB=2.5,MaxDupLen=MaxDupLen,MaxInterp=9)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.