View Full Version : MatchFrames/LocateFrames v1.06
StainlessS
23rd April 2012, 00:10
MatchFrames, intended for matched frames extraction,
LocateFrames, intended to be usable by other scripts to identify matches.
MatchFrames()
Find And return frames in c clip that are best matched to frames in f clip.
Below a mod of Gavino's FindFrame, Advantages:-
Deals with a clip of frames to find rather than a single frame.
Can find exact/best match or 1st match below or equal to a threshold (rather than last frame if <= Thresh not found).
Extra Paranoia setting continues searching subsequent frames for a better match once thresh is broken.
Float Threshold.
Can show StackHorizontal required 'find' frame alongside source clip 'found' frames.
Can output a command file consisting of frame numbers found.
Command file can be used with FrameSelect() Plugin to select all found frames (useful if viewing StackHorizontal frames without 2nd SLOW run for extraction).
Originally prompted by this thread:
http://forum.doom9.org/showthread.php?t=164662
v1.02
Outputs LogFile
Can cut down on search times if clip f is known to be time ordered (in c).
v1.03
Added "(Thresh2)" Indicator to log.
v1.04
Added Args, "Start", "Stop", "XP".
v1.05
Added Args, "Chroma", "ChromaWeight", "Title", Added Debug Mode.
v1.06
Debug mode now holds TotalDiff as two floats providing greater precision.
############################################################################
# MatchFrames v1.06, by StainlessS:
#
# Find And return frames in c clip that are best matched to frames in f clip.
# Requires YV12, as uses LumaDifference(). Null Audio returned.
# ##################################
# Based on FindFrame() (c) Gavino. http://forum.doom9.org/showthread.php?p=1569622#post1569622
# Required: GScript (c) Gavino: http://forum.doom9.org/showthread.php?t=147846
# ##################################
#
# MatchFrames(clip c,clip f,bool "Show",float "Thresh",float "Thresh2",string "FileName",string "LogFile", \
# int "Start",int "Stop",bool "XP",Bool "Chroma",Float "ChromaWeight",string "Title")
#
# Args:
#
# c = clip, Source clip.
# f = clip, Consisting of frames that you wish to find in the c clip.
# Show = bool[true], True returns both find and found frames using StackHorizontal. NOTE, hires clips, may cause problems in eg VDUB
# if StackHorizontal width goes over some VD imposed limit.
# Thresh = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
# Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
# If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
# If f clip is known to be time ordered (in c), this arg can significantly cut down on the time taken to search for frames.
#
# Assuming time ordered f clip (Thresh < Thresh2),
#
# If a match found where diff of find to found frame <= Thresh,
# Next frame search will start from found frame + 1.
# Else if diff of find to Full Scan BEST found frame < Thresh2
# Next frame search will start from BEST found frame + 1.
# Else
# Next frame search will start from current start position.
# End if
# *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
#
# FileName= string["MatchFramesCmd.txt"], Output Frames command file.
# Can use FrameSelect() Plugin to select frames using MatchFramesCmd.txt Command file.
# FrameSelect() Plugin can be found here:- http://forum.doom9.org/showthread.php?t=164497
# Can monitor the MatchFramesCmd.txt file during scanning to view progress (ie view in notepad, [Read-Only viewer maybe safer]).
#
# LogFile = string["MatchFrames.Log"], Output Log file. Can monitor as for command file.
# The Logfile might produce an output line like that below:
#
# "0]=[1100] Diff=0.239 (T1:XP) S=1000 E =1101 XPCNT=5"
#
# Where eg 0] is find frame number, [1100] is found frame,
# Diff is the Difference (Luma + optional Chroma) between find and found frames.
# S and E are the search start and end positions that were searched for that frame.
# The "(T1:XP)" stuff presents just a little info about the search:
# "(BM: )" Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
# "(BM:T2)" Same as "(BM: )" but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
# "(T1: )" Means that the found frame had a Diff <= Thresh.
# "(T1:XP)" Same as "(T1: )" but Xtra Paranoia (XP) successfully found a better matching frame following the one that
# initially broke thresh. If this flag is shown, you will also see "XPCNT" which will tell how many successive better frames
# were found after the initial frame that broke Thresh.
#
# Start = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
# Stop = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
# XP = bool[true == Extra Paranoid] Main purpose of XP is so that you can use Thresh > 0.0 even if you dont fully trust a non best search.
# If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
# XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
# in 1 extra frame being compared (providing that your Thresh is not too high).
# If Thresh is set to 0.0 (default) then will only stop search on EXACT match, and so is likely to do a full search
# (unless exact frame exists). XP allows you to settle for a close match by setting thresh a little above 0.0, and when a close
# match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
# If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
#
# Chroma = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
# ChromaWeight=float[1.0/3.0 ie 0.33333], default for now, may change. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
# If Chroma==false then ChromaWeight is ignored and only luma difference is used.
# Title = string[""== none], Allows you to place a string of text in the Log and Command file headers, eg "Hires Test#2" or whatever.
# ##################################
# DEBUG MODE: If the f FrameCount and c[START,STOP] FrameCount (ie STOP-START) are same AND Thresh < Thresh2 (ie Ordered), then the script is put
# into DEBUG mode. This would be easiest achieved when START and STOP are at their default 0 values meaning 'All of c clip' and lengths of
# f and c are same.
# In Debug Mode, there is no searching for best match, log is produced with difference between all corresponding frames
# and in the footer of the log, it will show Average Diff, Min Diff, and Max Diff for the entire frame set.
# In DEBUG mode, the command file is cleared, prints header only.
# ##################################
#
# Will take some time to show results, it is not a bug if it seems to hang, it is WORKING HARD.
#
############################################################################
#
Suggested settings, Thresh=1.0, (if ordered clips then Thresh2=Thresh+0.1) but of course depends on f clip quality.
And always leave XP default.
If you have a lot of frames to find, might like to do a dummy run on only the first find frame and note what the difference
is, then repeat full scan with eg Thresh = Diff *1.25 (maybe 1.5) and Thresh2 = Thresh + 0.1 (assuming ordered clips).
As Script overflowed D9 16kb limit, have had to move posts around and the current script is in next post.
For Sister script LocateFrames(), see here:- http://forum.doom9.org/showthread.php?p=1600961#post1600961
MatchFrames & LocateFrames in single zip, also available via MediaFire in Sig.
StainlessS
23rd April 2012, 05:59
MatchFrames() v1.06 current script.
Function MatchFrames(clip c,clip f,bool "Show",float "Thresh",float "Thresh2",string "FileName",string "LogFile", \
int "Start",int "Stop",bool "XP", Bool "Chroma",Float "ChromaWeight",string "Title") {
ver = "v1.06 - 18 May 2012" # Version Number
Show = Default(Show,true) # Defaults true = show StackHorizontal find & found frames
Thresh = Default(Thresh, 0.0) # Threshold for declaring match, Default==0.0 to search for best possible match.
Thresh2 = Default(Thresh2,0.0) # Threshold2 Default==0.0, find clip f, not time ordered.
FileName = Default(FileName,"MatchFramesCmd.txt")# "" to switch OFF Frames output command file.
LogFile = Default(LogFile,"MatchFrames.Log") # "" to switch OFF Logfile.
Start = Default(Start,0) # Frame to start search from.
Stop = Default(Stop,0) # Frame to stop search (0 == last frame + 1).
XP = Default(XP,true) # Extra Paranoid, dont fully trust Thresh.
Chroma = Default(Chroma,False) # Default Luma Only.
ChromaWeight= Default(ChromaWeight,1.0/3.0) # Default, 33% of Total Difference (Combined U and V).
Title = Default(Title,"") # Shown in log and command file, Default "".
Start = (Start<0)?0:Start # Silent check
Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
cfrms = Stop-Start # Number of frames to scan in c
ChromaWeight=(Chroma)?ChromaWeight:0.0 # If Not Needed, ignore default weight.
Assert(c.IsYV12() && f.IsYV12(),"MatchFrames:- Requires YV12 clips")
Assert(c.Width==f.Width,"MatchFrames:- Clip Width mismatch")
Assert(c.Height==f.Height,"MatchFrames:- Clip Height mismatch")
Assert(cfrms>0,"MatchFrames:- Invalid Start>=Stop")
Assert(Thresh>=0.0,"MatchFrames:- Invalid Thresh")
Assert(f.Framecount<=cfrms,"MatchFrames:- f Frames > c[START,STOP] Frames")
Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,"MatchFrames:- ChromaWeight Range 0.0->1.0")
DBug = (cfrms==f.FrameCount && Thresh < Thresh2) # Debugging Mode ?
Thresh = (DBug) ? 255.0 : Thresh # If DBug, Ensure everything breaks Thresh.
Thresh2 = (DBug) ? 255.1 : Thresh2 # If DBug, Maintain Ordered.
TDHi =0.0 # DEBUG: TotalDifference Hi (Extra precision)
TDLo =0.0 # DEBUG: TotalDifference Lo
MinDiff = 255.0 + 1.0 # DEBUG: Output, max + 1
MaxDiff = 0.0 - 1.0 # DEBUG: Output, min - 1
Ordered = Thresh < Thresh2 # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
Result = 0 # Dummy, Will become a Clip, Dont use 'c.BlankClip(length=0)' (Maybe StackHorizontal)
Scanned = 0 # Init Total Frames scanned
EOL = Chr(10) # End Of Line. (Do NOT use Carriage Return, Line Feed, Will auto add the CR)
TLINE = "##########################################################################" + EOL
TGEN = "# MatchFrames " + Ver
TCMD = "Command File for SelectFrames Plugin." + EOL + "#" + EOL
TLOG = " (c) StainlessS : LogFile." + EOL + "#" + EOL
TNAM = (Title=="") ? "" : "# Title='" + Title + "'" + EOL + "#" + EOL
TSET = "# Width=" + String(c.Width) + " : Height=" + String(c.Height) + " : Start=" + String(Start) + " : Stop=" + String(Stop) + EOL+"#"+EOL
TSET2 = "# Thresh="+String(Thresh,"%.3f")+" : Thresh2="+String(Thresh2,"%.3f")+" : XP="+String(XP)
TSET3 = ((Chroma)?" : ChromaWeight="+String(ChromaWeight,"%.3f"):"") + EOL + "#" + EOL
TSET4 = ((DBug) ? "# DEBUG MODE" + EOL:"") + "#" + EOL
c=(FileName=="")? c : c.WriteFileStart(FileName,"""TLINE+"#"+EOL+TGEN+" : "+TCMD+TNAM+TSET+TSET2+TSET3+TSET4+TLINE""")
c=(LogFile=="") ? c : c.WriteFileStart(LogFile, """TLINE+"#"+EOL+TGEN +TLOG+TNAM+TSET+TSET2+TSET3+TSET4+TLINE""")
FileName= (DBug) ? "" : FileName # No Command file frame numbers if DBug Mode, HEADER ONLY (ie Wipe command file).
TimeStart = Time("%#c") # Used "%#c" LONG FORMAT time as "%c" shows eg "04/27/12" instead of correct 27/04/12 in UK.
GScript(""" # !!! WARNING !!!, Moving GScript before 1st WriteFileStart causes script error on 1st WriteFileStart line (Dont know why).
Lw = (Chroma) ? 1.0 - ChromaWeight: 1.0
Cw = ChromaWeight / 2.0 # Half for each chroma channel
dS="" # A Spare Debug String (NOT USED).
for (ix = 0, f.Framecount-1) { # Iterate through find frames clip.
ff=f.Trim(ix,-1).Loop(c.FrameCount, 0, 0) # Make a clip of identical find frame, same length as clip c (dont 'Stop' Limit).
s = Start # Init Start search position
BestSoFar = s # Search start position
BestSoFarDiff = 255.0 + 1.0 # Maximum Possible + 1
sS =" S=" + String(s,"%-4.0f") # Start offset this time, as string (at least 4 digits)
mS=" (BM: )" # Init to 'scanned all the way' message (Flag Best Match).
eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
e=eterm # Init to 'scanned all the way'
Assert(s<=e,"MatchFrames:- Internal Error, s > e") # Oops.
xS="" # Prep XP skip Count string
for(current_frame=s, eterm) { # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
# Difference to current find frame.
CurrDiff=(!Chroma)?LumaDifference(c,ff):Cw*ChromaUDifference(c,ff)+Cw*ChromaVDifference(c,ff)+(Lw>0.0?Lw*LumaDifference(c,ff):0)
if(CurrDiff < BestSoFarDiff) { # Better match than found so far ?
BestSoFar = current_frame # Remember frame number
BestSoFarDiff = CurrDiff # Remember difference
if(BestSoFarDiff <= thresh) { # Good enough to satisfy user requirement ?
if(DBug) { # DEBUG
MinDiff = (CurrDiff<MinDiff)?CurrDiff:MinDiff
MaxDiff = (CurrDiff>MaxDiff)?CurrDiff:MaxDiff
TDLo = TDLo + CurrDiff
TDHi = TDHi + floor(TDLo / 256.0) # Hi part, Extra Precision
TDLo = frac(TDLo / 256.0) * 256.0 # Lo part, Extra Precision
# ANY DEBUGGING STUFF YOU MIGHT WANT TO APPEND TO LOG FILE LINE.
# dS = " DBUG: Abs(AverageLuma(f)-AverageLuma(c)) = " + String(Abs(AverageLuma(ff)-AverageLuma(c)),"%.3f")
}
e=BestSoFar # Where we've scanned to so far
mS=" (T1: )" # Found satisfactory frame, (Flag Thresh)
if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
tmp = BestSoFar # Remember
for(current_frame=BestSoFar+1,eterm) {
CurrDiff=(!Chroma)?LumaDifference(c,ff): \
Cw*ChromaUDifference(c,ff)+Cw*ChromaVDifference(c,ff)+(Lw>0.0?Lw*LumaDifference(c,ff):0)
e=current_frame # We scanned more frames past original BestSoFar
if(CurrDiff < BestSoFarDiff) { # Better match ?
BestSoFar = current_frame # Remember frame number
BestSoFarDiff= CurrDiff # Remember difference
} else {
current_frame = eterm+1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
}
}
if(BestSoFar != tmp) {
mS=" (T1:XP)" # Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
xS=" XPCNT=" + String(BestSoFar-tmp) # How many frames Xtra Paranoid skipped to find better match than Thresh.
}
}
Start=(Ordered)?BestSoFar+1:Start # If required, Next time search from BestSoFar + 1
current_frame = eterm + 1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
}
}
}
if(Ordered && current_frame == eterm+1 && BestSoFarDiff < Thresh2) {
mS = " (BM:T2)" # For Log, Time ordered, (Flag, Best Match and Thresh2)
Start = BestSoFar + 1 # Next time start from BEST MATCH found + 1.
}
Scanned = Scanned + e - s + 1
Text = String(ix) + "]=[" + String(BestSoFar) + "] Diff=" + String(BestSoFarDiff,"%.3f") + mS + sS + " E =" + String(e,"%-4.0f") + xS + dS
FindFrame=ff.Trim(BestSoFar,-1).SubTitle(Text)
wrClip=(FileName=="") ? c : c.WriteFileStart(FileName,"BestSoFar",Append=true) # Command file
wrClip=(LogFile=="") ? wrClip : wrClip.WriteFileStart(LogFile,"Text",Append=true) # Log
wrClip=wrClip.Trim(BestSoFar,-1) # Only matched frame. (limit writefile to 1 frame only)
GotFrame=(Show)?StackHorizontal(FindFrame,wrClip):wrClip # Either will output Cmd/log if required.
Result = (IsClip(Result)) ? Result ++ GotFrame : GotFrame # Append to 'result clip so far'.
}
""") # End Of GScript
TimeEnd = Time("%#c")
Result=(LogFile=="")?Result:Result.WriteFileStart(LogFile,""" EOL+TLINE+EOL+"Start Time = "+TimeStart+EOL+"End Time = "+TimeEnd+EOL """, \
Append=True)
Result=(LogFile=="")?Result:Result.WriteFileStart(LogFile,""" "Total Frames Scanned = "+String(Scanned)+EOL """,Append=True)
Result=(!DBug||LogFile=="")?Result:Result.WriteFileStart(LogFile,""" "DEBUG: AveDiff="+String((TDHi / cfrms * 256.0) + (TDLo / cfrms),"%.3f")+ \
" : MinDiff="+ String(MinDiff,"%.3f")+" : MaxDiff="+String(MaxDiff,"%.3f") + " : [L="+String(Lw,"%.3f") + \
" : (U+V)="+ String(Cw*2,"%.3f")+"]" + EOL """,Append=True)
return Result.KillAudio() # Audio not sensible.
}
StainlessS
25th April 2012, 09:49
Here is the Basic Test Code with XP setting turned OFF and Thresh=Default 0.0 (Best possible match)
Test=Avisource("D:\avs\avi\TESTVID.avi").ConvertToYV12() # For LumaDifference
MCOUNT=600 # Size of sample taken from full Test clip.
MSTART=1000 # Start position in Full Test clip of Sample.
MSTOP =MSTART+MCOUNT # Stop position in full test clip.
Test.Trim(MSTART,-MCOUNT) # Last = 600 Frames from MSTART to MSTART+MSTOP-1
# Manufacture 5 frame FindClip, NOTE middle frame exact, others blurred to some degree.
Q=trim(100,-1).Blur(0.1) + trim(200,-1).Blur(1.58).Blur(1.58) + Trim(300,-1) + trim(400,-1).Blur(0.3) + Trim(500,-1).Blur(1.0)
MatchFrames(Test,Q,start=MSTART,stop=MSTOP,XP=false)
And the Log File:
##########################################################################
#
# MatchFrames v1.04 - 25 Apr 2012 (c) StainlessS : LogFile.
#
# Thresh=0.000 : Thresh2=0.000 : XP=false : Start=1000 : Stop=1600
#
##########################################################################
0]=[1100] Diff=0.239 (BM: ) S=1000 E =1599
1]=[1200] Diff=1.261 (BM: ) S=1000 E =1599
2]=[1300] Diff=0.000 (T1: ) S=1000 E =1300
3]=[1400] Diff=0.083 (BM: ) S=1000 E =1599
4]=[1500] Diff=0.098 (BM: ) S=1000 E =1599
##########################################################################
Total Frames Scanned = 2701
Note that it scanned all the way to the end except where the exact match was found.
MatchFrames(Test,Q,Thresh=0.5,Start=MSTART,Stop=MEND,XP=false)
##########################################################################
#
# Thresh=0.500 : Thresh2=0.000 : XP=false : Start=1000 : Stop=1600
#
##########################################################################
0]=[1100] Diff=0.239 (T1: ) S=1000 E =1100
1]=[1200] Diff=1.261 (BM: ) S=1000 E =1599
2]=[1300] Diff=0.000 (T1: ) S=1000 E =1300
3]=[1400] Diff=0.083 (T1: ) S=1000 E =1400
4]=[1500] Diff=0.098 (T1: ) S=1000 E =1500
##########################################################################
Total Frames Scanned = 1904
A Thresh 0f 0.5 identified all but one frame which was scanned to the end.
MatchFrames(Test,Q,Thresh=0.5,Thresh2=0.6,Start=MSTART,Stop=MSTOP,XP=false)
##########################################################################
#
# Thresh=0.500 : Thresh2=0.600 : XP=false : Start=1000 : Stop=1600
#
##########################################################################
0]=[1100] Diff=0.239 (T1: ) S=1000 E =1100
1]=[1200] Diff=1.261 (BM: ) S=1101 E =1596
2]=[1300] Diff=0.000 (T1: ) S=1101 E =1300
3]=[1400] Diff=0.083 (T1: ) S=1301 E =1400
4]=[1500] Diff=0.098 (T1: ) S=1401 E =1500
##########################################################################
Total Frames Scanned = 997
Ordered scans fewer frames.
MatchFrames(Test,Q,Thresh=1.5,Thresh2=1.6,Start=MSTART,Stop=MSTOP,XP=true)
##########################################################################
#
# Thresh=1.500 : Thresh2=1.600 : XP=true : Start=1000 : Stop=1600
#
##########################################################################
0]=[1100] Diff=0.239 (T1:XP) S=1000 E =1101 XPCNT=5
1]=[1200] Diff=1.261 (T1: ) S=1101 E =1201
2]=[1300] Diff=0.000 (T1: ) S=1201 E =1300
3]=[1400] Diff=0.083 (T1:XP) S=1301 E =1401 XPCNT=1
4]=[1500] Diff=0.098 (T1:XP) S=1401 E =1501 XPCNT=1
##########################################################################
Total Frames Scanned = 505
Using Ordered and XP, fewest scans of all and ALL frames correctly identified.
This test was a little contrived (1st guess) to force the Xtra Paranoia setting to work but
shows that even with a quite high threshold setting, the correct frames were
identified and number of frames scanned is reduced fairly significantly.
The XPCNT=5 line shows that the first find frame was incorrectly identified by
the Thresh setting, but the XtraParanoia setting scanned 5 further frames,
all of which were identified as giving a better match, and the eventually returned
frame was correct. Also NOTE, just before XPCNT=5, you see that the E (end frame)
scanned is one past the returned frame, ie it failed to give a better match.
jmac698
26th April 2012, 21:13
That's really nice - good job!
It's almost what I need. It could be more flexible with just a few changes in logic.
My problem, which is particularly irksome, is I have a set of frames which are actually the same except for a) extreme noise and b) dupes in each that puts them out of sync eventually.
The problem is that due to a) there is no dupe finder or even frame matching possible, however there is frame *un*matching; when the camera is panning say the change is large enough to reliably detect.
So what I need is an ordered sort of unmatching frames. Let me be more clear with an example:
[code]
A B Match?
1 1 yes
2 1 yes (falsely because of low motion)
3 3 yes
4 5 yes (falsely, also we're out of sync now)
5 6 no (noticed beause there's camera pan now)
6 7 no
.......
31 32 yes (pan is finished, false matching again)
I know that 4-30 don't match, but I'd like to know that a shift of 1 matches this string for n frames better than another offset. So I guess a multiframe match is more robust. At some point I'd know I was in sync from n1 to n2 and out of sync from n3 to n4, and the loss was somewhere in n2-n3, which I'd have to check by hand.
I believe I explained this before and Gavino provided an answer but I didn't get back to it, to explain that I required a more robust solution.
So Id like to say, for a sync shift of up to n frames, do an ordfered search for each offset until you've eliminated an offset by virtue of it definitely mismatching for m frames. For n>=2 you could end up with two theories which aren't eliminated; then log the result with a confidence. But over enough video you hould always find areas with definite mismatch
I probably have to think about this more.
Bear in mind that when I say matching here, the tolerance is at a really high level because of all the noise.
One more thing, I'd like to see the matching function just separated out in code to return a value between two single frames, then I can put other matching functinos in there. I'd have to test some, but I like correlation because I can prove that mathematically it will match even different brightness or contrast, but not match really different pixels. That's good for my case.
StainlessS
27th April 2012, 11:26
Hi Jmac,
Cant look at it just now, I've really got to get some sleep (10:27 am right now), but can you seek out the
Gavino answer thread/post, I'll take a peek later.
Been up all night on a mod to the script, Added args:- bool "Chroma",Float "ChromaWeight",string "Title".
Also added a Debug mode (When c.FrameCount == f.FrameCount), all that it does is scan through the
clips logging difference between similar position frames with no searching, at the end of the log, it will
also print out the clip Average Difference, Minimum Difference and Maximum Difference.
Also, I now think that it may be better to downsize any eg hirez clip to the same size as a smaller
clip as the Clip average difference seem to be lower when doing that, I guess that upscaling a low
rez compressed clip would also play games with the already existing compression artefacts,
better to downscale, possibly quicker too. Anyway, that was the reason for implementing the
Debug mode, and also so I can experiment with eg Luma only Average Difference and also
Chroma Only Average difference. I think I've seen elsewhere, that weighting Chroma along with
Luma, Chroma is given a combined weight of 0.5 (U+V), maybe I'm wrong on that, and its actually
0.25 combined. Anyways been doing a couple of tests and got these results (for the same f and c clips):
Test 1: Upscale Lowres f clip
DEBUG: Average Diff = 3.408322 : MinDiff=1.437595 : MaxDiff=4.771824 # Lumaweight = 1.0 (Luma Only)
DEBUG: Average Diff = 0.706108 : MinDiff=0.075863 : MaxDiff=2.565223 # Chromaweight = 1.0 (Chroma Only)
Test 2: Downscale Hires c clip
DEBUG: Average Diff = 1.099017 : MinDiff=0.162313 : MaxDiff=5.715830 # Lumaweight = 1.0 (Luma Only)
DEBUG: Average Diff = 0.587522 : MinDiff=0.079203 : MaxDiff=2.198153 # Chromaweight = 1.0 (Chroma Only)
Note, when downscaling (This clip pair):
The ave diff of both luma & chroma goes down.
The min diff luma goes down & chroma goes up.
The max diff luma goes up & chroma goes down.
Dont know if anything sensible can be deduced from that, need more samples.
I'm tempted to do something like this:
ChromaWeight = ChromaAveDiff / (LumaAveDiff+ChromaAveDiff)
0.706108 / (3.408322 + 0.706108) = 0.171617453 # Upscale
0.587522 / (1.099017 + 0.587522) = 0.348359569 # Downscale
ie for
Upscale maybe suggests ChromaWeight = ~0.17 and LumaWeight= 1.0 - 0.17 == 0.83
Downscale maybe suggests ChromaWeight = ~0.35 and LumaWeight= 1.0 - 0.35 == 0.65
Could a generally good ChromaWeight be deduced from a greater sample set or is the above,
total twaddle? (Compression has got to mangle chroma to a greater extent than luma).
Any thoughts ?
EDIT: All resizing up/down using BilinearResize.
EDIT: Above clip pair, the hirez source was 1920x1080, Lowrez resize/compressed to 352x288 MPG Low bitRate (0.2 bits per pixel).
EDIT: Aspect ratio was not taken into account (352x288), lowest rez I felt comfortable converting to.
StainlessS
28th April 2012, 00:14
Jmac, if you want to try the current beta, probably about complete, maybe just a little playing with format
and set a preliminary ChromaWeight default to 0.333.
Any body else want to try it, and any results/conclusions would be good, otherwise, may keep this chromaweight of 0.333 (What I 'feel' is about right).
EDIT: I think I'm correct about most filters using a weighting of about 0.5 for combined chroma, dont myself think
this is a good measure, luma commonly fills it's full dynamic range, whereas chroma huddles about the middle,
as chroma habitually occupies considerably less dynamic range, it should count for less in any kind of weighting, even
if combining two chroma channels. If the dynmic range of chroma is somewhat reduced, then the difference between
two identical frames where one has been reduced/compressed has got to be likewise reduced and of lesser importance
as a measure. Think about 33% might be a better guestimate.
See here: (Will be deleted when new non beta published)
EDIT: Link Removed.
StainlessS
12th May 2012, 17:58
New version v1.05, see 1st & 2nd posts.
StainlessS
18th May 2012, 00:21
New version v1.06, see 1st & 2nd posts.
StainlessS
27th May 2012, 11:44
may keep this chromaweight of 0.333 (What I 'feel' is about right).
EDIT: I think I'm correct about most filters using a weighting of about 0.5 for combined chroma, dont myself think
this is a good measure, luma commonly fills it's full dynamic range, whereas chroma huddles about the middle,
as chroma habitually occupies considerably less dynamic range, it should count for less in any kind of weighting, even
if combining two chroma channels. If the dynmic range of chroma is somewhat reduced, then the difference between
two identical frames where one has been downsized/compressed has got to be likewise reduced and of lesser importance
as a measure. Think about 33% might be a better guestimate.
Seems the reason that combined chroma normally counts for 0.5 total weight can be found here:
http://forum.doom9.org/showthread.php?p=640032#post640032
And as already stated, chroma tends to huddle around the centre so should probably be of lesser weight.
StainlessS
16th November 2012, 19:21
LocateFrames(), Sister script to MatchFrames().
Function LocateFrames(clip c,clip f,float "Thresh",float "Thresh2",int "Start",int "Stop",bool "XP", Bool "Chroma", \
Float "ChromaWeight",String "Prefix",bool "Debug") {
# LocateFrames() v1.06 by StainlessS:
# THREAD: http://forum.doom9.org/showthread.php?t=164766
# POST: http://forum.doom9.org/showthread.php?p=1600961#post1600961
# Requires GScript & RT_Stats plugins.
# Args as per MatchFrames() script.
# Returns newline [Chr(10)] separated list of results as a multiline String.
# Results string for a single frame find clip, as in format:-
#
# "LF_FOUND=1100 LF_FIND=0 LF_DIFF=0.006134 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0"
#
# LF_FOUND= Index of found clip frame
# LF_FIND = Index of find clip frame
# LF_DIFF = LumaDifference between find and found
# LF_START= Start frame searched
# LF_END = End frame searched
# LF_XPCNT= As for XPCNT in MatchFrames.
# LF_MATCH= Kind of match found. # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1: )", 3="(T1:XP)"
#
# Additional arg String Prefix, sets the default variable name prefix and defaults to "LF_" as in above.
# Bool Debug, default false, sends debug info to DebugView, if true.
#
# Can use RT_Stats functions eg
# RT_TxtQueryLines() to inquire lines of text in result string (same as frames in find f clip).
# RT_TxtGetLine() to extract a single result (if multiple find frames) from the combined results string.
# Can use eg "Eval(s)" to set variables where s is a single line result string.
#
# The innards of LocateFrames are much like MatchFrames, but could be more useful as implemented to use results
# programatically in other scripts.
#
# Use DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
#
Thresh = Default(Thresh, 0.0) # Threshold for declaring match, Default==0.0 to search for best possible match.
Thresh2 = Default(Thresh2,0.0) # Threshold2 Default==0.0, find clip f, not time ordered.
Start = Default(Start,0) # Frame to start search from.
Stop = Default(Stop,0) # Frame to stop search (0 == last frame + 1).
XP = Default(XP,true) # Extra Paranoid, dont fully trust Thresh.
Chroma = Default(Chroma,False) # Default Luma Only.
ChromaWeight= Default(ChromaWeight,1.0/3.0) # Default, 33% of Total Difference (Combined U and V).
Prefix = Default(Prefix,"LF_")
Debug = Default(Debug,False)
Start = (Start<0)?0:Start # Silent check
Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
cfrms = Stop-Start # Number of frames to scan in c
ChromaWeight=(Chroma)?ChromaWeight:0.0 # If Not Needed, ignore default weight.
Assert(c.IsYV12() && f.IsYV12(),"LocateFrames:- Requires YV12 clips")
Assert(c.Width==f.Width,"LocateFrames:- Clip Width mismatch")
Assert(c.Height==f.Height,"LocateFrames:- Clip Height mismatch")
Assert(cfrms>0,"LocateFrames:- Invalid Start>=Stop")
Assert(Thresh>=0.0,"LocateFrames:- Invalid Thresh")
Assert(f.Framecount<=cfrms,"LocateFrames:- f Frames > c[START,STOP] Frames")
Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,"LocateFrames:- ChromaWeight Range 0.0->1.0")
Ordered = Thresh < Thresh2 # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
Result = ""
GScript("""
Lw = (Chroma) ? 1.0 - ChromaWeight: 1.0
Cw = ChromaWeight / 2.0 # Half for each chroma channel
for (ix = 0, f.Framecount-1) { # Iterate through find frames clip.
ff=f.Trim(ix,-1).Loop(c.FrameCount, 0, 0) # Make a clip of identical find frame, same length as clip c (dont 'Stop' Limit).
s = Start # Init Start search position
BestSoFar = s # Search start position
BestSoFarDiff = 255.0 + 1.0 # Maximum Possible + 1
sS =String(s,"%-4.0f") # Start offset this time, as string (at least 4 digits)
mS= 0 # " (BM: )", Init to 'scanned all the way' message (Flag Best Match).
eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
e=eterm # Init to 'scanned all the way'
Assert(s<=e,"LocateFrames:- Internal Error, s > e") # Oops.
xpCnt=0 # Prep XP skip Count string
for(current_frame=s, eterm) { # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
# Difference to current find frame.
CurrDiff=(!Chroma)?LumaDifference(c,ff):Cw*ChromaUDifference(c,ff)+Cw*ChromaVDifference(c,ff)+(Lw>0.0?Lw*LumaDifference(c,ff):0)
if(CurrDiff < BestSoFarDiff) { # Better match than found so far ?
BestSoFar = current_frame # Remember frame number
BestSoFarDiff = CurrDiff # Remember difference
if(BestSoFarDiff <= thresh) { # Good enough to satisfy user requirement ?
e=BestSoFar # Where we've scanned to so far
mS=2 # " (T1: )", Found satisfactory frame, (Flag Thresh)
if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
tmp = BestSoFar # Remember
for(current_frame=BestSoFar+1,eterm) {
CurrDiff=(!Chroma)?LumaDifference(c,ff): \
Cw*ChromaUDifference(c,ff)+Cw*ChromaVDifference(c,ff)+(Lw>0.0?Lw*LumaDifference(c,ff):0)
e=current_frame # We scanned more frames past original BestSoFar
if(CurrDiff < BestSoFarDiff) { # Better match ?
BestSoFar = current_frame # Remember frame number
BestSoFarDiff= CurrDiff # Remember difference
} else {
current_frame = eterm+1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
}
}
if(BestSoFar != tmp) {
mS=3 # " (T1:XP)", Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
XpCnt=BestSoFar-tmp # How many frames Xtra Paranoid skipped to find better match than Thresh.
}
}
Start=(Ordered)?BestSoFar+1:Start # If required, Next time search from BestSoFar + 1
current_frame = eterm + 1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
}
}
}
if(Ordered && current_frame == eterm+1 && BestSoFarDiff < Thresh2) {
mS = 1 # " (BM:T2)", For Log, Time ordered, (Flag, Best Match and Thresh2)
Start = BestSoFar + 1 # Next time start from BEST MATCH found + 1.
}
Text = Prefix + "FOUND=" + String(BestSoFar) + " " + \
Prefix + "FIND=" + String(ix) + " " + \
Prefix + "DIFF=" + String(BestSoFarDiff) + " " + \
Prefix + "START=" + sS + " " + \
Prefix + "END=" + String(e) + " " + \
Prefix + "XPCNT=" + String(XpCnt) + " " + \
Prefix + "MATCH=" + String(mS) # 0=BM, 1=(BM:T2), 2=(T1: ), 3=(T1:XP)
Result = RT_TxtAddStr(Result,Text) # Avoid string concatenation bug in v2.58 and v2.6a3.
(DEBUG) ? RT_Debug(Text) :NOP
}
""") # End Of GScript
return Result
}
EDIT: Changed from version v0.0 to 1.06 to sync with MatchFrames() version.
Test snippet in next post.
StainlessS
16th November 2012, 19:25
Test snippet for LocateFrames() in previous post.
#Import("LocateFrames.avs")
VIDOEOFILE="D:\AVS\AVI\PAL-P_169_P-AeonFlux.d2v"
Test=MPEG2Source(VIDOEOFILE).Trim(0,2999)
MCOUNT=600 # Size of sample taken from full Test clip.
MSTART=1000 # Start position in Full Test clip of Sample.
MSTOP =MSTART+MCOUNT # Stop position in full test clip.
Test.Trim(MSTART,-MCOUNT) # Last = 600 Frames from MSTART to MSTART+MSTOP-1
# Manufacture 5 frame FindClip, NOTE middle frame exact, others blurred to some degree.
Q=trim(100,-1).Blur(0.1) + trim(200,-1).Blur(1.58).Blur(1.58) + Trim(300,-1) + trim(400,-1).Blur(0.3) + Trim(500,-1).Blur(1.0)
Results=LocateFrames(Test,Q,start=MSTART,stop=MSTOP)
#Results=LocateFrames(Test,Q,Thresh=1.5,Thresh2=1.6,Start=MSTART,Stop=MSTOP) # Alternative Ordered search
RT_Debug(Results) # Send combined results to debugview
RT_Debug(" ") # Line separator
GScript("""
N = RT_TxtQueryLines(Results) # Same as number of frames in find f clip.
for(i=0,N-1) {
s=RT_TxtGetLine(Results,Line=i) # Get individual result string
Eval(s) # Set variables for this find frame
RT_Debug("Found frame",String(LF_FOUND),"for find frame",String(LF_FIND),"Had a diff of",String(LF_DIFF))
}
""")
Return Test # Dummy return avoid ThrowError
Results from DebugView
00000002 25.34745216 [3680] RT_Debug: LF_FOUND=1100 LF_FIND=0 LF_DIFF=0.006134 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0
00000003 25.34751892 [3680] RT_Debug: LF_FOUND=1200 LF_FIND=1 LF_DIFF=0.482239 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0
00000004 25.34756088 [3680] RT_Debug: LF_FOUND=1300 LF_FIND=2 LF_DIFF=0.000000 LF_START=1000 LF_END=1300 LF_XPCNT=0 LF_MATCH=2
00000005 25.34760475 [3680] RT_Debug: LF_FOUND=1400 LF_FIND=3 LF_DIFF=0.038260 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0
00000006 25.34764290 [3680] RT_Debug: LF_FOUND=1500 LF_FIND=4 LF_DIFF=0.928930 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0
00000007 25.34771919 [3680] RT_Debug:
00000008 25.35038757 [3680] RT_Debug: Found frame 1100 for find frame 0 Had a diff of 0.006134
00000009 25.35267448 [3680] RT_Debug: Found frame 1200 for find frame 1 Had a diff of 0.482239
00000010 25.35495567 [3680] RT_Debug: Found frame 1300 for find frame 2 Had a diff of 0.000000
00000011 25.35724068 [3680] RT_Debug: Found frame 1400 for find frame 3 Had a diff of 0.038260
00000012 25.35950851 [3680] RT_Debug: Found frame 1500 for find frame 4 Had a diff of 0.928930
StainlessS
17th November 2012, 18:37
Modified LocateFrames version from v0.0 to v1.06 to sync with MatchFrames (logic is same).
Uploaded zip to Mediafire (in sig) containing both MatchFrames and LocateFrames scripts.
EDIT: LocateFrames() Intro is extended with full args spec in zip (similar to MatchFrames spec).
Brad555
21st November 2012, 11:37
Good job, Thanks to post here Code..
StainlessS
29th April 2015, 21:57
Both scripts have had several updates (In RT_Stats zip) which have not been posted here (mainly due to D9 post size restriction).
Matchframes.avs Part 1 of 2
############################################################################
# MatchFrames v1.10, by StainlessS:
#
# Find And return frames in c clip that are best matched to frames in f clip.
# v1.10 Planar, YUY2, RGB24/32. Previously YV12 only.
# Null Audio returned.
# ##################################
# Based on FindFrame() (c) Gavino. http://forum.doom9.org/showthread.php?p=1569622#post1569622
# Required: GScript (c) Gavino: http://forum.doom9.org/showthread.php?t=147846
# Required: RT_Stats (c) StainlessS: http://forum.doom9.org/showthread.php?p=1584313
# Recommended FrameSel (c) StainlessS: http://forum.doom9.org/showthread.php?t=167971
# Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
# MatchFrames THREAD: http://forum.doom9.org/showthread.php?t=164766
# LocateFrames POST: http://forum.doom9.org/showthread.php?p=1600961#post1600961
# ##################################
#
# MatchFrames(clip c,clip f,bool "Show",float "Thresh",float "Thresh2",string "FileName",string "LogFile", \
# int "Start",int "Stop",bool "XP",Bool "Chroma",Float "ChromaWeight",string "Title",bool "debug")
#
# Args:
#
# c = clip, Source clip.
# f = clip, Consisting of frames that you wish to find in the c clip.
# Show = bool[true], True returns both find and found frames using StackHorizontal. NOTE, hires clips, may cause problems in eg VDUB
# if StackHorizontal width goes over some VD imposed limit.
# Thresh = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
# Range 0.0 -> 255.0.
# Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
# If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
# If f clip is known to be time ordered (in c), this arg can significantly cut down on the time taken to search for frames.
#
# Assuming time ordered f clip (Thresh < Thresh2),
#
# If a match found where diff of find to found frame <= Thresh,
# Next frame search will start from found frame + 1.
# Else if diff of find to Full Scan BEST found frame < Thresh2
# Next frame search will start from BEST found frame + 1.
# Else
# Next frame search will start from current start position.
# End if
# *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
#
# FileName= string["MatchFramesCmd.txt"], Output Frames command file.
# Can use FrameSel() Plugin to select frames using MatchFramesCmd.txt Command file.
# FrameSel() Plugin can be found here:- http://forum.doom9.org/showthread.php?t=167971
# Can monitor the MatchFramesCmd.txt file during scanning to view progress (ie view in notepad, [Read-Only viewer maybe safer]).
#
# LogFile = string["MatchFrames.Log"], Output Log file. Can monitor as for command file.
# The Logfile might produce an output line like that below:
#
# "0]=[1100] Diff=0.239 (T1:XP) S=1000 E =1101 XPCNT=5"
#
# Where eg 0] is find frame number, [1100] is found frame,
# Diff is the Difference (Luma + optional Chroma) between find and found frames.
# S and E are the search start and end positions that were searched for that frame.
# The "(T1:XP)" stuff presents just a little info about the search:
# "(BM: )" Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
# "(BM:T2)" Same as "(BM: )" but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
# "(T1: )" Means that the found frame had a Diff <= Thresh.
# "(T1:XP)" Same as "(T1: )" but Xtra Paranoia (XP) successfully found a better matching frame following the one that
# initially broke thresh. If this flag is shown, you will also see "XPCNT" which will tell how many successive better frames
# were found after the initial frame that broke Thresh.
# v1.10, See Debug arg below to view real time output in DebugView window without slight risk involved reading open log file.
#
# Start = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
# Stop = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
# XP = bool[true == Extra Paranoid] Main purpose of XP is so that you can use Thresh > 0.0 even if you dont fully trust a non best search.
# If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
# XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
# in 1 extra frame being compared (providing that your Thresh is not too high).
# If Thresh is set to 0.0 (default) then will only stop search on EXACT match, and so is likely to do a full search
# (unless exact frame exists). XP allows you to settle for a close match by setting thresh a little above 0.0, and when a close
# match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
# If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
#
# Chroma = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
# ChromaWeight=float[1.0/3.0 ie 0.33333]. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
# If Chroma==false then ChromaWeight is ignored and only luma difference is used.
# v1.10, Chroma and ChromaWeight are for YUV only, not used for Y8 or RGB, no real advantage to using Luma only.
# Title = string[""== none], Allows you to place a string of text in the Log and Command file headers, eg "Hires Test#2" or whatever.
# Debug = bool[True == Debug info sent to debugview], True, send logging info to DebugView window (google DebugView),
# allows monitoring of progress without the slightly risky method of reading the open LogFile. New v1.10.
# Default True as cannot change your mind in middle of long search, does not have significant overhead in producing debug log.
# False, switch real time debug logging off.
# This setting has nothing whatever to do with below pre v1.10 DEBUG MODE, see below.
# ##################################
# DEBUG MODE: If the f FrameCount and c[START,STOP] FrameCount (ie STOP-START) are same AND Thresh < Thresh2 (ie Ordered), then the script is put
# into DEBUG MODE. This would be easiest achieved when START and STOP are at their default 0 values meaning 'All of c clip' and lengths of
# f and c are same.
# In Debug Mode, there is no searching for best match, log is produced with difference between all corresponding frames
# and in the footer of the log, it will show Average Diff, Min Diff, and Max Diff for the entire frame set.
# In DEBUG MODE, the command file is cleared, prints header only.
# ##################################
#
# Will take some time to show results, it is not a bug if it seems to hang, it is WORKING HARD.
#
############################################################################
#
StainlessS
29th April 2015, 21:58
Matchframes.avs Part 2 of 2
Function MatchFrames(clip c,clip f,bool "Show",float "Thresh",float "Thresh2",string "FileName",string "LogFile", \
int "Start",int "Stop",bool "XP", Bool "Chroma",Float "ChromaWeight",string "Title",bool "Debug") {
ver = "v1.10 - 25 June 2014" # Version Number
myName ="MatchFrames: "
c = c.Killaudio() f = f.Killaudio() # Audio return not sensible.
Show = Default(Show,true) # Defaults true = show StackHorizontal find & found frames
Thresh = Float(Default(Thresh, 0.0)) # Threshold for declaring match, Default==0.0 to search for best possible match.
Thresh2 = Float(Default(Thresh2,0.0)) # Threshold2 Default==0.0, find clip f, not time ordered.
FileName = Default(FileName,"MatchFramesCmd.txt")# "" to switch OFF Frames output command file.
LogFile = Default(LogFile,"MatchFrames.Log") # "" to switch OFF Logfile.
Start = Default(Start,0) # Frame to start search from.
Stop = Default(Stop,0) # Frame to stop search (0 == last frame + 1).
XP = Default(XP,true) # Extra Paranoid, dont fully trust Thresh.
Chroma = Default(Chroma,True) # Default Luma + Chroma.
ChromaWeight= Float(Default(ChromaWeight,1.0/3.0)) # Default, 33% of Total Difference (Combined U and V).
Title = Default(Title,"") # Shown in log and command file, Default "".
Debug = Default(Debug,True) # Default no debug logging to DebugView
Start = (Start<0)?0:Start # Silent check
Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
cfrms = Stop-Start # Number of frames to scan in c
ChromaWeight=(Chroma)?ChromaWeight:0.0 # If Not Needed, ignore default weight.
Assert(c.Width==f.Width,myName+"- Clip Width mismatch")
Assert(c.Height==f.Height,myName+"- Clip Height mismatch")
Assert(RT_VarIsSame(c,f),myName+"- ColorSpace Mismatch") # Same colorspace ?
Assert(cfrms>0,myName+"- Invalid Start>=Stop")
Assert(Thresh>=0.0,myName+"- Invalid Thresh")
Assert(f.Framecount<=cfrms,myName+"- f Frames > c[START,STOP] Frames")
Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,myName+"- ChromaWeight Range 0.0->1.0")
DBug = (cfrms==f.FrameCount && Thresh < Thresh2) # Debugging Mode ?
Thresh = (DBug) ? 255.0 : Thresh # If DBug, Ensure everything breaks Thresh.
Thresh2 = (DBug) ? 255.1 : Thresh2 # If DBug, Maintain Ordered.
TDHi =0.0 # DEBUG: TotalDifference Hi (Extra precision)
TDLo =0.0 # DEBUG: TotalDifference Lo
MinDiff = 255.0 + 1.0 # DEBUG: Output, max + 1
MaxDiff = 0.0 - 1.0 # DEBUG: Output, min - 1
Ordered = Thresh < Thresh2 # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
Result = 0 # Dummy, Will become a Clip, Dont use 'c.BlankClip(length=0)' (Maybe StackHorizontal)
Scanned = 0 # Init Total Frames scanned
EOL = Chr(10) # End Of Line. (Do NOT use Carriage Return, Line Feed, Will auto add the CR)
TLINE = "##########################################################################" + EOL
TGEN = "# MatchFrames " + Ver
TCMD = "Command File for FrameSel() Plugin." + EOL + "#" + EOL
TLOG = " (c) StainlessS : LogFile." + EOL + "#" + EOL
TNAM = (Title=="") ? "" : "# Title='" + Title + "'" + EOL + "#" + EOL
TSET = "# Width=" + String(c.Width) + " : Height=" + String(c.Height) + " : Start=" + String(Start) + " : Stop=" + String(Stop)
\ + ((ORDERED && !DBug) ? " : ORDERED" : "") + EOL+"#"+EOL
TSET2 = "# Thresh="+String(Thresh,"%.3f")+" : Thresh2="+String(Thresh2,"%.3f")+" : XP="+String(XP)
TSET3 = ((Chroma)?" : ChromaWeight="+String(ChromaWeight,"%.3f"):"") + EOL + "#" + EOL
TSET4 = ((DBug) ? "# DEBUG MODE" + EOL:"") + "#" + EOL
LogT = RT_String("%s#\n%s%s%s%s%s%s%s%s",TLINE,TGEN,TLOG,TNAM,TSET,TSET2,TSET3,TSET4,TLINE)
(Debug) ? RT_DebugF("%s",LogT,name=myName) : NOP # DebugView
(LogFile !="") ? RT_WriteFile(LogFile, "%s",LogT) : NOP
(FileName!="") ? RT_WriteFile(FileName,"%s#\n%s : %s%s%s%s%s%s%s",TLINE,TGEN,TCMD,TNAM,TSET,TSET2,TSET3,TSET4,TLINE) : NOP
FileName= (DBug) ? "" : FileName # No Command file frame numbers if DBug Mode, HEADER ONLY (ie Wipe command file).
TimeStart = RT_LocalTimeString(file=false) # Format "YYYY-MM-DD HH:MM:SS.mmm"
Start_Secs = RT_TimerHP()
GScript("""
for(ix = 0, f.Framecount-1) { # Iterate through find frames clip.
s = Start # Init Start search position
BestSoFar = s # Search start position
BestSoFarDiff = 255.0 + 1.0 # Maximum Possible + 1
sS =" S=" + String(s,"%-4.0f") # Start offset this time, as string (at least 4 digits)
mS=" (BM: )" # Init to 'scanned all the way' message (Flag Best Match).
eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
e=eterm # Init to 'scanned all the way'
Assert(s<=e,myName+"- Internal Error, s > e") # Oops.
xS="" # Prep XP skip Count string
for(n=s, eterm) { # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
# Difference to current find frame.
CurrDiff=RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight)
if(CurrDiff < BestSoFarDiff) { # Better match than found so far ?
BestSoFar = n # Remember frame number
BestSoFarDiff = CurrDiff # Remember difference
if(BestSoFarDiff <= thresh) { # Good enough to satisfy user requirement ?
if(DBug) { # DEBUG
MinDiff = Min(CurrDiff,MinDiff)
MaxDiff = Max(CurrDiff,MaxDiff)
TDLo = TDLo + CurrDiff
TDHi = TDHi + floor(TDLo / 256.0) # Hi part, Extra Precision
TDLo = frac(TDLo / 256.0) * 256.0 # Lo part, Extra Precision
}
e=BestSoFar # Where we've scanned to so far
mS=" (T1: )" # Found satisfactory frame, (Flag Thresh)
if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
tmp = BestSoFar # Remember
for(n=BestSoFar+1,eterm) {
CurrDiff=RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight)
e=n # We scanned more frames past original BestSoFar
if(CurrDiff < BestSoFarDiff) { # Better match ?
BestSoFar = n # Remember frame number
BestSoFarDiff= CurrDiff # Remember difference
} else {
n = eterm+1 # Force Exit with n == eterm + 2 (normally exit @ eterm+1)
}
}
if(BestSoFar != tmp) {
mS=" (T1:XP)" # Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
xS=" XPCNT=" + String(BestSoFar-tmp)# How many frames Xtra Paranoid skipped to find better match than Thresh.
}
}
Start=(Ordered)?BestSoFar+1:Start # If required, Next time search from BestSoFar + 1
n = eterm + 1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
}
}
}
if(Ordered && n == eterm+1 && BestSoFarDiff < Thresh2) {
mS = " (BM:T2)" # For Log, Time ordered, (Flag, Best Match and Thresh2)
Start = BestSoFar + 1 # Next time start from BEST MATCH found + 1.
}
Scanned = Scanned + e - s + 1
Text = RT_String("%4d]=[%6d] Diff=%7.3f%s%s E =%-4.0f%s",ix,BestSoFar,BestSoFarDiff,ms,sS,e,xS)
(Debug) ? RT_DebugF("%s",Text,name=myName) : NOP # DebugView
(LogFile!="") ? RT_WriteFile(LogFile,"%s",Text,Append=true) : NOP # Log file
(FileName!="") ? RT_WriteFile(FileName,"%d",BestSoFar,Append=true) : NOP # Command file
FindFrame =f.Trim(ix,-1).SubTitle(Text)
wrClip =c.Trim(BestSoFar,-1)
GotFrame=(Show) ? StackHorizontal(FindFrame,wrClip) : wrClip
Result = (IsClip(Result)) ? Result ++ GotFrame : GotFrame # Append to 'result clip so far'.
}
""") # End Of GScript
TimeEnd = RT_LocalTimeString(file=false)
Tim = RT_TimerHP - Start_Secs
Text = RT_String("\n%s\nStart Time = %s\nEnd Time = %s\nTotal Time = %.3f Secs (%.3f Mins)\n",TLINE,TimeStart,TimeEnd,Tim,Tim/60.0)
Text2 = RT_String("Total Frames Searched =%6d (%7.3f FPS : %10.6f SPF)",Scanned,Scanned/Tim,Tim/Scanned)
Text3 = RT_String("Find Frames Located =%6d (%7.3f FPS : %10.6f SPF)",f.FrameCount,f.FrameCount/Tim,Tim/f.FrameCount)
(Debug) ? RT_DebugF("%s\n%s\n%s",Text,Text2,Text3,name=myName) : NOP
(LogFile!="") ? RT_WriteFile(LogFile,"%s\n%s\n%s",Text,Text2,Text3,Append=True) : NOP
Text4 = RT_String("DEBUG: AveDiff=%.3f : MinDiff=%.3f : MaxDiff=%.3f : [L=%.3f : (U+V)=%.3f]\n",
\ (TDHi / cfrms * 256.0) + (TDLo / cfrms),MinDiff,MaxDiff,1.0-ChromaWeight,ChromaWeight)
(DBug&&Debug) ? RT_DebugF("%s",Text4,name=myName) : NOP
(DBug&&LogFile!="") ? RT_WriteFile(LogFile,"%s",Text4,Append=True) : NOP
Return Result.AssumeFPS(1.0)
}
StainlessS
29th April 2015, 22:01
LocateFrame.avs Part 1 of 2 (DBase usage added)
Function LocateFrames(clip c,clip f,float "Thresh",float "Thresh2",int "Start",int "Stop",bool "XP", Bool "Chroma", \
Float "ChromaWeight",String "Prefix",bool "Debug",String "DB") {
#
# LocateFrames() v1.10 by StainlessS:
# Find frames in c clip that are best matched to frames in f clip.
# v1.10 Planar, YUY2, RGB24/32. Previously YV12 only.
#
# Returns either a result string (old method) or if given a string DB arg, creates RT_Stats DB DataBase file, and returns number of records, Int.
#
# ##################################
# Based on FindFrame() (c) Gavino. http://forum.doom9.org/showthread.php?p=1569622#post1569622
# Required: GScript (c) Gavino: http://forum.doom9.org/showthread.php?t=147846
# Required: RT_Stats (c) StainlessS: http://forum.doom9.org/showthread.php?p=1584313
# Recommended FrameSel (c) StainlessS: http://forum.doom9.org/showthread.php?t=167971
# Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
# MatchFrames THREAD: http://forum.doom9.org/showthread.php?t=164766
# LocateFrames POST: http://forum.doom9.org/showthread.php?p=1600961#post1600961
# ##################################
# Args:
#
# c = clip, Source clip.
# f = clip, Consisting of frames that you wish to find in the c clip.
# Thresh = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
# Range 0.0 -> 255.0.
# Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
# If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
# If f clip is known to be time ordered (in c), this arg can significantly cut down on the time taken to search for frames.
#
# Assuming time ordered f clip (Thresh < Thresh2),
#
# If a match found where diff of find to found frame <= Thresh,
# Next frame search will start from found frame + 1.
# Else if diff of find to Full Scan BEST found frame < Thresh2
# Next frame search will start from BEST found frame + 1.
# Else
# Next frame search will start from current start position.
# End if
# *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
#
# Start = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
# Stop = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
# XP = bool[true == Extra Paranoid] Main purpose of XP is so that you can use Thresh > 0.0 even if you dont fully trust a non best search.
# If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
# XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
# in 1 extra frame being compared (providing that your Thresh is not too high).
# If Thresh is set to 0.0 (default) then will only stop search on EXACT match, and so is likely to do a full search
# (unless exact frame exists). XP allows you to settle for a close match by setting thresh a little above 0.0, and when a close
# match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
# If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
#
# Chroma = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
# ChromaWeight=float[1.0/3.0 ie 0.33333]. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
# If Chroma==false then ChromaWeight is ignored and only luma difference is used.
# v1.10, Now Planar, YUY2, RGB (was YV12 only), Chroma and ChromaWeight are for YUV only, not used for Y8 or RGB,
# no real advantage to using Luma only.
# Prefix = string("LF_"). Prefix prepended to variable names in returned string. (NOT USED if DBase mode, see below DB arg)
# Debug = bool[True == Debug info sent to debugview], True, send logging info to DebugView window (google DebugView),
# allows monitoring of progress.
# v1.10, Default True as cannot change your mind in middle of long search, does not have significant overhead in producing debug log.
# False, switch real time debug logging off.
#
# DB = string["" == Do Not Use DataBase]. Default "" as old version, where results returned in String as described below.
# v1.10, Otherwise, if DB != "" eg "LocateFrames.DB", then will create an RT_Stats DBase file using supplied DB as the filename,
# where results are stored in the Dbase and will return an Int, ie the number of frames in find f clip, which is also the
# number of records stored in the DB File. DB file created with typestring "iifiiii", in other words 7 fields per record.
# First two fields are Type Int, next 1 field of Type Float, then 4 fields of Type Int.
# Field 0 : Type Int : LF_FOUND Index of found clip frame
# Field 1 : Type Int : LF_FIND Index of find clip frame
# Field 2 : Type Float : LF_DIFF FrameDifference() between find and found
# Field 3 : Type Int : LF_START Start frame searched
# Field 4 : Type Int : LF_END End frame searched
# Field 5 : Type Int : LF_XPCNT Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
# Field 6 : Type Int : LF_MATCH Kind of match found. # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1: )", 3="(T1:XP)"
# See below for explanation of field contents, and RT_Stats for usage of RT_DBaseGetField(String Filename,Int Record,Int Field).
# ##################################
#
# Returns newline [Chr(10)] separated list of results as a multiline String, OR results stored in DB Database File, where it returns
# the number of records in the DB file (ie frames in Findclip f).
#
# STRING RESULT:-
# Results string for a single frame find clip using default "LF_" prefix, as in format:-
#
# "LF_FOUND=1100 LF_FIND=0 LF_DIFF=0.006134 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0"
#
# LF_FOUND= Index of found clip frame
# LF_FIND = Index of find clip frame
# LF_DIFF = FrameDifference() between find and found (range 0.0 -> 255.0)
# LF_START= Start frame searched
# LF_END = End frame searched
# LF_XPCNT= Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
# LF_MATCH= Kind of match found. # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1: )", 3="(T1:XP)"
#
# 0= Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
# 1= Same as 0 but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
# 2= Means that the found frame had a Diff <= Thresh.
# 3= Same as 2 but Xtra Paranoia (XP) successfully found a better matching frame following the one that
# initially broke thresh. "XPCNT" will tell how many successive better frames were found after the initial
# frame that broke Thresh.
#
# Can use RT_Stats functions eg
# RT_TxtQueryLines() to inquire lines of text in result string (same as frames in find f clip).
# RT_TxtGetLine() to extract a single result (if multiple find frames) from the combined results string.
# Can use eg "Eval(s)" to set variables where s is a single line result string.
#
# The innards of LocateFrames are much like MatchFrames, but could be more useful as implemented to use results
# programatically in other scripts.
#
# Use DebugView utility to view and capture output.
#
# Brief example usage:
#
# GScript("""
# myName="StringResultScript:"
# SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000) # 1000 frame SearchClip
# FindClip=SearchClip.SelectEvery(100,0).Blur(1.58) # 10 frame FindClip, Make a bit Different
# Results=LocateFrames(searchclip,findclip)
# n = RT_TxtQueryLines(Results) # Same as number of frames in findclip.
# Result = 0 # Will become clip
# for(i=0,n-1) {
# s=RT_TxtGetLine(Results,Line=i) # Get individual result string
# Eval(s) # Set variables for this find frame
# RT_DebugF("Found frame %d for find frame %d Had a diff of %f",LF_FOUND,LF_FIND,LF_DIFF,name=myName)
# Lft=FindClip.Trim(LF_FIND,-1).RT_SubTitle("%d DIFF=%f",LF_FIND,LF_DIFF) # Find Frame
# Rgt=SearchClip.Trim(LF_FOUND,-1).RT_SubTitle("%d",LF_FOUND) # Found Frame
# Stak = StackHorizontal(Lft,Rgt)
# Result = (Result.IsClip) ? Result ++ Stak : Stak # Append to clip so far
# }
# Return Result.AssumeFPS(1.0)
# """)
# Return Last
# ##################################
#
# DBASE RESULT:- (actual result is Int, number of records in created DB, ie frames in FindClip)
#
# SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000) # 1000 frame SearchClip
# FindClip=SearchClip.SelectEvery(100,0).Blur(1.58) # 10 frame FindClip, Make a bit Different
# DEBUG=True
# myName="DB_Script: "
# DB="~MyDbase_" + RT_LocalTimeString(File=True)+".DB" # Unique Temporary DBase filename
# Records = LocateFrames(SearchClip,FindClip,debug=DEBUG,db=DB) # Same as number of frames in FindClip.
# RT_DebugF("I got %d Records",Records,name=myName) # Send to DebugView
# Result = 0 # Will later be a clip
# GScript("""
# for(i=0,Records-1) {
# FoundIx = RT_DBaseGetField(DB,i,0) # Frame we found (Int)
# FindIx = RT_DBaseGetField(DB,i,1) # Frame that we had to find (Int)
# Diff = RT_DBaseGetField(DB,i,2) # FrameDifference (Float)
# RT_DebugF("%d ] Found frame %d with Difference of %f",FindIx,FoundIx,Diff,name=myName)
# Lft=FindClip.Trim(FindIx,-1).RT_SubTitle("%d DIFF=%f",FindIx,Diff) # Find Frame
# Rgt=SearchClip.Trim(FoundIx,-1).RT_SubTitle("%d",FoundIx) # Found Frame
# Stak = StackHorizontal(Lft,Rgt)
# Result = (Result.IsClip) ? Result ++ Stak : Stak # Append to clip so far
# }
# RT_FileDelete(DB) # Delete temp DB file
# """)
# Return Result.AssumeFPS(1.0)
#
# ##################################
StainlessS
29th April 2015, 22:01
Post 4 of 4.
LocateFrame.avs Part 2 of 2
myName = "LocateFrames: "
ver = "v1.10 - 25 June 2014" # Version Number
Assert(RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846")
c = c.Killaudio() f = f.Killaudio() # Audio not needed.
Thresh = Default(Thresh, 0.0) # Threshold for declaring match, Default==0.0 to search for best possible match.
Thresh2 = Default(Thresh2,0.0) # Threshold2 Default==0.0, find clip f, not time ordered.
Start = Default(Start,0) # Frame to start search from.
Stop = Default(Stop,0) # Frame to stop search (0 == last frame + 1).
XP = Default(XP,true) # Extra Paranoid, dont fully trust Thresh.
Chroma = Default(Chroma,False) # Default Luma Only.
ChromaWeight= Default(ChromaWeight,1.0/3.0) # Default, 33% of Total Difference (Combined U and V).
Prefix = Default(Prefix,"LF_")
Debug = Default(Debug,True) # v1.10, changed True
DB = Default(DB,"") # DBase not default
Start = (Start<0)?0:Start # Silent check
Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
cfrms = Stop-Start # Number of frames to scan in c
ChromaWeight=(Chroma)?ChromaWeight:0.0 # If Not Needed, ignore default weight.
Assert(c.Width==f.Width,myName+"- Clip Width mismatch")
Assert(c.Height==f.Height,myName+"- Clip Height mismatch")
Assert(RT_VarIsSame(c,f),myName+"- ColorSpace Mismatch") # Same colorspace ?
Assert(cfrms>0,myName+"- Invalid Start>=Stop")
Assert(Thresh>=0.0,myName+"- Invalid Thresh")
Assert(f.Framecount<=cfrms,myName+"- f Frames > c[START,STOP] Frames")
Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,myName+"- ChromaWeight Range 0.0->1.0")
MODE = (DB!="")
Ordered = Thresh < Thresh2 # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
FMT="%sFOUND=%-6d %sFIND=%-6d %sDIFF=%f %sSTART=%d %sEND=%-6d %sXPCNT=%-3d %sMATCH=%d"
Result = ""
GScript("""
(DEBUG) ? RT_DebugF("\n%s %s (%s Mode)\n",myName, Ver,(!MODE)? "STRING" : "DBASE",name=myName) : NOP
if(MODE) {RT_DBaseAlloc(DB,0,"iifiiii")}
for (ix = 0, f.Framecount-1) { # Iterate through find frames clip.
s = Start # Init Start search position
BestSoFar = s # Search start position
BestSoFarDiff = 255.0 + 1.0 # Maximum Possible + 1
sS =s # Start offset this time
mS= 0 # " (BM: )", Init to 'scanned all the way' message (Flag Best Match).
eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
e=eterm # Init to 'scanned all the way'
Assert(s<=e,myName+"- Internal Error, s > e") # Oops.
xpCnt=0 # Prep XP skip Count string
for(n=s, eterm) { # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
# Difference to current find frame.
CurrDiff=RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight)
if(CurrDiff < BestSoFarDiff) { # Better match than found so far ?
BestSoFar = n # Remember frame number
BestSoFarDiff = CurrDiff # Remember difference
if(BestSoFarDiff <= thresh) { # Good enough to satisfy user requirement ?
e=BestSoFar # Where we've scanned to so far
mS=2 # " (T1: )", Found satisfactory frame, (Flag Thresh)
if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
tmp = BestSoFar # Remember
for(n=BestSoFar+1,eterm) {
CurrDiff=RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight)
e=n # We scanned more frames past original BestSoFar
if(CurrDiff < BestSoFarDiff) { # Better match ?
BestSoFar = n # Remember frame number
BestSoFarDiff= CurrDiff # Remember difference
} else {
n = eterm+1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
}
}
if(BestSoFar != tmp) {
mS=3 # " (T1:XP)", Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
XpCnt=BestSoFar-tmp # How many frames Xtra Paranoid skipped to find better match than Thresh.
}
}
Start=(Ordered)?BestSoFar+1:Start # If required, Next time search from BestSoFar + 1
n = eterm + 1 # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
}
}
}
if(Ordered && n == eterm+1 && BestSoFarDiff < Thresh2) {
mS = 1 # " (BM:T2)", For Log, Time ordered, (Flag, Best Match and Thresh2)
Start = BestSoFar + 1 # Next time start from BEST MATCH found + 1.
}
if(MODE) {
(DEBUG) ? RT_DebugF(FMT,Prefix,BestSoFar,Prefix,ix,Prefix,BestSoFarDiff,Prefix,sS,Prefix,e,Prefix,XpCnt,Prefix,mS,name=myName) : NOP
RT_DBaseAppend(DB,BestSoFar,ix,BestSoFarDiff,sS,e,XpCnt,mS)
} Else {
Text = RT_String(FMT, Prefix,BestSoFar,Prefix,ix,Prefix,BestSoFarDiff,Prefix,sS,Prefix,e,Prefix,XpCnt,Prefix,mS)
Result = RT_TxtAddStr(Result,Text) # Avoid string concatenation bug in v2.58 and v2.6a3.
(DEBUG) ? RT_DebugF("%s",Text,name=myName) : NOP
}
}
""") # End Of GScript
return (MODE) ? f.FrameCount : Result # Int return for Dbase and String if not DBase
}
creaothceann
29th April 2015, 23:08
You can always post it on pastebin. (it even has an Avisynth color scheme)
StainlessS
29th April 2015, 23:37
Good to know, thanks very much :)
StainlessS
26th October 2016, 02:06
MatchFrames.avs + LocateFrames.avs v1.13, Requires RT_Stats v2.00 Beta 2. http://forum.doom9.org/showthread.php?p=1782028#post1782028
For MatchFrames zip (~15KB) see MediaFire in sig. (there will be two versions).
Here on PasteBin
MatchFrames:- http://pastebin.com/1TGKg3nw
LocateFrames:- http://pastebin.com/kBX4RCPY
Added X,Y,W,H coords (avoid logos), also new PD mode (Pearsons distance based on LumaCorrelation, less affected by changes in brightness).
EDIT: Seems to be formatted a bit too wide for Pastebin.
EDIT: Note, also added DBASE mode to LocateFrames, some time ago (old version supplied in RT_Stats). DBase mode returns results
for LocateFrames in DBase, instead of via a multiline string.
mastrboy
14th June 2023, 22:53
Is it possible to set the temporal radius for the search in Matchframes? The Thresh1/2 does not provide enough control alone over this.
I just need to search 12 frames back and 12 frames forward, and use the best match of those 24...
StainlessS
27th June 2023, 18:46
OOoops, sorry mastrboy, I did see this a coupla weeks ago and did not immediately know how to answer, so left it till later (and forgot).
Matchframes does not do that which you seem to think it does.
It does this,
############################################################################
# MatchFrames v1.10, by StainlessS:
#
# Find And return frames in c clip that are best matched to frames in f clip.
# v1.10 Planar, YUY2, RGB24/32. Previously YV12 only.
# Null Audio returned.
# ##################################
# Based on FindFrame() (c) Gavino. http://forum.doom9.org/showthread.php?p=1569622#post1569622
# Required: GScript (c) Gavino: http://forum.doom9.org/showthread.php?t=147846
# Required: RT_Stats (c) StainlessS: http://forum.doom9.org/showthread.php?p=1584313
# Recommended FrameSel (c) StainlessS: http://forum.doom9.org/showthread.php?t=167971
# Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
# MatchFrames THREAD: http://forum.doom9.org/showthread.php?t=164766
# LocateFrames POST: http://forum.doom9.org/showthread.php?p=1600961#post1600961
Returns a clip of the found matched frames. If given a single "Find Frame", it returns a single frame result clip.
I just need to search 12 frames back and 12 frames forward, and use the best match of those 24..
"Back and forward", Back and forward from WHAT.
Sounds like you want some kind of real time scan matching something to current_frame.
What is it that you are actually trying to do ?
MatchFrames(v1.10):- https://forum.doom9.org/showthread.php?p=1719673#post1719673
Sister script function, LocateFrames(v1.10):- https://forum.doom9.org/showthread.php?p=1719675#post1719675
Link to both updated versions v1.13:- https://forum.doom9.org/showthread.php?p=1783857#post1783857
StainlessS
27th June 2023, 18:55
Further: (for older v1.10)
Function LocateFrames(clip c,clip f,float "Thresh",float "Thresh2",int "Start",int "Stop",bool "XP", Bool "Chroma", \
Float "ChromaWeight",String "Prefix",bool "Debug",String "DB") {
#
# LocateFrames() v1.10 by StainlessS:
# Find frames in c clip that are best matched to frames in f clip.
# v1.10 Planar, YUY2, RGB24/32. Previously YV12 only.
#
# Returns either a result string (old method) or if given a string DB arg, creates RT_Stats DB DataBase file, and returns number of records, Int.
#
# ##################################
# Based on FindFrame() (c) Gavino. http://forum.doom9.org/showthread.php?p=1569622#post1569622
# Required: GScript (c) Gavino: http://forum.doom9.org/showthread.php?t=147846
# Required: RT_Stats (c) StainlessS: http://forum.doom9.org/showthread.php?p=1584313
# Recommended FrameSel (c) StainlessS: http://forum.doom9.org/showthread.php?t=167971
# Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
# MatchFrames THREAD: http://forum.doom9.org/showthread.php?t=164766
# LocateFrames POST: http://forum.doom9.org/showthread.php?p=1600961#post1600961
# ##################################
# Args:
#
# c = clip, Source clip.
# f = clip, Consisting of frames that you wish to find in the c clip.
# Thresh = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
# Range 0.0 -> 255.0.
# Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
# If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
# If f clip is known to be time ordered (in c), this arg can significantly cut down on the time taken to search for frames.
#
# Assuming time ordered f clip (Thresh < Thresh2),
#
# If a match found where diff of find to found frame <= Thresh,
# Next frame search will start from found frame + 1.
# Else if diff of find to Full Scan BEST found frame < Thresh2
# Next frame search will start from BEST found frame + 1.
# Else
# Next frame search will start from current start position.
# End if
# *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
#
# Start = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
# Stop = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
# XP = bool[true == Extra Paranoid] Main purpose of XP is so that you can use Thresh > 0.0 even if you dont fully trust a non best search.
# If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
# XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
# in 1 extra frame being compared (providing that your Thresh is not too high).
# If Thresh is set to 0.0 (default) then will only stop search on EXACT match, and so is likely to do a full search
# (unless exact frame exists). XP allows you to settle for a close match by setting thresh a little above 0.0, and when a close
# match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
# If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
#
# Chroma = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
# ChromaWeight=float[1.0/3.0 ie 0.33333]. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
# If Chroma==false then ChromaWeight is ignored and only luma difference is used.
# v1.10, Now Planar, YUY2, RGB (was YV12 only), Chroma and ChromaWeight are for YUV only, not used for Y8 or RGB,
# no real advantage to using Luma only.
# Prefix = string("LF_"). Prefix prepended to variable names in returned string. (NOT USED if DBase mode, see below DB arg)
# Debug = bool[True == Debug info sent to debugview], True, send logging info to DebugView window (google DebugView),
# allows monitoring of progress.
# v1.10, Default True as cannot change your mind in middle of long search, does not have significant overhead in producing debug log.
# False, switch real time debug logging off.
#
# DB = string["" == Do Not Use DataBase]. Default "" as old version, where results returned in String as described below.
# v1.10, Otherwise, if DB != "" eg "LocateFrames.DB", then will create an RT_Stats DBase file using supplied DB as the filename,
# where results are stored in the Dbase and will return an Int, ie the number of frames in find f clip, which is also the
# number of records stored in the DB File. DB file created with typestring "iifiiii", in other words 7 fields per record.
# First two fields are Type Int, next 1 field of Type Float, then 4 fields of Type Int.
# Field 0 : Type Int : LF_FOUND Index of found clip frame
# Field 1 : Type Int : LF_FIND Index of find clip frame
# Field 2 : Type Float : LF_DIFF FrameDifference() between find and found
# Field 3 : Type Int : LF_START Start frame searched
# Field 4 : Type Int : LF_END End frame searched
# Field 5 : Type Int : LF_XPCNT Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
# Field 6 : Type Int : LF_MATCH Kind of match found. # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1: )", 3="(T1:XP)"
# See below for explanation of field contents, and RT_Stats for usage of RT_DBaseGetField(String Filename,Int Record,Int Field).
# ##################################
#
# Returns newline [Chr(10)] separated list of results as a multiline String, OR results stored in DB Database File, where it returns
# the number of records in the DB file (ie frames in Findclip f).
#
# STRING RESULT:-
# Results string for a single frame find clip using default "LF_" prefix, as in format:-
#
# "LF_FOUND=1100 LF_FIND=0 LF_DIFF=0.006134 LF_START=1000 LF_END=1599 LF_XPCNT=0 LF_MATCH=0"
#
# LF_FOUND= Index of found clip frame
# LF_FIND = Index of find clip frame
# LF_DIFF = FrameDifference() between find and found (range 0.0 -> 255.0)
# LF_START= Start frame searched
# LF_END = End frame searched
# LF_XPCNT= Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
# LF_MATCH= Kind of match found. # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1: )", 3="(T1:XP)"
#
# 0= Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
# 1= Same as 0 but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
# 2= Means that the found frame had a Diff <= Thresh.
# 3= Same as 2 but Xtra Paranoia (XP) successfully found a better matching frame following the one that
# initially broke thresh. "XPCNT" will tell how many successive better frames were found after the initial
# frame that broke Thresh.
#
# Can use RT_Stats functions eg
# RT_TxtQueryLines() to inquire lines of text in result string (same as frames in find f clip).
# RT_TxtGetLine() to extract a single result (if multiple find frames) from the combined results string.
# Can use eg "Eval(s)" to set variables where s is a single line result string.
#
# The innards of LocateFrames are much like MatchFrames, but could be more useful as implemented to use results
# programatically in other scripts.
#
# Use DebugView utility to view and capture output.
#
# Brief example usage:
#
# GScript("""
# myName="StringResultScript:"
# SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000) # 1000 frame SearchClip
# FindClip=SearchClip.SelectEvery(100,0).Blur(1.58) # 10 frame FindClip, Make a bit Different
# Results=LocateFrames(searchclip,findclip)
# n = RT_TxtQueryLines(Results) # Same as number of frames in findclip.
# Result = 0 # Will become clip
# for(i=0,n-1) {
# s=RT_TxtGetLine(Results,Line=i) # Get individual result string
# Eval(s) # Set variables for this find frame
# RT_DebugF("Found frame %d for find frame %d Had a diff of %f",LF_FOUND,LF_FIND,LF_DIFF,name=myName)
# Lft=FindClip.Trim(LF_FIND,-1).RT_SubTitle("%d DIFF=%f",LF_FIND,LF_DIFF) # Find Frame
# Rgt=SearchClip.Trim(LF_FOUND,-1).RT_SubTitle("%d",LF_FOUND) # Found Frame
# Stak = StackHorizontal(Lft,Rgt)
# Result = (Result.IsClip) ? Result ++ Stak : Stak # Append to clip so far
# }
# Return Result.AssumeFPS(1.0)
# """)
# Return Last
# ##################################
#
# DBASE RESULT:- (actual result is Int, number of records in created DB, ie frames in FindClip)
#
# SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000) # 1000 frame SearchClip
# FindClip=SearchClip.SelectEvery(100,0).Blur(1.58) # 10 frame FindClip, Make a bit Different
# DEBUG=True
# myName="DB_Script: "
# DB="~MyDbase_" + RT_LocalTimeString(File=True)+".DB" # Unique Temporary DBase filename
# Records = LocateFrames(SearchClip,FindClip,debug=DEBUG,db=DB) # Same as number of frames in FindClip.
# RT_DebugF("I got %d Records",Records,name=myName) # Send to DebugView
# Result = 0 # Will later be a clip
# GScript("""
# for(i=0,Records-1) {
# FoundIx = RT_DBaseGetField(DB,i,0) # Frame we found (Int)
# FindIx = RT_DBaseGetField(DB,i,1) # Frame that we had to find (Int)
# Diff = RT_DBaseGetField(DB,i,2) # FrameDifference (Float)
# RT_DebugF("%d ] Found frame %d with Difference of %f",FindIx,FoundIx,Diff,name=myName)
# Lft=FindClip.Trim(FindIx,-1).RT_SubTitle("%d DIFF=%f",FindIx,Diff) # Find Frame
# Rgt=SearchClip.Trim(FoundIx,-1).RT_SubTitle("%d",FoundIx) # Found Frame
# Stak = StackHorizontal(Lft,Rgt)
# Result = (Result.IsClip) ? Result ++ Stak : Stak # Append to clip so far
# }
# RT_FileDelete(DB) # Delete temp DB file
# """)
# Return Result.AssumeFPS(1.0)
#
# ##################################
EDIT:
MatchFrames(v1.13) on PasteBin:- https://pastebin.com/1TGKg3nw
LocateFrames(v1.13) on PasteBin:- https://pastebin.com/kBX4RCPY
v1.13, Added X,Y,W,H coords (avoid logos), also new PD mode (Pearsons distance based on LumaCorrelation, less affected by changes in brightness).
Seems to be formatted a bit too wide for Pastebin.
EDIT: Stuff added in v1.13
X = int[0], X coord, allow avoid some edge artefact or logo.
Y = int[0], Y coord, allow avoid some edge artefact or logo.
W = int[0], W coord, allow avoid some edge artefact or logo.
H = int[0], H coord, allow avoid some edge artefact or logo.
Matrix = int[2,PC601]. # Matrix: Default=2(PC601), 3=PC709. Used in conversion of RGB to YUV-Y. (Best not use 0 or 1, TV levels)
PD = False. New in v1.13, uses Pearsons Distance measure instead of RT_FrameDifference (well actually a limited variation of it).
To make the function work with both RT_FrameDifference and the PD=True methods, it is necessary for them both to return similar-ish
value, ie 0.0 being identical and 255.0 being totally different. RT__FrameDifference returns the average pixel difference across the
whole frame (in X,Y,W,H area). For RT_FrameDifference can also weight in the U&V compnent differences by specifying ChromaWeight.
For RGB, a little new functionality has been added (RT_Stats v2.0). If ChromaWeight is specified as 0.0, then RT_FrameDifference
returns Exactly the same as LumaDifference, but if ChromaWeight is non 0.0, then for RGB, it will return the average channel difference,
ie (RDif + GDif + BDif) / 3. [For LumaDifference mode, RGB converted to Luma-Y, uses Matrix arg].
Our limited version of Pearsons Distance goes like this
PD = Min(1.0 - LumaCorrelation, 1.0) * 255.0, result in range 0.0 -> 255.0 where 0.0 means identical.
when PD=True, ChromaWeight has no function.
Pearsons distance, based on Correlation, is not so perturbed by small changes in frame bightness, and may be better for matching
than the standard Average Pixel Difference mode.
Correlation limited PD
1.00 00.00
0.95 12.75
0.90 25.50
0.85 38.25
0.80 51.00
0.75 63.75
0.70 76.50
0.65 89.25
0.60 102.00
0.55 114.75
0.50 127.50
# EDIT: ADDED
0.00 255.00 # 0.0 Correlation
-1.00 255.00 # Max -ve Correlation
kedautinh12
29th June 2023, 00:57
i can't connect to https://pastebin.com/, can you upload to other host??
StainlessS
29th June 2023, 20:51
i can't connect to https://pastebin.com/, can you upload to other host??
EDIT:
MatchFrames(v1.13) on PasteBin:- https://pastebin.com/1TGKg3nw
LocateFrames(v1.13) on PasteBin:- https://pastebin.com/kBX4RCPY
Are you sure, your pasted link is missing the final "/1TGKg3nw" and "/kBX4RCPY" parts ?
Also, is on MediaFire in zip.
[direct link]:- https://www.mediafire.com/file/bk413nh1zt1cxu8/MatchFrames-LocateFrames_1-13_20161026.zip/file
EDIT: Also note thread title, "MatchFrames/LocateFrames v1.06",
Cannot change thread title if thread older than 8 (I think) years old [D9 (vBulletin forum software) restriction].
EDIT: Nasty advert from MediaFire, I dont usually see them with an ad blocker.
Suggest FireFox addon, "uBlock Origin". [From original 'AdBlock' author, currently named 'Adblock' addons, is/are not from the original author]
Been my 'go to' blocker for years.
Author, Raymond Hill GitHub page:- https://github.com/gorhill/uBlock#ublock-origin
From GitHub page, available for,
Firefox (uBO works best on Firefox and is available for desktop and Android versions).
Thunderbird
Chromium, uBO should be compatible with any Chromium-based browser.
Microsoft Edge Add-ons (Published by: Nicole Rolls)
Opera
kedautinh12
30th June 2023, 03:12
Yeah, i try click but error "cannot connect to server" pastebin
StainlessS
30th June 2023, 14:30
Might be some kind of restriction based on the country you are in (S. Korea, maybe, ???).
Anyway, I hope you got it from MediaFire OK :)
kedautinh12
30th June 2023, 16:02
Might be some kind of restriction based on the country you are in (S. Korea, maybe, ???).
Anyway, I hope you got it from MediaFire OK :)
yeah, mediafire ok
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.