View Full Version : How to synchronize two videos by comparing video frames
StainlessS
20th May 2015, 18:34
SilSic,
Here FFMatch in English, (via Google translate, with orig Italian):- http://www.mediafire.com/download/wbcy8q6w2arsjk2/FFMatch.7z
Temp link only.
Cannot re-use the Fingerprint Dbase as it is for a different pair of uncropped clips (would kinda make the cropping pointless, and searches would fail).
I will not be doing anything soon on this, I want to make changes to the SpatialAlign thing, and need to amend RT_Stats
FrameDifference etc to accomplish this. I shall not be on-line much until done.
Motenai Yoda
21st May 2015, 19:04
If I remember correctly ffmatch works on decoded frames, and should get avs input too (maybe mp3/ac3 too).
Limitations are that the videos and audios must be at the same speed and without interlace, blend or ghost artifacts.
So it's useful only on speeded up/down stuff (ie tv series) or same film/video with different mountage/edit.
SilSic
21st May 2015, 20:42
Here FFMatch in English, (via Google translate, with orig Italian)
Did that already but thx anyway ;)
It's now the first time I used a whole episode to check out the results.
I did only output wav and merged that wav with the original uncut clip. Unfortunately non sync.
I made a lot of tests and made all combinations possible which means swapped uncut and cut (Fn1 to Fn2/ Fn2 to Fn1)
I also changed DEST_FN1 from false to true to swap it the other way round to be really sure about this. No luck.
I figure out the cause of it. You wrote the whole stuff to fill the uncut clip with frames from the cut clip in any case
also doin the other way round to fill the cut clip with the uncut clip so no clip will keep to its original clip.
The uncut clip must be untouched for the cut clip to rearranges itself by referencing to the uncut clip(all additional frames of cut clip will be dumped).
Funny I told you yesterday about this approach, but still without knowing how actually Replacecuts processes the clips internally.
StainlessS
21st May 2015, 23:52
If I remember correctly ffmatch works on decoded frames
IIRC, said in docs that you need to re-encode into XVid if not already XV (a temporary step, uses XVid stats).
Motenai Yoda
22nd May 2015, 01:44
Indeed actually said thah you need to re-encode into XVid if not compatible, to use it as a temporal file to analyze.
Unlucky DE has gone down for too long
SilSic
28th May 2015, 14:12
By the way it is possible to display each values of a frame eg LumaDifference, FrameDifference, LumaPixelsDifferent, RT_LumaPixelsDifferent and all other values,
would help me a lot to adjust very fast. That's the part which takes me the most time to figure out.
Or what values eg LumaDifference, FrameDifference must get to to approve both clips similar. It would be a significant help.
How are you doing with upcoming update for Replacecuts StainlessS?
notice, there is no rush :)
StainlessS
28th May 2015, 17:24
Still taking time to do the update.
See DebugView for debug info.
You might want to try just FrameDifference flag.
EDIT: FrameDifference results were a lot better once clips were aligned
(should also be faster, LumaCorrelation is quite slow and Lumadifference makes it even slower).
LumaPixelsDifferent dont seem at all useful where frames are from different source.
StainlessS
30th May 2015, 12:47
Silsic, think I have decided to abandon the ReplaceCuts function and incorporate similar functionality into DBSC,
would make sense to do this as everything much simpler when broken up into scenes, spatial alignment
also simpler.
DBSC:- http://forum.doom9.org/showthread.php?t=171624
SilSic
30th May 2015, 15:49
I'm fine with that as long as it has the same functionality and doesn't need a whole reorientation for me(except you explain it ;)).
SilSic
12th July 2015, 19:17
Hey StainlessS, it's been a while ago and I'm wondering how are you getting on with the incorporation?
StainlessS
12th July 2015, 19:39
Still working my way towards it, slowly. Been adding enhancement to RT_FrameDifference lately, going lovely.
SilSic
13th July 2015, 22:49
What exactly do you yet need to do for completion? :)
StainlessS
14th July 2015, 08:56
Sorry, I dont have that much time available to tell you exactly.
I'm snowed under with stuff to do and that is only part of it. :)
SilSic
14th July 2015, 12:09
That's unfortunate. I wish you recreation!
PS: just be glad if you do a mere job without much enhancement "no-frills". Just something to begin with,
if your time allows. Relax and until then :)
StainlessS
14th July 2015, 16:51
Presently mobile.
Need good scene change detection and frame alignment so would be a waste of time to do anything until I can do that,no point in doing half a job only to have to do it again.
SilSic
18th July 2015, 15:25
Actually your scene change detection and frame alignment are already good enough. Teething troubles are mostly common in every kind of software.
Your scene change detection needs more likely to detect a spot/keyframe with a certain high accuracy to shift the whole clip to this very keyframe (makes yet no cut, only shifting)and to check every 5 minutes later if it is still sync, if it isn't sync the first cut will be made to shift again if necessary(better explained in previous post). 99% accuracy isn't always needed but appreciated.
I'm glad for your concern which wasn't naturally at the very beginning but keep in mind less is more ;)
loneboyz
30th July 2015, 03:59
Hi StainlessS,
I've read all your post, it's useful to me.
Actually, I'm having the same problem. I have two source PAL DVDs, Uncut and Cut. I want to make a script from Hybird source, purpose to use some frames from the Cut to Overlay the Uncut. So I must insert blank frame into the Cut but I don't know how to identify?
It's the first time for me and I see it'll very difficult. I don't know where to start and I need your some advices. Thanks a lot!
johnmeyer
30th July 2015, 15:15
I don't know where to start and I need your some advices.Are you asking for some sort of tutorial? That is asking too much. I think you need to ask specific questions if you hope to get any answers.
I've followed this thread, and my advice would be to use your NLE (your video editing software). Line up your two (or more captures) on the editing timeline, and then cut and slide the various tracks until they match. With a typical TV program that has six commercial inserts per hour, that would only be 6-12 cuts. You should be able to finish the job in a lot less time that it will take you to get all these scripts running.
I've done exactly this sort of thing for TV program collectors, and it works great. This approach also lets you deal with the situation where the audio is out of sync, or where the audio from one capture needs to be merged with the video from a different version of the same program. It even lets you mix PAL and NTSC versions, something I've had to do on many occasions.
My toughest assignment was to take a French film that didn't have English subtitles on the DVD, but did have them on an old VHS transfer. The VHS transfer was cut differently in several places, and the aspect ratio was 4:3 instead of 16:9. Using my NLE I put the VHS transfer on one timeline, created a mask which matched the color of the subtitles, and was able to overlay these onto the pristine DVD version. I tried to use one of the subtitle tools to actually extract the subtitles and put them on the DVD the "right" way (i.e., as a subtitle track), but since this version was from a YouTube download, the quality wasn't good enough to get reliable OCR. So, I had to "hard-wire" the subtitles into the video itself.
So, bottom line: use your NLE and get the job done in the next hour.
loneboyz
3rd August 2015, 04:10
Anyway, thanks @johnmeyer
I'm interesting Avisynth, I'll step by step to learning it, from easy to hard and I'm continuing
StainlessS
18th August 2015, 14:01
Silsic.
I shall complete this project when (and if) I complete it, no amount of prodding me by PM will change that, sorry.
SilSic
7th October 2015, 15:14
StainlessS you've got message from me ;)
Besides do you know someone who is as good as you?
StainlessS
7th October 2015, 17:50
Yes I know you sent me a series of messages which I two posts previously hinted that you should not repeat.
After that you sent me more, and then chided me for not answering your pesterings.
Then came your out and out bollockings for not answering, that is when I stopped taking any notice of your un-solicited,
and unwelcome PM's (definition of Junk Mail / SPAM).
I will under no circumstance answer any further PM from you, without your seeking prior permission to send, and there had better
be a better excuse that you just want to coerce me into doing your bidding.
Since my previous public answer to your question, you have sent me 3 more unwelcome PM's which I have not (as you know)
even opened, what do I have to do to make you aware that you are ************* me off.
It is always possible that I might at some future point mellow in my attitude to you, but I'm guessin it aint gonna happen terribly soon.
DO NOT use PM as a way of trying to force someone to do what you want, PM is for personal or sensitive stuff only, not to get you some kind
of personal service. You are not the only one to do this, I've had same problem before, but not by so persistent an offender.
EDIT: FYI, nobody I know feels obliged to answer junk mail.
StainlessS
4th November 2016, 01:52
Post 1 of Many.
Updated (slightly for RT_Stats v2.0 BETA 3 QwikScan Arrays instead of DBase).
# SpatialAlign.avs
Function SpatialAlign(clip Fix,clip Src,Int "MatchLen",Int "Rad",Float "LdTh",String "Prefix") {
/*
SpatialAlign v1.01: By StainlessS. http://forum.doom9.org/showthread.php?p=1722142#post1722142
Fix spatial alignment between two clips containing similar scenes (dont have to be temporally aligned).
Could take a Long time for long clips where they contain no common sequences.
Spatial mis-alignment should not be too great or may not find temporal (and therefore spatial) alignment.
Requires:- GScript, RT_stats v2.0 BETA 3, RoboCrop'ed before calling. DebugView for viewing debug info.
Frame Accurate Progressive sources of same Size, FrameRate, Colorspace.
Fix, clip to align with Src.
Src, clip that Fix clip will be spatially aligned to.
MatchLen, Default 50 frames. Number of frames that have to match when finding temporal alignment.
Rad, Default 4 (1 -> 6). Maxiumum number of pixels (H and V) that fix clip may be shifted by.
LdTh, Default 3.0 * Rad (ie 12.0 when Rad=Default 4), LumaDifference has to be less than or equal to this to detect temporal alignment.
Prefix, Default "SA_Crop_". Default sets Global Variables with "SA_Crop_" Prefix.
Sets variables "L", "T", "R" and "B", prefixed by the Prefix string, eg 'SA_Crop_L'.
Can be used to crop off gunk remaining around clip edges after fixing a shifted clip.
Prefix, allows you to change the prefix to the names of the variables.
eg if Prefix == "My_Crop_", then set Global variables 'My_Crop_L' as Global Int.
*/
myName = "SpatialAlign: "
MatchLen = Default(MatchLen,50)
Rad = Default(Rad,4)
AutoLDTh = !Defined(LdTh)
LdTh = Float(Default(LdTh,3.0*Rad))
Prefix = Default(Prefix,"SA_Crop_")
Assert(Src.Width==Fix.Width,RT_String("%sClip Width mismatch",myName))
Assert(Src.Height==Src.Height,RT_String("%sClip Height mismatch",myName))
Assert(RT_VarIsSame(Src,Fix,sig=false),RT_String("%sClip ColorSpace mismatch",myName))
Assert(MatchLen>0,RT_String("%sInvalid MatchLen, Must be greater than 0(%d)",myName,MatchLen))
Assert(Rad>=1 && Rad<=6,RT_String("%sInvalid Rad, 1 -> 6(%d)",myName,Rad))
SrcMax = Src.FrameCount - MatchLen
FixMax = Fix.FrameCount - MatchLen
Assert(SrcMax>=0,RT_String("%sInvalid MatchLen, Src too short",myName))
Assert(FixMax>=0,RT_String("%sInvalid MatchLen, Fix too short",myName))
GScript("""
FixMatchFrame = -1 SrcMatchFrame = -1 # Match frames not yet found
# Test already temporally aligned
mnlen = Min(FixMax,SrcMAx) + 1
nTests = Min(mnlen,10)
tstMul = (nTests<=1) ? 0.0 : (mnlen-1) / (nTests-1.0)
WorstOfAllDf = -1.0
For(Test = 1, nTests) {
tStart = int((Test - 1) * tstMul + 0.5)
if(RT_YPlaneMinMaxDifference(Fix,n=tStart,x=rad,y=rad,w=-rad,h=-rad,Threshold=1.0) >= 32) { # Reliable frame ?
worstDf= -1.0
for(j = 0, Matchlen-1) {
df = RT_LumaDifference(Fix,Src,n=tStart+j,n2=tStart+j,x=rad,y=rad,w=-rad,h=-rad)
worstDf = (df>worstDf) ? df : worstDf
if(df > LdTh) {
j = Matchlen + 1 # Break, MatchLen, not found
}
}
if(j==MatchLen) {
RT_DebugF("Already temporally aligned @ frame %d (Worst LumaDif of %d frames =%.3f)",tStart,Matchlen,worstDf,name=myName)
FixMatchFrame = tStart SrcMatchFrame = tStart
Test = nTests # Break Test
}
WorstOfAllDf = (worstDf>WorstOfAllDf) ? worstDf : WorstOfAllDf
}
}
if(FixMatchFrame<0) {
RT_DebugF("Not already temporally aligned (Worst LumaDif of all tested frames=%.3f)",WorstOfAllDf,name=myName)
RT_DebugF("Searching for temporal alignment",name=myName)
Tim = RT_LocalTimeString(File=True)
QDB = RT_String("~QDB_%s.DB",Tim) NDB = RT_String("~NDB_%s.DB",Tim)
RT_QwikScanCreate(Src,QDB,prev="",next=NDB,debug=True)
LumaTolStart = 5 LumaTolStep = 3 LumaTolEnd=17 ScanPerc = 0.5 / 2.0
for(LT = LumaTolStart,17,LumaTolStep) {
ScanPerc = ScanPerc * 2.0
LumaTol = Float(min(LT,16))
Testlen = FixMax + 1
nTests = Min(Testlen,Max(Round(ScanPerc*TestLen/100.0),50))
tstMul = (nTests<=1) ? 0.0 : (TestLen-1) / (nTests-1.0)
If(LT != LumaTolStart) {
RT_DebugF("Scan failed @ LumaTol==%d, LdTh=%.2f retrying",LT-LumaTolStep,LdTh,name=myName)
LdTh = (AutoLdTh) ? LdTh + 1.0 : LdTh
}
RT_DebugF("Scanning %d frames (%.1f%%) of Fix clip @ LumaTol==%d LdTh=%.2f",
\ nTests,nTests*100.0/Fix.Framecount,LT,LdTh,name=myName)
for(Test = 1,nTests) {
Fi = int((Test - 1) * tstMul + 0.5)
if(RT_YPlaneMinMaxDifference(Fix,n=Fi,x=rad,y=rad,w=-rad,h=-rad,Threshold=1.0) >= 32) { # Reliable frame ?
# Best match LumaDifference scan, Only exit early on EXACT match
Result=RT_QwikScan(Src,0,Fix,Fi,QDB,NDB,lumatol=LumaTol,Flags=2,ld=0.0,maxdistance=SrcMax,XP=0)
if(Result < 0 && QWKS_BM_COUNT > 0 && QWKS_BM_LD <= LdTh) {
Result = QWKS_BM_LD_FRM # Best match to Fix[Fi] in entire Src
}
if(Result>=0) {
mxdif = QWKS_BM_LD # Best or EXACT exit condition match for LumaDifference
for(j=1,MatchLen-1) {
df=RT_LumaDifference(Fix,Src,n=Fi+j,n2=Result+j)
mxdif = (df>mxdif) ? df : mxdif
if(df > LdTh) {
j = Matchlen + 1 # Break MatchLen, not found
}
}
if(j == MatchLen) { # completed normally ?
SrcMatchFrame = Result
FixMatchFrame = Fi
RT_DebugF("Fix[%d] Match Frame found at Src[%d] MaxLumaDif=%.3f (over %d frames)",
\ FixMatchFrame,SrcMatchFrame,mxdif,MatchLen,name=myName)
Test = nTests # Break Tests
}
}
}
}
if(FixMatchFrame != -1) {
LT = LumaTolEnd # Break LT
}
}
RT_FileDelete(QDB) RT_FileDelete(NDB)
}
Crop_L=0 Crop_T=0 Crop_R=0 Crop_B=0
if(FixMatchFrame>=0) {
X = rad*2
Y = rad*2
W = - X # As in crop(), clip width relative, same as c.width - X - (RADIUS * 2)
H = - Y # clip height relative, same as c.height - Y - (RADIUS * 2)
HDir = 0
VDir = 0
corr = -1.0
for(i= - rad, rad) {
for (j= - rad, rad) {
cor = RT_LumaCorrelation(Fix, Src,n=FixMatchFrame, x=X,y=Y,w=W,h=H,n2=SrcMatchFrame, x2=X+i, y2=Y+j)
if(cor>corr) {
corr=cor
HDir = i
VDir = j
}
}
}
Org_corr = RT_LumaCorrelation(Fix, Src,n=FixMatchFrame, x=X,y=Y,w=W,h=H,n2=SrcMatchFrame, x2=X, y2=Y)
RT_DebugF("Shifting clip HDir=%d VDir=%d (orig correlation=%f shifted=%f",HDir,VDir,Org_corr,corr,name=myName)
LCrop = (HDir<0) ? -HDir : 0 RCrop = (HDir>0) ? HDir : 0
TCrop = (VDir<0) ? -VDir : 0 BCrop = (VDir>0) ? VDir : 0
Wid = Fix.Width Hit = Fix.Height
XM = Fix.RT_ColorSpaceXMod() YM = Fix.RT_ColorSpaceYMod(Laced=False) # NOT for Interlaced
Fix = Fix.PointResize(Wid*XM,Hit*YM)
Fix = Fix.Crop(LCrop*XM,TCrop*YM,-RCrop*XM,-BCrop*YM).Addborders(RCrop*XM,BCrop*YM,LCrop*XM,TCrop*YM)
Fix = Fix.PointResize(Wid,Hit)
SA_x = (Abs(HDir) + XM - 1) / XM * XM
SA_y = (Abs(VDir) + YM - 1) / YM * YM
Crop_L = (HDir<0) ? 0 : SA_x Crop_T = (VDir<0) ? 0 : SA_y
Crop_R = (HDir<0) ? SA_x : 0 Crop_B = (VDir<0) ? SA_y : 0
} Else {
RT_DebugF("Cannot temporally align frames",name=myName)
}
SS = RT_String("Global %sL=%d Global %sT=%d Global %sR=%d Global %sB=%d",
\ Prefix,Crop_L,Prefix,Crop_T,Prefix,Crop_R,Prefix,Crop_B)
Eval(SS) RT_DebugF("%s",SS,name=myName)
""") # End Of GScript
return Fix
}
# SubstituteRangesGenny_PREP.avs
# Req TWriteAVI v2.0, RT_Stats v2.0 BETA 3, GScript.
Import("SpatialAlign.avs") # http://forum.doom9.org/showthread.php?p=1722142#post1722142
Function AutoContPC(clip c,Float "Strength",Float "Ignore",Int "X",Int "Y",Int "W", Int "H") {
c myName="AutoContPC: "
Strength=Max(Min(Float(Default(Strength,0.5)),1.0),0.0)
Ignore = Default(Ignore,0.0)
CSMin = 0 CSMax = 255
Eval(RT_QueryLumaMinMax(Samples=100,X=X,Y=Y,W=H,H=H,ignore=Ignore)) QLRng=QLMMMax-QLMMMin+1 CSRng=CSMax-CSMin+1
ALMin = Int(CSMin - ((CSMin - QLMMMin) * STRENGTH) + 0.5) ALMax = Int(CSMax - ((CSMax - QLMMMax) * STRENGTH))
Doit = (ALMin!=CSMin || ALMax != CSMax)
(Doit) ? RT_DebugF("Levels(%3d,1.0,%3d,%d,%d,Coring=False)",ALMin,ALMax,CSMin,CSMax,name=myName) : NOP
(!Doit) ? RT_DebugF("Skipping Levels",name=myName) : NOP
(Doit) ? Levels(ALMin,1.0,ALMax,CSMin,CSMax,Coring=False) : NOP
Return Last
}
############ FILE STUFF ##########
SrcFN = "UnCut.mkv.avi" # Higher rez 1024x584 @ 23.976 FPS
RepFN = "Cut.mkv.avi" # 720x480 @ 23.970 FPS (ie FrameRate mismatch)
USE_BOB = False # True, Bob if interlaced, Else dont Bob, both Progressive
# May need to AssumeTFF or AssumeBFF for both clips prior to bobbing.
BLURD = True # Blur Detection Clips if True
BLUR_ARG = 0.5 # Blur arg if BLURD, (0.0 -> 1.58)
ALIGN = True # Auto align clips
USE_ASSUMEFPS = False # Choose method to change FrameRate, True = AssumeFPS, False = ChangeFPS
CONTRAST = True # Auto Set Levels
AUD_SAMPLERATE= 48000 # Audio SampleRate
RAD = 4 # Arg to SpatialAlign()
######## ReplaceCuts CONFIG ########
Src = Avisource(SrcFN).Trim(0,0).ConvertToYV24(interlaced=USE_BOB)
Rep = Avisource(RepFN).Trim(0,0).ConvertToYV24(interlaced=USE_BOB)
######## Bob to Remove Interlacing (Bobber of your choice) ############
Src = (USE_BOB) ? Src.Bob : Src
Rep = (USE_BOB) ? Rep.Bob : Rep
######## Crop after Bob ############
# Use RoboCrop Thresh -40.0 as thin border line may remain on frame edge
Src = Src.RoboCrop(WMod=1,HMOD=1,Laced=False,Thresh=-40.0,Align=True)
Rep = Rep.RoboCrop(WMod=1,HMOD=1,Laced=False,Thresh=-40.0,Align=True)
######## Make Same FrameRate ##################
RHiFPS = (Rep.FrameRate>Src.FrameRate)
Src = (!RHiFPS) ? Src :(USE_ASSUMEFPS) ? Src.AssumeFPS(Rep.FrameRate,sync_audio=True) : Src.ChangeFPS(Rep.FrameRate,Linear=True)
Rep = (RHiFPS) ? Rep :(USE_ASSUMEFPS) ? Rep.AssumeFPS(Src.FrameRate,sync_audio=True) : Rep.ChangeFPS(Src.FrameRate,Linear=True)
######## MAKE SIMILAR Detection clip (resize to low dimension clip [Bilinear]) ########
RBIG = (Rep.Width > Src.Width)
RepD = (RBIG) ? Rep.BilinearResize(Src.Width,Src.Height) : Rep # Detection clips to LOWER dim rez
SrcD = (!RBIG) ? Src.BilinearResize(Rep.Width,Rep.Height) : Src
######## Auto Contrast #####
RepD = (CONTRAST) ? RepD.AutoContPC(1.0,0.04) : RepD
SrcD = (CONTRAST) ? SrcD.AutoContPC(1.0,0.04) : SrcD
######## Align shifted clip #####
RepD = (ALIGN) ? SpatialAlign(RepD,SrcD,Rad=RAD,Prefix="Crop_") : RepD
RepD = (ALIGN) ? RepD.Crop(Crop_L,Crop_T,-Crop_R,-Crop_B) : RepD
SrcD = (ALIGN) ? SrcD.Crop(Crop_L,Crop_T,-Crop_R,-Crop_B) : SrcD
######## Get rid of any thin edge borders left over after RoboCrop and make mod 4 #####
RepD = RepD.Crop(4,4,(RepD.Width/4-2)*4,(RepD.Height/4-2)*4)
SrcD = SrcD.Crop(4,4,(SrcD.Width/4-2)*4,(SrcD.Height/4-2)*4)
######## BLUR Detect
RepD = (BLURD) ? RepD.Blur(BLUR_ARG) : RepD
SrcD = (BLURD) ? SrcD.Blur(BLUR_ARG) : SrcD
########
Rep = (!RBIG) ? Rep.Spline36Resize(Src.Width,Src.Height) : Rep # Output clips to the Higher rez (Resizer of your choice)
Src = (RBIG) ? Src.Spline36Resize(Rep.Width,Rep.Height) : Src
Rep = Rep.ConvertAudioTo16bit.ReSampleAudio(AUD_SAMPLERATE)
Src = Src.ConvertAudioTo16bit.ReSampleAudio(AUD_SAMPLERATE)
WW = (Rep.Width + (4-1)) / 4 * 4
HH = (Rep.Height + (4-1)) / 4 * 4
Rep = Rep.AddBorders(0,0,WW-Rep.Width,HH-Rep.Height).ConvertToYV12
Src = Src.AddBorders(0,0,WW-Rep.Width,HH-Rep.Height).ConvertToYV12
# YV12
Src=Src.ConvertToYV12
Rep=Rep.ConvertToYV12
SrcD=SrcD.ConvertToYV12
RepD=RepD.ConvertToYV12
# Killdetect clip audio
SrcD=SrcD.KillAudio
RepD=RepD.KillAudio
#Return Src.Info
#Return Rep.Info
#Return SrcD.Info
#Return RepD.Info
# Write Src/Rep and SrcD/RepD clips to lossless UT_Video.
Src_Dummy=TWriteAVI(Src,"SourceClip.AVI",OverWrite=True,fourCC="ULY0") Src_Dummy.ForceProcessAVI
Rep_Dummy=TWriteAVI(Rep,"ReplaceClip.AVI",OverWrite=True,fourCC="ULY0") Rep_Dummy.ForceProcessAVI
SrcD_Dummy=TWriteAVI(SrcD,"SourceDetectClip.AVI",OverWrite=True,fourCC="ULY0") SrcD_Dummy.ForceProcessAVI
RepD_Dummy=TWriteAVI(RepD,"ReplaceDetectClip.AVI",OverWrite=True,fourCC="ULY0") RepD_Dummy.ForceProcessAVI
Return MessageClip("DONE")
StainlessS
4th November 2016, 01:56
Post 2 of Many
SubstituteRangesGenerator.avs PART 1 (req RT_Stats v2.0 Beta 3)
# SubstituteRangesGenerator.avs
/*
Function SubstituteRangesGenerator(clip src,clip rep,string srcARR,string srcNxtARR,Float "Th"=63.0,Float "Th2"=102.0,Int "MatchLen"=10,
\ Bool "Strict"=True,String "Project"="Default",
\ Float "LumaTol"=16.0,Bool "InsertExtras"=False,Bool "Debug"=True,Bool "Verbose"=False)
Req:-
RT_Stats v2.0 Beta 3, http://forum.doom9.org/showthread.php?p=1782029#post1782029 (c) StainlessS
Prune, http://forum.doom9.org/showthread.php?t=162446 (c) StainlessS
GScript, http://forum.doom9.org/showthread.php?t=147846 (c) Gavino
Function to substitute sequences in src source clip with similar sequences from rep replacement clip.
Both clips must have scenes similarly ordered.
NOTE, RT_QwikScanCreate() which is used to create the srcARR, and srcNxtARR Arrays, sets the Matrix (RGB to Luma-Y) and X, Y, W, and H args used
for RT_LumaCorrelation differencing. This function acquires those values from the srcARR array ID's.
For every rep replacement frame, it searches the entire src source clip for a frame that best matches (via Th), this is Sync1 frame, if Sync1+1
ie Sync2 frame (also via Th) also matches, then tries to match remainder of frames (both forwards and backwards using Th2) and the resulting
range length is compared to MatchLen. If sufficiently long, then that range will be replaced. That is basically it.
The function creates a Prune() Command file which is used to splice the sequences together. Note, Prune will Trim/Splice BOTH video and Audio.
Args:-
src, source clip.
rep, replacement/substitute clip (probably better quality clip of similar dimensions/colorspace and spatially in sync with src).
srcArr, RT_Stats Array filename, for array as created by RT_QwikScanCreate(), eg
RT_QwikScanCreate(src,"MySrc.ARR","","MySrcNxt.ARR",Matrix=Matrix,x=X,y=Y,w=W,h=H)
where
Matrix defaults (src.Width>1100||src.Height>600)?3:2) # 3=PC709, 2=PC601
X,Y,W,H are crop style coords (ignore eg logo).
srcNxtARR, RT_Stats Array filename, for array as created by RT_QwikScanCreate() as in above example.
Used for fast forward searching and locating of frames using RT_QwikScan().
Th, Default 0.75. LumaCorrelation threshold, greater or equal to this are considered similar frames. Th is used to find 'Sync' frames, and
Th should be greater than Th2. Range 0.0 < Th <= 1.0.
0.0 = not correlated, 1.0 = full correlation.
Th2, Default 0.60. LumaCorrelation threshold, greater or equal to this are considered similar frames, used for all remaining frames that are not
'Sync' frames. Range 0.0 < Th2 < Th.
MatchLen, Default = 10. Minimum number of frames (of source clip, when Strict=False) that must match, otherwise not replaced. Range 5 or more.
Strict, Default True. If True, then compared ranges must match 1:1, if replacement rep clip has extra frames or fewer frames in places,
then matched ranges will break at those points.
If False, then will try to see if match will be re-established if allowing for fewer or more frames in the replacement clip.
NOTE, if set false, then audio must use audio from the 'Prune'ed clips to maintain audio sync, if the src and rep clips are NOT
of similar volume, then the effect will not be good (change in volume where ranges are replaced, the alternative is out of sync audio).
Suggest audio pre-normalizing of both clips, if Strict=False.
Project, Default "Default". Empty string "" will be converted to the default.
Project is the name prefix given to output command and log files. (Below output files using default project).
"Default_Command.txt" # Prune Command file to create result clip.
"Default_UnUsed.txt" # Prune Command file to create clip of unused frames from rep replacement clip.
"Default_SubstituteRanges.LOG" # The log file.
LumaTol, Default 16.0. Range 0.0->16.0. See RT_Stats RT_QwikScan docs. Suggest ALWAYS leave at default maximum, lower is faster but may
not find some frames if significant difference in brightness between src and rep clips.
If big differences in brightness, maybe try AutoContrast() on both clips beforehand.
AutoContrast.avs:- http://forum.doom9.org/showthread.php?p=1757661#post1757661
InsertExtras, Default False. Set this true if you think the replacement Rep clip has additional scenes to those in the source src clip.
If true, then extra frames/ranges that seem to exist in the rep clip, are inserted into the result clip.
If set true, then you must peruse the result and delete any duplicate ranges. This is EXPERIMENTAL, unlikely to be removed
but may not work as wished for in all circumstances.
Debug, Default True. Send info to DebugView (Google).
Verbose, Default False. A little extra info when Debug=True.
*/
Function SubstituteRangesGenerator(clip src,clip rep,string srcARR,string srcNxtARR,Float "Th",Float "Th2",Int "MatchLen",Bool "Strict",String "Project",
\ Float "LumaTol",Bool "InsertExtras",Bool "Debug",Bool "Verbose") {
myName="SubstituteRangesGenerator: "
Th = Default(Th,0.75)
Th2 = Default(Th2,0.60)
MatchLen = Default(MatchLen,10)
Strict = Default(Strict,True)
Project = Default(Project,"")
LumaTol = Float(Default(LumaTol,16.0))
InsertExtras = Default(InsertExtras,False)
Debug=Default(Debug,True)
Verbose=(Debug) ? Default(Verbose,False) : False
Project = (Project!="")?Project:"Default"
Assert(Exist(srcARR),RT_String("%ssrcArr does not Exist, use RT_QwikScanCreate\n('%s')",myName,srcARR))
Assert(Exist(srcNxtARR),RT_String("%ssrcNxtARR does not Exist, use RT_QwikScanCreate\n('%s')",myName,srcNxtARR))
Assert(0.0 < Th <= 1.0,RT_String("%s0.0 < Th <= 1.0 ('%.3f')",myName,Th))
Assert(0.0 < Th2 < Th,RT_String("%s0.0 < Th2 < Th('Th2=%.3f:Th=%.3f')",myName,Th2,Th))
Assert(5 <= MatchLen,RT_string("%s5 <= MatchLen(%d)",myName,MatchLen))
Assert(0.0 <= LumaTol <= 16.0,RT_string("%s0.0 <= LumaTol <= 16.0(%.3f)",myName,Lumatol))
#
LOG = Project+"_SubstituteRanges.LOG"
Cmd = Project+"_Command.txt"
UnUsed = Project+"_UnUsed.txt" # Prune/FrameSel format.
RT_WriteFile(Cmd,"######\n#\n# Splice replacements\n#\n# Prune/FrameSel Command File\n#")
RT_WriteFile(UnUsed,"######\n#\n# Extract Unused frames from rep clip\n#\n# Prune/FrameSel Command file\n#")
RT_WriteFile(LOG,"######\n#\n# LOG\n#")
S=RT_string("###\n#\n# Local Start Time = %s\n#\n# Th=%.3f Th2=%.3f LumaTol=%.3f\n#",RT_LocalTimeString(false),Th,Th2,LumaTol)
(Debug) ? RT_DebugF("###%s",S,name=myName) :NOP
RT_WriteFile(LOG,"%s",S,Append=True) RT_WriteFile(Cmd,"%s",S,Append=True) RT_WriteFile(UnUsed,"%s",S,Append=True)
S=RT_string("# MatchLen=%d Strict=%s Project='%s' InsertExtras=%s\n#\n######\n",Matchlen,Strict,Project,InsertExtras)
(Debug) ? RT_DebugF("%s",S,name=myName) : NOP
RT_WriteFile(LOG,"%s\n",S,Append=True) RT_WriteFile(Cmd,"%s",S,Append=True) RT_WriteFile(UnUsed,"%s",S,Append=True)
TimSTART = RT_TimerHP
# Must use same values as set in QwikScan Array ID's
Matrix=RT_ArrayGetID(srcARR,6) X=RT_ArrayGetID(srcARR,8) Y=RT_ArrayGetID(srcARR,9) W=RT_ArrayGetID(srcARR,10) H=RT_ArrayGetID(srcARR,11)
#
False=False True=True # Locals (faster)
O=0 Xp=3 EXTCNT=0 REPCNT=0 SEARCHED=0 LUMATOL_FAILS=0 JUMPING=0
GSCript("""
srcNext=0 srcEnd=src.FrameCount-1 sRun=0 sStop=srcEnd-1
repNext=0 repEnd=rep.FrameCount-1 rRun=0 rStop=repEnd-1
###
While(rRun<=rStop && sRun<=sStop) { # Detect fully done
sGot=0
While(rRun<=rStop && sGot<MatchLen) {
# We do not track Gray start frames, too easy to get it wrong and screw up.
MinMxDif=RT_YPlaneMinMaxDifference(rep,n=rRun,Threshold=1.0)
if(MinMxDif >= 16) {
sGot=0
# Here align, look for BEST MATCH rep[rRun] match position in possibly longer src[]
MaxDistance=sStop-sRun
# Full search in src[sRun->sStop] for BEST MATCH with rep[rRun].
RT_QwikScan(src,sRun,rep,rRun,srcARR,srcNxtARR,LumaTol=LUMATOL,Flags=1,LC=0.0,MaxDistance=MaxDistance,xp=XP)
SEARCHED=SEARCHED+MaxDistance+1
if(RT_BitAND(QWKS_BM_FLAGS,1)!=0) {
Sync1 = 1.0 - (QWKS_BM_LC / 255.0) # HalfRange Pearsons Distance to Correlation(0.0->1.0)
sI = QWKS_BM_LC_FRM
rI = rRun
if(Sync1>=Th) {
Sync2 = RT_LumaCorrelation(rep,src,n=rI+1,n2=sI+1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Sync2>=Th) {
(Verbose) ? RT_DebugF("%6d] Sync on 2, rI=%d sI=%d Sync1=%.3f Sync2=%.3f",O,rI,sI,Sync1,Sync2,name=myName) : NOP sGot=2
Jumped=False StartFailCor=0.0 Cor=Sync1 StartCor=Sync1 MinCor=Min(Sync1,Sync2)
rIs=rI sIs=sI
if(Strict) { # Strict Backward search
Brk=False
While(!Brk && repNext<rIs && srcNext<sIs) {
Cor = RT_LumaCorrelation(rep,src,n=rIs-1,n2=sIs-1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) {rIs=rIs-1 sIs=sIs-1 MinCor=Min(MinCor,Cor) EndCor=cor}
else {StartFailCor=Cor Brk=True} # Break
}
} else { # Loose Backward search
Brk=False Jump=False
While(!Brk && repNext<rIs && srcNext<sIs) {
Cor= RT_LumaCorrelation(rep,src,n=rIs-1,n2=sIs-1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # Both match aligned OK
rIs=rIs-1 sIs=sIs-1 MinCor=Min(MinCor,Cor) StartCor=Cor Jump=False # Good match, allow leeway on next frame
} else if(Jump || (repNext<rIs-2 && srcNext<sIs-2)) {
StartFailCor=Cor
Brk=True # Break
} else {
if(repNext<=rIs-2) {
Cor=RT_LumaCorrelation(rep,src,n=rIs-2,n2=sIs-1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # rep seems to have duplicate/extra frame
rIs=rIs-2 sIs=sIs-1 EndCor=cor Jump=True Jumped=True # Good match, Disallow leeway on next frame
} else {
StartFailCor=Cor
}
}
if(!Jump && srcNext<=sIs-2) {
Cor=RT_LumaCorrelation(rep,src,n=rIs-1,n2=sIs-2,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # rep seems to have missing frame
rIs=rIs-1 sIs=sIs-2 EndCor=Cor Jump=True Jumped=True # Good match, Disallow leeway on next frame
} else {
StartFailCor=Cor
}
}
brk = ! Jump # break if not Jump
}
}
}
StainlessS
4th November 2016, 01:58
Post 3 of Many
SubstituteRangesGenerator.avs PART 2
Cor=Sync2 EndCor=Sync2
rIe=rI+1 sIe=sI+1
if(Strict) { # Strict Forward Search
Brk=False
While(!Brk && rIe<repEnd && sIe<srcEnd) {
Cor=RT_LumaCorrelation(rep,src,n=rIe+1,n2=sIe+1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) {rIe=rIe+1 sIe=sIe+1 MinCor=Min(MinCor,Cor) EndCor=Cor}
else {Brk=True} # Break
}
} else { # Loose Forward Search
Brk=False Jump=False
While(!Brk && rIe<repEnd && sIe<srcEnd) {
Cor=RT_LumaCorrelation(rep,src,n=rIe+1,n2=sIe+1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # Both match aligned OK
rIe=rIe+1 sIe=sIe+1 MinCor=Min(MinCor,Cor) EndCor=Cor Jump=False # Good match, allow leeway on next frame
} else if(Jump || (rIe+2>repEnd && sIe+2>srcEnd)) {
Brk=True # Break
} else {
if(rIe+2<=repEnd) {
Cor=RT_LumaCorrelation(rep,src,n=rIe+2,n2=sIe+1,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # rep seems to have duplicate/extra frame
rIe=rIe+2 sIe=sIe+1 EndCor=Cor Jump=True Jumped=True # Good match, Disallow leeway on next frame
}
}
if(!Jump && sIe+2<=srcEnd) {
Cor=RT_LumaCorrelation(rep,src,n=rIe+1,n2=sIe+2,x=X,y=Y,w=W,h=H,matrix=Matrix)
if(Cor>=Th2) { # rep seems to have missing frame
rIe=rIe+1 sIe=sIe+2 EndCor=Cor Jump=True Jumped=True # Good match, Disallow leeway on next frame
}
}
brk = ! Jump # break if not Jump
}
}
}
sGot = sIe-sIs+1
SEARCHED=SEARCHED+sGot+2
} else {
(Verbose) ? RT_DebugF("%6d] Sync on 1, rI=%d sI=%d Sync1=%.3f Sync2=%.3f(FAIL)",O,rI,sI,Sync1,Sync2,name=myName) : NOP
}
}
} else {
(Debug) ? RT_DebugF("%6d] @ rRun[%d] sRun[%d], QwikScan sync failure, perhaps LumaTol too low",O,rRun,sRun,name=myName) : NOP
LUMATOL_FAILS=LUMATOL_FAILS+1
}
if(sGot<MatchLen) {
rRun=rRun+1
} else {
BackGot=sI-sIs
if(BackGot>0 && Verbose) {
RT_DebugF("%6d] BACKWARDS Got=%d rRun=%d rI=%d sRun=%d sI=%d StartCor=%.3f",O,BackGot,rRun,rI,sRun,sI,StartCor,name=myName)
}
FwdGot=sIe-sI+1
if(FwdGot>0 && Verbose) {
RT_DebugF("%6d] FORWARD Got=%d rRun=%d sRun=%d rI=%d sI=%d EndCor=%.3f EndFailCor=%.3f",O,FwdGot,rRun,sRun,rI,sI,EndCor,Cor,name=myName)
}
rRun=rIs
sRun=sIs
sGot=sIe-sIs+1
}
} else {
(Verbose) ? RT_DebugF("%6d] rRun=%d GREY FRAME MinMxDif=%d: No detection attempt",O,rRun,MinMxDif,name=myName) : NOP
rRun = rRun + 1
} # end if YPlaneMinMaxDifference
} # End, While(rRun<rStop && Got<MatchLen)
if(sGot>=Matchlen) {
(Debug) ? RT_DebugF("%6d] *** ALIGNMENT SUCCEED *** rep[%d,%d]->src[%d,%d]",O,rIs,rIe,sIs,sIe,name=myName) : NOP
(Debug) ? RT_DebugF("%6d] %s%d source frames : %d replace frames",O,Jumped?"*** JUMPED *** (Strict==False) ":"",sIe-sIs+1,rIe-rIs+1,name=myName) : NOP
(Debug) ? RT_DebugF("%6d] StartFailCor=%.3f StartCor=%.3f Sync1=%.3f Sync2=%.3f MinCor=%.3f EndCor=%.3f EndFailCor=%.3f",
\ O,StartFailCor,StartCor,Sync1,Sync2,MinCor,EndCor,Cor,name=myName) : NOP
if(sIs>srcNext) {
(Debug) ? RT_DebugF("%6d] Writing Intervening non preferred source src[%d,%d] Len=%d",O,srcNext,sIs-1,sIs-srcNext,name=myName):NOP
RT_Writefile(LOG,"%6d] Writing Intervening non preferred source src[%d,%d] Len=%d",O,srcNext,sIs-1,sIs-srcNext,Append=true)
RT_WriteFile(Cmd,"0 %6d,%6d\t # %6d] Len=%-6d",srcNext,sIs-1,O,sIs-srcNext,Append=True)
O=O+sRun-srcNext srcNext=sRun
}
Extras=rRun-repNext
if(Extras>0) {
if(Extras>=MatchLen) {
if(InsertExtras) {
(Debug) ? RT_DebugF("%6d] *** Writing seemingly extra range rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,name=myName):NOP
RT_Writefile(LOG,"%6d] Writing seemingly extra range rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,Append=True)
RT_WriteFile(Cmd,"2 %6d,%6d\t # %6d] Len=%-6d *** Seemingly Extra Replacement frames",repNext,rRun-1,O,Extras,Append=True)
EXTCNT=EXTCNT+Extras
O=O+Extras
} else {
(Debug) ? RT_DebugF("%6d] Skipping seemingly extra range rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,name=myName):NOP
RT_Writefile(LOG,"%6d] Skipping seemingly extra range frames rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,Append=True)
RT_WriteFile(UnUsed,"1 %6d,%6d\t # Len=%-6d *** Seemingly Extra Replacement frames",repNext,rRun-1,Extras,Append=True)
}
} Else {
(Debug) ? RT_DebugF("%6d] Ignoring Short length seemingly extra range rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,name=myName):NOP
RT_WriteFile(LOG,"%6d] Ignoring Short length seemingly extra range rep[%d,%d] Len=%d",O,repNext,rRun-1,Extras,Append=True)
RT_WriteFile(UnUsed,"0 %6d,%6d\t # Len=%-6d Ignoring Short Range",repNext,rRun-1,Extras,Append=True)
}
repNext=rRun
}
(Debug) ? RT_DebugF("%6d] Writing Preferred range rep[%d,%d] Len=%d",O,rIs,rIe,rIe-rIs+1,name=myName):NOP
RT_Writefile(LOG,"%6d] Writing Preferred range rep[%d,%d] Len=%d%s",O,rIs,rIe,rIe-rIs+1,Jumped?" (*** JUMPED ***)":"",Append=True)
RT_WriteFile(Cmd,"1 %6d,%6d\t # %6d] Len=%-6d StartFailCor=%.3f StartCor=%.3f Sync1=%.3f Sync2=%.3f MinCor=%.3f EndCor=%.3f EndFailCor=%.3f%s",
\ rRun,rIe,O,rIe-rIs+1,StartFailCor,StartCor,Sync1,Sync2,MinCor,EndCor,Cor,Jumped?" *** JUMPED *** ":"",Append=True)
rGot=rIe-rRun+1 REPCNT=REPCNT+rGot O=O+rGot
rRun=rIe+1 repNext=rRun sRun=sIe+1 srcNext=sRun
JUMPING = JUMPED ? JUMPING+1:JUMPING
}
} # End, While(rRun<=rStop && sRun<=sStop)
if(rRun<=repEnd) {
Extras=repEnd-rRun+1
if(Extras>=MatchLen) {
if(InsertExtras) {
(Debug) ? RT_DebugF("%6d] *** Writing seemingly extra range rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,name=myName):NOP
RT_WriteFile(LOG,"%6d] * Writing seemingly extra range rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,Append=True)
RT_WriteFile(Cmd,"2 %6d,%6d\t # %6d] Len=%-6d rep[%d,%d] *** Seemingly Extra Replacement frames",rRun,repEnd,O,Extras,rRun,repEnd,Append=True)
EXTCNT=EXTCNT+Extras
} else {
(Debug) ? RT_DebugF("%6d] *** Skipping seemingly extra range frames rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,name=myName):NOP
RT_WriteFile(LOG,"%6d] * Skipping seemingly extra range rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,Append=True)
RT_WriteFile(UnUsed,"1 %6d,%6d\t # Len=%-6d Seemingly Extra Replacement frames",rRun,repEnd,Extras,Append=True)
}
} else {
(Debug) ? RT_DebugF("%6d] Ignoring seemingly extra range rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,name=myName):NOP
RT_WriteFile(LOG,"%6d] Ignoring seemingly extra range rep[%d,%d] Len=%d",O,rRun,repEnd,Extras,Append=True)
RT_WriteFile( UnUsed,"0 %6d,%6d\t # Len=%-6d Extra Range",rRun,repEnd,Extras,Append=True)
Extras=0
}
rRun=rRun+Extras O=O+Extras
}
if(sRun<=srcEnd) {
(Debug) ? RT_DebugF("%6d] Writing End Range src[%d,%d] Len=%d",O,sRun,srcEnd,srcEnd-sRun+1,name=myName):NOP
RT_WriteFile(LOG,"%6d] Writing End Range src[%d,%d] Len=%d",O,sRun,srcEnd,srcEnd-sRun+1,Append=True)
RT_WriteFile(Cmd,"0 %6d,%6d\t # %6d] Len=%-6d",sRun,srcEnd,O,srcEnd-sRun+1,Append=True)
Got=srcEnd-sRun+1
O=O+Got
}
S=RT_String("\n######\n# InLen=%6d OutLen=%6d Replaced=%d NotReplaced=%d Extras=%d",src.FrameCount,O,REPCNT,rep.FrameCount-REPCNT,EXTCNT)
(Debug) ? RT_DebugF("%s",S,name=myName):NOP
RT_WriteFile(LOG,"%s",S,Append=True)
S=RT_String("# Approx Frames Compared=%d",SEARCHED)
(Debug) ? RT_DebugF("%s",S,name=myName):NOP
RT_WriteFile(LOG,"%s",S,Append=True)
if(LUMATOL_FAILS>0) {
S=RT_String("# LumaTol Failures=%d",LUMATOL_FAILS)
(Debug) ? RT_DebugF("%s",S,name=myName):NOP
RT_WriteFile(LOG,"%s",S,Append=True)
if(LumaTol<16.0) {
S=RT_String("# Suggest Increase LumaTol and retry",LUMATOL_FAILS)
(Debug) ? RT_DebugF("%s",S,name=myName):NOP
RT_WriteFile(LOG,"%s",S,Append=True)
}
}
if(JUMPING>0) {
S=RT_String("# *** %d JUMPING *** sequences detected (Strict=False)",JUMPING)
(Debug) ? RT_DebugF("%s",S,name=myName):NOP
RT_WriteFile(LOG,"%s",S,Append=True)
}
Tim = RT_TimerHP-TimStart
S=RT_String ("# Local Stop Time = %s : Time Taken=%.3f Secs (%.3f mins)",RT_LocalTimeString(False),tim,tim/60.0)
(Debug) ? RT_DebugF("%s\n######",S,name=myName):NOP
RT_WriteFile(LOG,"%s\n######",S,Append=True)
""")
}
StainlessS
4th November 2016, 02:01
Post 4 of many
SubstituteRangesGenerator_Client.avs
# SubstituteRangesGenerator_Client.avs
Import("SubstituteRangesGenerator.avs")
SRCFN = "SourceDetectClip.AVI" # Source clip
REPFN = "ReplaceDetectClip.AVI" # Replace clip, Holds sequences that will replace those in source clip.
# Sequences in Replace clip should be in SAME order as in source clip.
# Clips must be same size, colorspace.
# When splicing sequences with Prune (later) everything must be similar, audio etc,
# also audio should both be normalized for similar voume levels, this detection stage ignores audio.
# In later script, Prune will replace with both video and audio from replace clip.
srcARR = SRCFN+".ARR" # Name of RT_QwikScan FingerPrint Array
srcNxtARR = SRCFN+"_Next.ARR" # Name of RT_QwikScan Locator Next Array (Next == scan forward Array)
#
src = AVISource(srcFN)
rep = AVISource(repFN)
#
MatchLen = 10 # Minimum sequence length that must match (frames).
STRICT = True # True=strict 1:1 matching of frames, False=allow slight mismatch ie missing/extra frames in replacement clip.
X = 0 # Avoid logos
Y = 0
W = 0
H = 0
CREATE = True # True to create QwikScan Arrays, Then Set False
(CREATE) ? RT_QwikScanCreate(Src,srcARR,"",srcNxtARR,debug=true,x=X,y=Y,w=W,h=H) : NOP # Only need create this once
(!CREATE) ? SubstituteRangesGenerator(src,rep,srcARR,srcNxtARR,MatchLen=MatchLen,Strict=STRICT,Verbose=True) : NOP
return Messageclip("All Done")
SubstituteRangesSplice.avs
# SubstituteRangesSplice.avs
Project="Default"
Fn=Project+"_Command.txt"
SHOW=True
A=AVISource("SourceClip.AVI")
B=AVISource("ReplaceClip.AVI")
C=B
SrcAudio=A.KillVideo
Nicks="""
Source=0
Replaced=1
Extras=2
"""
Prune(A,B,C,cmd=Fn,NickName=Nicks,Show=SHOW)
#AudioDub(SrcAudio) # Use only Source audio. ONLY if STRICT, else out of sync audio likely
#return Last
StackVertical(Last,A) # Only of use if STRICT=True
SubstituteRangesShowNonReplaced.avs
# SubstituteRangesShowNonReplaced.avs
Project="Default"
Fn=Project+"_UnUsed.txt"
A=AVISourcE("ReplaceClip.avi")
Nicks="""
ShortRangeLessThanMinReplace=0
Skipped=1
"""
SHOW=True
Prune(A,A,cmd=Fn,NickName=Nicks,Show=SHOW)
StainlessS
4th November 2016, 02:09
Post 5 of many.
SubstituteRangesGenerator.avs Output log [EDIT: Also logs to DebugView in real time, more verbose than this log]
######
#
# LOG
#
###
#
# Local Start Time = 2016-11-04 00:20:08.921
#
# Th=0.750 Th2=0.600 LumaTol=16.000
#
# MatchLen=10 Strict=True Project='Default' InsertExtras=False
#
######
0] Writing Intervening non preferred source src[0,66] Len=67
67] Writing Preferred range rep[0,689] Len=690
757] Writing Intervening non preferred source src[757,765] Len=9
766] Skipping seemingly extra range frames rep[690,699] Len=10
766] Writing Preferred range rep[700,730] Len=31
797] Writing Intervening non preferred source src[797,803] Len=7
804] Ignoring Short length seemingly extra range rep[731,737] Len=7
804] Writing Preferred range rep[738,816] Len=79
883] Writing Intervening non preferred source src[883,883] Len=1
884] Writing Preferred range rep[817,981] Len=165
1049] Ignoring Short length seemingly extra range rep[982,982] Len=1
1049] Writing Preferred range rep[983,1077] Len=95
1144] Writing Intervening non preferred source src[1144,1145] Len=2
1146] Writing Preferred range rep[1078,1219] Len=142
1288] Writing Intervening non preferred source src[1288,1289] Len=2
1290] Ignoring Short length seemingly extra range rep[1220,1220] Len=1
1290] Writing Preferred range rep[1221,1335] Len=115
1405] Writing Intervening non preferred source src[1405,1406] Len=2
1407] Ignoring Short length seemingly extra range rep[1336,1337] Len=2
1407] Writing Preferred range rep[1338,1357] Len=20
1427] Ignoring Short length seemingly extra range rep[1358,1359] Len=2
1427] Writing Preferred range rep[1360,1397] Len=38
1465] Writing Intervening non preferred source src[1465,1465] Len=1
1466] Ignoring Short length seemingly extra range rep[1398,1398] Len=1
1466] Writing Preferred range rep[1399,1408] Len=10
1476] Ignoring Short length seemingly extra range rep[1409,1409] Len=1
1476] Writing Preferred range rep[1410,1618] Len=209
1685] Writing Intervening non preferred source src[1685,1688] Len=4
1689] Writing Preferred range rep[1619,1674] Len=56
1745] Ignoring Short length seemingly extra range rep[1675,1677] Len=3
1745] Writing Preferred range rep[1678,1877] Len=200
1945] Writing Intervening non preferred source src[1945,1949] Len=5
1950] Ignoring Short length seemingly extra range rep[1878,1882] Len=5
1950] Writing Preferred range rep[1883,1996] Len=114
2064] Writing Intervening non preferred source src[2064,2075] Len=12
2076] Skipping seemingly extra range frames rep[1997,2034] Len=38
2076] Writing Preferred range rep[2035,2088] Len=54
2130] Writing Intervening non preferred source src[2130,2134] Len=5
2135] Writing Preferred range rep[2089,2134] Len=46
2181] Ignoring Short length seemingly extra range rep[2135,2138] Len=4
2181] Writing Preferred range rep[2139,2234] Len=96
2277] Ignoring Short length seemingly extra range rep[2235,2235] Len=1
2277] Writing Preferred range rep[2236,2294] Len=59
2336] Writing Intervening non preferred source src[2336,2336] Len=1
2337] Writing Preferred range rep[2295,2435] Len=141
2478] Ignoring Short length seemingly extra range rep[2436,2436] Len=1
2478] Writing Preferred range rep[2437,2640] Len=204
2682] Writing End Range src[2682,2882] Len=201
######
# InLen= 2883 OutLen= 2883 Replaced=2564 NotReplaced=77 Extras=0
# Approx Frames Compared=83303
# LumaTol Failures=12
# Local Stop Time = 2016-11-04 00:21:31.828 : Time Taken=82.905 Secs (1.382 mins)
######
You use the SubstituteRangesGenny_PREP.avs first to create and save lossless clips.
[EDIT Same size and framerate for both detect clips, and also both splice clips (detect/splice pairs not necessarily same) ]
Then use SubstituteRangesGenerator_Client.avs to create a frames/range command file for Prune().
SubstituteRangesSplice.avs Splices for Final result clip.
SubstituteRangesShowNonReplaced.avs show frames/ranges that were not used from Replacement clip.
SilSic, if you go back to pestering me by PM, I shall totally ignore you in future.
EDIT: Log above for your cut/uncut clips previously provided.
EDIT: SilSic last on-line April 2016, still I hope he sees this one day.
EDIT: The LumaTol failures in log above pretty much all down to searching for a duplicate in rep clip that does not exist in src clip,
so it cannot be found.
dark76
24th February 2021, 20:45
Sorry for the archeology (and for my bad english) :)
Maybe these scripts could help me with something I had in mind, but looks like i can't make them work. I copied all the AVS files and i put them in the same folder, I replaced in the SubstituteRangesGenny_PREP.avs the references to the 2 clips, in my case an uncut BW version of Invasion of the Body Snatchers (624x304 25 FPS) and a colorized version (quality vhs 544x400 23.976 ). These are 2 dummy files that I created from a DVD PAL and from a custom DVD NTSC who was 29.97(bought on ebay 10 years ago, the colorized version is simply a reversed vhs). This way, they have both approximately 115000 frames (they are not exactly the same, I guess there are a dozen of different microscenes) . If I run in AVSPMOD the first AVS (SubstituteRangesGenny_PREP.avs) after 20 minutes I get 2 .DB files (~NDB_20210224_175335_216, around 1.8 GB and ~QDB_20210224_175335_216, around 14 MB); after 1 hour the script apparently finishes and according to the script I should have 4 new AVI, created by TWriteAVI but this doesn't happen.
I have Windows 7 32 bit, AVSPMod 2.6.6.7 32 bit, Avisynth + 3.7.0 and apparently what is required: RT Stats 26 x86 v2.00 Beta, TWriteAVI v2.05, Gscript 2020 version, Robocrop 2020 version. I don't get any error, so I'm not sure what i should check... Any advice? Maybe what I'm doing has no sense (it could be, lol)? If it's the last option, I excuse myself for wasting the time of who is reading my horrible english :P
Post 1 of Many.
# SubstituteRangesGenny_PREP.avs
StainlessS
24th February 2021, 22:29
Nope, not gonna happen, sorry.
This thread is the one I'm least likely to want to return to [apart from Silsic pestering the hell out of me by PM, and eventually bollocking me for not answering].
His clips were pretty much impossible to match, and you say about differing micro scenes and one B&W and other color,
aint no way its gonna be any easier than doing it by hand yourself.
Sorry, and aint nuttin wrong with your English, pretty good actually.
(also, my time is limited, has been for some time now and likely to remain that way for some time to come).
dark76
25th February 2021, 11:05
No, problem :) I admit that after reading your "adventures" with Silsic , I was not much sure to awaken this topic.
I will try another approach, I will find position of missing frames with FFmatch, then I will try to insert them with Insertframesmc and finally I will try to use depanestimate and depaninterleave to spatial align and to merge chroma only on the BW movie, thank you anyway for your attention ;)
StainlessS
25th February 2021, 13:32
For Spatial Align, maybe take a look at AutoOverlay,
https://forum.doom9.org/showthread.php?t=175247
Introspected upped a new version a little while ago, I have not tried it yet, but looks well capable.
(I think Intospected tracks posts so will maybe pop-up if you make a post).
EDIT: Maybe you only need to align for 1 frame, and apply for all (Hopefully).
Frank62
25th February 2021, 18:29
Another hint: If AutoOverlay doesn't work in this case (when I tested it a longer time ago in a similar case, it didn't), you may try it how we solved it at last:
-align both sources temporally
-Deshake both sources, not too much
-align by hand spatially (cropping and resizing) until the sources match quite well (this will never be as exact as you will need it for using the chroma)
-interleave the two sources
-deshake this
-separate it again with selectevery
This is only the idea. You will have to experiment a lot. When I remember correctly (about 5 or 6 years ago), it finally worked with frames more often repeated of each source. So you have to interleave both first with itself a few times, then interleave with each other, deshake, and finally take the deshaked frames in the mid of the rows of both sources.
Sounds complicate, but it's the only way to be as exact as you quite certainly will need to be.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.