Code:
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)
#
# ##################################