Advertisement
Guest User

Matchframes.Avs

a guest
Oct 25th, 2016
522
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Avisynth 22.36 KB | None | 0 0
  1. ############################################################################
  2. /*
  3.  MatchFrames v1.13, by StainlessS:
  4.  
  5.  Find And return frames in c clip that are best matched to frames in f clip.
  6.  Planar, YUY2, RGB24/32. Previously YV12 only.
  7.  Null Audio returned.
  8.  ##################################
  9.  Based on FindFrame() (c) Gavino.         http://forum.doom9.org/showthread.php?p=1569622#post1569622
  10.  Required: GScript    (c) Gavino:         http://forum.doom9.org/showthread.php?t=147846
  11.  Required: RT_Stats v2.0 (c) StainlessS:  http://forum.doom9.org/showthread.php?p=1584313
  12.  Recommended FrameSel (c) StainlessS:     http://forum.doom9.org/showthread.php?t=167971
  13.  Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
  14.  MatchFrames  THREAD:                     http://forum.doom9.org/showthread.php?t=164766
  15.  LocateFrames POST:                       http://forum.doom9.org/showthread.php?p=1600961#post1600961
  16.  ##################################
  17.  
  18.  MatchFrames(clip c,clip f,bool "Show"=true,float "Thresh"=0.0,float "Thresh2"=0.0,
  19.                \ string "FileName"="MatchframesCmd.txt",string "LogFile"=="Matchframes.Log",
  20.                \ int "Start"=0,int "Stop"=0,bool "XP"=true,Bool "Chroma"=false,Float "ChromaWeight"=1/3.0,string "Title"="",bool "debug"=true,
  21.                \ int "X"=0,int "Y"=0,int "W"=0,int "H"=0,Int "Matrix"=2,Bool "PD")
  22.  
  23.  Args:
  24.  
  25.  c       = clip, Source clip.
  26.  f       = clip, Consisting of frames that you wish to find in the c clip.
  27.  Show    = bool[true], True returns both find and found frames using StackHorizontal. NOTE, hires clips, may cause problems in eg VDUB
  28.                 if StackHorizontal width goes over some VD imposed limit.
  29.  Thresh  = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
  30.            Range 0.0 -> 255.0.
  31.  Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
  32.            If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
  33.            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.
  34.  
  35.            Assuming time ordered f clip (Thresh < Thresh2),
  36.  
  37.                If a match found where diff of find to found frame <= Thresh,
  38.                     Next frame search will start from found frame + 1.
  39.                Else if diff of find to Full Scan BEST found frame < Thresh2
  40.                     Next frame search will start from BEST found frame + 1.
  41.                Else
  42.                     Next frame search will start from current start position.
  43.                End if
  44.                *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
  45.  
  46.  FileName= string["MatchFramesCmd.txt"], Output Frames command file.
  47.              Can use FrameSel() Plugin to select frames using MatchFramesCmd.txt Command file.
  48.              FrameSel() Plugin can be found here:- http://forum.doom9.org/showthread.php?t=167971
  49.              Can monitor the MatchFramesCmd.txt file during scanning to view progress (ie view in notepad, [Read-Only viewer maybe safer]).
  50.  
  51.  LogFile = string["MatchFrames.Log"], Output Log file. Can monitor as for command file.
  52.              The Logfile might produce an output line like that below:
  53.  
  54.              "0]=[1100] Diff=0.239 (T1:XP) S=1000 E =1101 XPCNT=5"
  55.  
  56.              Where eg 0] is find frame number, [1100] is found frame,
  57.              Diff is the Difference (Luma + optional Chroma) between find and found frames.
  58.              S and E are the search start and end positions that were searched for that frame.
  59.              The "(T1:XP)" stuff presents just a little info about the search:
  60.               "(BM:  )" Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
  61.               "(BM:T2)" Same as "(BM:  )" but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
  62.               "(T1:  )" Means that the found frame had a Diff <= Thresh.
  63.               "(T1:XP)" Same as "(T1:  )" but Xtra Paranoia (XP) successfully found a better matching frame following the one that
  64.               initially broke thresh. If this flag is shown, you will also see "XPCNT" which will tell how many successive better frames
  65.               were found after the initial frame that broke Thresh.
  66.               See Debug arg below to view real time output in DebugView window without slight risk involved reading open log file.
  67.  
  68.  Start   = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
  69.  Stop    = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
  70.  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.
  71.                If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
  72.                XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
  73.                in 1 extra frame being compared (providing that your Thresh is not too high).
  74.                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
  75.                (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
  76.                match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
  77.                If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
  78.  
  79.  Chroma   = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
  80.                THIS IS NO LONGER FUNCTIONAL, totally switched now via the ChromaWeight arg.
  81.  
  82.  ChromaWeight=float[1.0/3.0 ie 0.33333]. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
  83.                If Chroma==false then ChromaWeight is ignored and only luma difference is used.
  84.                Chroma and ChromaWeight are for YUV only, not used for Y8 or RGB, no real advantage to using Luma only.
  85.  Title    = string[""== none], Allows you to place a string of text in the Log and Command file headers, eg "Hires Test#2" or whatever.
  86.  Debug    = bool[True == Debug info sent to debugview], True, send logging info to DebugView window (google DebugView),
  87.             allows monitoring of progress without the slightly risky method of reading the open LogFile.
  88.             Default True as cannot change your mind in middle of long search, does not have significant overhead in producing debug log.
  89.             False, switch real time debug logging off.
  90.             This setting has nothing whatever to do with below pre v1.10 DEBUG MODE, see below.
  91.  
  92.  X        = int[0], X coord, allow avoid some edge artefact or logo.
  93.  Y        = int[0], Y coord, allow avoid some edge artefact or logo.
  94.  W        = int[0], W coord, allow avoid some edge artefact or logo.
  95.  H        = int[0], H coord, allow avoid some edge artefact or logo.
  96.  
  97. 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)
  98.  
  99.  PD       = False. New in v1.13, uses Pearsons Distance measure instead of RT_FrameDifference (well actually a limited variation of it).
  100.             To make the function work with both RT_FrameDifference and the PD=True methods, it is necessary for them  both to return similar-ish
  101.             value, ie 0.0 being identical and 255.0 being totally different. RT__FrameDifference returns the average pixel difference across the
  102.             whole frame (in X,Y,W,H area). For RT_FrameDifference can also weight in the U&V compnent differences by specifying ChromaWeight.
  103.             For RGB, a little new functionality has been added (RT_Stats v2.0). If ChromaWeight is specified as 0.0, then RT_FrameDifference
  104.             returns Exactly the same as LumaDifference, but if ChromaWeight is non 0.0, then for RGB, it will return the average channgel difference,
  105.             ie (RDif + GDif + BDif) / 3. [For LumaDifference mode, RGB converted to Luma-Y, uses Matrix arg].
  106.             Our limited version of Pearsons Distance goes like this
  107.                 PD = Min(1.0 - LumaCorrelation, 1.0) * 255.0, result in range 0.0 -> 255.0 where 0.0 means identical.
  108.             when PD=True, ChromaWeight has no function.
  109.             Pearsons distance, based on Correlation, is not so perturbed by small changes in frame bightness, and may be better for matching
  110.             than the standard Average Pixel Difference mode.
  111.             Correlation      limited PD
  112.                 1.00             00.00
  113.                 0.95             12.75
  114.                 0.90             25.50
  115.                 0.85             38.25
  116.                 0.80             51.00
  117.                 0.75             63.75
  118.                 0.70             76.50
  119.                 0.65             89.25
  120.                 0.60            102.00
  121.                 0.55            114.75
  122.                 0.50            127.50
  123.  
  124.  ##################################
  125.  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
  126.  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
  127.  f and c are same.
  128.  In Debug Mode, there is no searching for best match, log is produced with difference between all corresponding frames
  129.  and in the footer of the log, it will show Average Diff, Min Diff, and Max Diff for the entire frame set.
  130.  In DEBUG MODE, the command file is cleared, prints header only.
  131.  ##################################
  132.  
  133.  Will take some time to show results, it is not a bug if it seems to hang, it is WORKING HARD.
  134.  
  135. */
  136.  
  137. Function MatchFrames(clip c,clip f,bool "Show",float "Thresh",float "Thresh2",string "FileName",string "LogFile",
  138.         \ int "Start",int "Stop",bool "XP", Bool "Chroma",Float "ChromaWeight",string "Title",bool "Debug",
  139.         \ int "X",int "Y",int "W",int "H",Int "Matrix",Bool "PD"
  140.         \ ) {
  141.     ver         = "v1.13 - 26 OCt 2016"                # Version Number
  142.     myName      ="MatchFrames: "
  143.     c = c.Killaudio()   f = f.Killaudio()               # Audio return not sensible.
  144.     Show        = Default(Show,true)                    # Defaults true = show StackHorizontal find & found frames
  145.     Thresh      = Float(Default(Thresh, 0.0))           # Threshold for declaring match, Default==0.0 to search for best possible match.
  146.     Thresh2     = Float(Default(Thresh2,0.0))           # Threshold2 Default==0.0, find clip f, not time ordered.
  147.     FileName    = Default(FileName,"MatchFramesCmd.txt")# "" to switch OFF Frames output command file.
  148.     LogFile     = Default(LogFile,"MatchFrames.Log")    # "" to switch OFF Logfile.
  149.     Start       = Default(Start,0)                      # Frame to start search from.
  150.     Stop        = Default(Stop,0)                       # Frame to stop search (0 == last frame + 1).
  151.     XP          = Default(XP,true)                      # Extra Paranoid, dont fully trust Thresh.
  152.     Chroma      = Default(Chroma,True)                  # Default Luma + Chroma.
  153.     ChromaWeight= Float(Default(ChromaWeight,1.0/3.0))  # Default, 33% of Total Difference (Combined U and V).
  154.     Title       = Default(Title,"")                     # Shown in log and command file, Default "".
  155.     Debug       = Default(Debug,True)                   # Default no debug logging to DebugView
  156.     X           = Default(X,0)
  157.     Y           = Default(Y,0)
  158.     W           = Default(W,0)
  159.     H           = Default(H,0)
  160.     Matrix      = Default(Matrix,2)                     # PC601
  161.     PD          = Default(PD,False)
  162.     Start       = (Start<0)?0:Start                     # Silent check
  163.     Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
  164.     cfrms       = Stop-Start                            # Number of frames to scan in c
  165.     ChromaWeight=(Chroma)?ChromaWeight:0.0              # If Not Needed, ignore default weight.
  166.     Assert(c.Width==f.Width,myName+"- Clip Width mismatch")
  167.     Assert(c.Height==f.Height,myName+"- Clip Height mismatch")
  168.     Assert(RT_VarIsSame(c,f),myName+"- ColorSpace Mismatch")    # Same colorspace ?
  169.     Assert(cfrms>0,myName+"- Invalid Start>=Stop")
  170.     Assert(Thresh>=0.0,myName+"- Invalid Thresh")
  171.     Assert(f.Framecount<=cfrms,myName+"- f Frames > c[START,STOP] Frames")
  172.     Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,myName+"- ChromaWeight Range 0.0->1.0")
  173.     DBug = (cfrms==f.FrameCount && Thresh < Thresh2)    # Debugging Mode ?
  174.     Thresh  = (DBug) ? 255.0 : Thresh                   # If DBug, Ensure everything breaks Thresh.
  175.     Thresh2 = (DBug) ? 255.1 : Thresh2                  # If DBug, Maintain Ordered.
  176.     TDHi =0.0                                           # DEBUG: TotalDifference Hi  (Extra precision)
  177.     TDLo =0.0                                           # DEBUG: TotalDifference Lo
  178.     MinDiff  = 255.0 + 1.0                              # DEBUG: Output, max + 1
  179.     MaxDiff  = 0.0 - 1.0                                # DEBUG: Output, min - 1
  180.     Ordered  = Thresh < Thresh2                         # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
  181.     Result = 0                                          # Dummy, Will become a Clip, Dont use 'c.BlankClip(length=0)' (Maybe StackHorizontal)
  182.     Scanned = 0                                         # Init Total Frames scanned
  183.     EOL = Chr(10)                                       # End Of Line. (Do NOT use Carriage Return, Line Feed, Will auto add the CR)
  184.     TLINE = "##########################################################################" + EOL
  185.     TGEN  = "# MatchFrames " + Ver
  186.     TCMD  = "Command File for FrameSel() Plugin." + EOL + "#" + EOL
  187.     TLOG  = " (c) StainlessS : LogFile." + EOL + "#" + EOL
  188.     TNAM  = (Title=="") ? "" : "# Title='" + Title + "'" + EOL + "#" + EOL
  189.     TSET  = "# Width=" + String(c.Width) + " : Height=" + String(c.Height) + " : Start=" + String(Start) + " : Stop=" + String(Stop)
  190.             \ + ((ORDERED && !DBug) ? " : ORDERED" : "") + EOL+"#"+EOL
  191.     TSET2 = "# Thresh="+String(Thresh,"%.3f")+" : Thresh2="+String(Thresh2,"%.3f")+" : XP="+String(XP)
  192.     TSET3 = ((Chroma)?" : ChromaWeight="+String(ChromaWeight,"%.3f"):"") + EOL + "#" + EOL
  193.     TSET4 = ((DBug) ? "# DEBUG MODE" + EOL:"") + "#" + EOL
  194.     LogT = RT_String("%s#\n%s%s%s%s%s%s%s%s",TLINE,TGEN,TLOG,TNAM,TSET,TSET2,TSET3,TSET4,TLINE)
  195.     (Debug) ? RT_DebugF("%s",LogT,name=myName)  : NOP           # DebugView
  196.     (LogFile !="") ? RT_WriteFile(LogFile, "%s",LogT)   : NOP
  197.     (FileName!="") ? RT_WriteFile(FileName,"%s#\n%s : %s%s%s%s%s%s%s",TLINE,TGEN,TCMD,TNAM,TSET,TSET2,TSET3,TSET4,TLINE) : NOP
  198.     FileName= (DBug) ? "" : FileName                # No Command file frame numbers if DBug Mode, HEADER ONLY (ie Wipe command file).
  199.     TimeStart = RT_LocalTimeString(file=false)      # Format "YYYY-MM-DD HH:MM:SS.mmm"
  200.     Start_Secs = RT_TimerHP()
  201.     GScript("""
  202.    for(ix = 0, f.Framecount-1) {                   # Iterate through find frames clip.
  203.        s = Start                                   # Init Start search position
  204.        BestSoFar       = s                         # Search start position
  205.        BestSoFarDiff   = 255.0 + 1.0               # Maximum Possible + 1
  206.        sS =" S=" + String(s,"%-4.0f")              # Start offset this time, as string (at least 4 digits)
  207.        mS=" (BM:  )"                               # Init to 'scanned all the way' message (Flag Best Match).
  208.        eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
  209.        e=eterm                                     # Init to 'scanned all the way'
  210.        Assert(s<=e,myName+"- Internal Error, s > e")  # Oops.
  211.        xS=""                                       # Prep XP skip Count string
  212.        for(n=s, eterm) {                           # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
  213.            # Difference to current find frame.
  214.            CurrDiff=(PD)
  215.                \ ? Min(1.0-RT_LumaCorrelation(c,f,n=n,x=X,y=Y,w=W,h=H,n2=ix,Matrix=Matrix),1.0)*255.0
  216.                \ : RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  217.            if(CurrDiff < BestSoFarDiff) {                      # Better match than found so far ?
  218.                BestSoFar       = n                             # Remember frame number
  219.                BestSoFarDiff   = CurrDiff                      # Remember difference
  220.                if(BestSoFarDiff <= thresh) {                   # Good enough to satisfy user requirement ?
  221.                    if(DBug) {                                  # DEBUG
  222.                        MinDiff = Min(CurrDiff,MinDiff)
  223.                        MaxDiff = Max(CurrDiff,MaxDiff)
  224.                        TDLo = TDLo + CurrDiff
  225.                        TDHi = TDHi + floor(TDLo / 256.0)       # Hi part, Extra Precision
  226.                        TDLo = frac(TDLo / 256.0) * 256.0       # Lo part, Extra Precision
  227.                    }
  228.                    e=BestSoFar                                 # Where we've scanned to so far
  229.                    mS=" (T1:  )"                               # Found satisfactory frame, (Flag Thresh)
  230.                    if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
  231.                        tmp = BestSoFar                         # Remember
  232.                        for(n=BestSoFar+1,eterm) {
  233.                            CurrDiff=(PD)
  234.                                \ ? Min(1.0-RT_LumaCorrelation(c,f,n=n,x=X,y=Y,w=W,h=H,n2=ix,Matrix=Matrix),1.0)*255.0
  235.                                \ : RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  236.                            e=n                                 # We scanned more frames past original BestSoFar
  237.                            if(CurrDiff < BestSoFarDiff) {      # Better match ?
  238.                                if(ix < f.Framecount-1) {
  239.                                    # Check if XP advance makes problem for next ix find
  240.                                    ChkDiff=(PD)
  241.                                        \ ? Min(1.0-RT_LumaCorrelation(c,f,n=n,x=X,y=Y,w=W,h=H,n2=ix+1,Matrix=Matrix),1.0)*255.0
  242.                                        \ : RT_FrameDifference(c,f,n=n,n2=ix+1,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  243.                                    if(ChkDiff>CurrDiff) {              # OK, no problem for next ix iteration
  244.                                        BestSoFar    = n                # Remember frame number
  245.                                        BestSoFarDiff= CurrDiff         # Remember
  246.                                    } Else {            # Override XP advance
  247.                                        n = eterm+1     # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
  248.                                    }
  249.                                } Else {
  250.                                    BestSoFar    = n                # Remember frame number
  251.                                    BestSoFarDiff= CurrDiff         # Remember
  252.                                }
  253.                            } else {
  254.                                n = eterm+1                     # Force Exit with n == eterm + 2 (normally exit @ eterm+1)
  255.                            }
  256.                        }
  257.                        if(BestSoFar != tmp) {
  258.                            mS=" (T1:XP)"                       # Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
  259.                            xS=" XPCNT=" + String(BestSoFar-tmp)# How many frames Xtra Paranoid skipped to find better match than Thresh.
  260.                        }
  261.                    }
  262.                    Start=(Ordered)?BestSoFar+1:Start           # If required, Next time search from BestSoFar + 1
  263.                    n = eterm + 1                               # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
  264.                }
  265.            }
  266.        }
  267.        if(Ordered && n == eterm+1 && BestSoFarDiff < Thresh2) {
  268.            mS = " (BM:T2)"                                     # For Log, Time ordered, (Flag, Best Match and Thresh2)
  269.            Start = BestSoFar + 1                               # Next time start from BEST MATCH found + 1.
  270.        }
  271.        Scanned = Scanned + e - s + 1
  272.        Text = RT_String("%4d]=[%6d] Diff=%7.3f%s%s E =%-4.0f%s",ix,BestSoFar,BestSoFarDiff,ms,sS,e,xS)
  273.        (Debug) ? RT_DebugF("%s",Text,name=myName) : NOP                                            # DebugView
  274.        (LogFile!="")  ? RT_WriteFile(LogFile,"%s",Text,Append=true) : NOP              # Log file
  275.        (FileName!="") ? RT_WriteFile(FileName,"%d",BestSoFar,Append=true) : NOP        # Command file
  276.        FindFrame =f.Trim(ix,-1).SubTitle(Text)
  277.        wrClip    =c.Trim(BestSoFar,-1)
  278.        GotFrame=(Show) ? StackHorizontal(FindFrame,wrClip) : wrClip
  279.        Result = (IsClip(Result)) ? Result ++ GotFrame : GotFrame                       # Append to 'result clip so far'.
  280.    }
  281.    """) # End Of GScript
  282.     TimeEnd = RT_LocalTimeString(file=false)
  283.     Tim = RT_TimerHP - Start_Secs
  284.     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)
  285.     Text2 = RT_String("Total Frames Searched =%6d (%7.3f FPS : %10.6f SPF)",Scanned,Scanned/Tim,Tim/Scanned)
  286.     Text3 = RT_String("Find Frames Located   =%6d (%7.3f FPS : %10.6f SPF)",f.FrameCount,f.FrameCount/Tim,Tim/f.FrameCount)
  287.     (Debug) ? RT_DebugF("%s\n%s\n%s",Text,Text2,Text3,name=myName) : NOP
  288.     (LogFile!="") ? RT_WriteFile(LogFile,"%s\n%s\n%s",Text,Text2,Text3,Append=True) : NOP
  289.     Text4 = RT_String("DEBUG: AveDiff=%.3f : MinDiff=%.3f : MaxDiff=%.3f : [L=%.3f : (U+V)=%.3f]\n",
  290.         \ (TDHi / cfrms * 256.0) + (TDLo / cfrms),MinDiff,MaxDiff,1.0-ChromaWeight,ChromaWeight)
  291.     (DBug&&Debug)       ? RT_DebugF("%s",Text4,name=myName)             : NOP
  292.     (DBug&&LogFile!="") ? RT_WriteFile(LogFile,"%s",Text4,Append=True)  : NOP
  293.     Return Result.AssumeFPS(1.0)
  294. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement