Advertisement
Guest User

LocateFrames.avs

a guest
Oct 25th, 2016
446
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Avisynth 22.53 KB | None | 0 0
  1. Function LocateFrames(clip c,clip f,float "Thresh",float "Thresh2",int "Start",int "Stop",bool "XP", Bool "Chroma", \
  2.       Float "ChromaWeight",String "Prefix",bool "Debug",String "DB",int "X",int "Y",int "W",int "H",Int "Matrix",Bool "PD") {
  3.  
  4. /*
  5.  LocateFrames() v1.13 by StainlessS:
  6.  Find frames in c clip that are best matched to frames in f clip.
  7.  Planar, YUY2, RGB24/32.
  8.  
  9.  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.
  10.  
  11.  ##################################
  12. Based on FindFrame() (c) Gavino.         http://forum.doom9.org/showthread.php?p=1569622#post1569622
  13.  Required: GScript    (c) Gavino:         http://forum.doom9.org/showthread.php?t=147846
  14.  Required: RT_Stats v2.0 (c) StainlessS:  http://forum.doom9.org/showthread.php?p=1584313
  15.  Recommended FrameSel (c) StainlessS:     http://forum.doom9.org/showthread.php?t=167971
  16.  Recommended DebugView utility to view and capture output: http://technet.microsoft.com/en-gb/sysinternals/bb545027
  17.  MatchFrames  THREAD:                     http://forum.doom9.org/showthread.php?t=164766
  18.  LocateFrames POST:                       http://forum.doom9.org/showthread.php?p=1600961#post1600961
  19.   ##################################
  20.  
  21. Function LocateFrames(clip c,clip f,float "Thresh"=0.0,float "Thresh2"0.0,int "Start"=0,int "Stop"=0,bool "XP"=True, Bool "Chroma"=false, \
  22.       Float "ChromaWeight"=1/3.0,String "Prefix"="LF_",bool "Debug"=True,String "DB"="",int "X"=0,int "Y"=0,int "W"=0,int "H"=0,Int "Matrix"=2,Bool "PD"=False) {
  23.  
  24.  Args:
  25.  
  26.  c       = clip, Source clip.
  27.  f       = clip, Consisting of frames that you wish to find in the c clip.
  28.  Thresh  = float[0.0 == Search for 1st exact match or best possible if no exact match found]. Threshold for declaring match (diff <= Thresh).
  29.            Range 0.0 -> 255.0.
  30.  Thresh2 = float[0.0 == NOT time ordered]. Both a 'time ordered' indicator and a threshold.
  31.            If (Thresh < Thresh2) Then clip f is taken as time ordered (in c), ie frames in both f and c clips are temporally ordered.
  32.            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.
  33.  
  34.            Assuming time ordered f clip (Thresh < Thresh2),
  35.  
  36.                If a match found where diff of find to found frame <= Thresh,
  37.                     Next frame search will start from found frame + 1.
  38.                Else if diff of find to Full Scan BEST found frame < Thresh2
  39.                     Next frame search will start from BEST found frame + 1.
  40.                Else
  41.                     Next frame search will start from current start position.
  42.                End if
  43.                *** Where above 'Full Scan' means scan from current start postion to the last valid search frame.
  44.  
  45.  Start   = int[0, == First frame of clip], Start frame to search from (eg Skip introduction).
  46.  Stop    = int[0, == Last frame of clip + 1], Frame prior to which, c clip is searched (Exclusive). (eg Skip end credits).
  47.  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.
  48.                If diff of find to found frame <= Thresh, then search would normally stop at that frame, but when
  49.                XP is true (Default), it will continue to search so long as subsequent frames provide a better match. Will usually result
  50.                in 1 extra frame being compared (providing that your Thresh is not too high).
  51.                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
  52.                (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
  53.                match is found, it will continue to edge forward 1 frame at a time until matches cease to be better.
  54.                If exact match was found, ie diff == 0.0 then will not scan extra frames (no better match possible).
  55.  
  56.  Chroma   = bool[false==Luma diff Only], If true then also uses chroma difference as per ChromaWeight.
  57.                THIS IS NO LONGER FUNCTIONAL, totally switched now via the ChromaWeight arg.
  58.  
  59.  ChromaWeight=float[1.0/3.0 ie 0.33333]. If Chroma==true then LumaWeight = 1.0-ChromaWeight.
  60.                Now Planar, YUY2, RGB (was YV12 only), Chroma and ChromaWeight are for YUV only, not used for Y8 or RGB,
  61.                no real advantage to using Luma only.
  62.  Prefix   = string("LF_"). Prefix prepended to variable names in returned string. (NOT USED if DBase mode, see below DB arg)
  63.  Debug    = bool[True == Debug info sent to debugview], True, send logging info to DebugView window (google DebugView),
  64.             allows monitoring of progress.
  65.             v1.10, Default True as cannot change your mind in middle of long search, does not have significant overhead in producing debug log.
  66.             False, switch real time debug logging off.
  67.  
  68.  DB       = string["" == Do Not Use DataBase]. Default "" as old version, where results returned in String as described below.
  69.             v1.10, Otherwise, if DB != "" eg "LocateFrames.DB", then will create an RT_Stats DBase file using supplied DB as the filename,
  70.             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
  71.             number of records stored in the DB File. DB file created with typestring "iifiiii", in other words 7 fields per record.
  72.             First two fields are Type Int, next 1 field of Type Float, then 4 fields of Type Int.
  73.               Field 0 : Type Int   : LF_FOUND      Index of found clip frame
  74.               Field 1 : Type Int   : LF_FIND       Index of find clip frame
  75.               Field 2 : Type Float : LF_DIFF       FrameDifference() between find and found
  76.               Field 3 : Type Int   : LF_START      Start frame searched
  77.               Field 4 : Type Int   : LF_END        End frame searched
  78.               Field 5 : Type Int   : LF_XPCNT      Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
  79.               Field 6 : Type Int   : LF_MATCH      Kind of match found.  # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1:  )", 3="(T1:XP)"
  80.               See below for explanation of field contents, and RT_Stats for usage of RT_DBaseGetField(String Filename,Int Record,Int Field).
  81.  
  82.  X        = int[0], X coord, allow avoid some edge artefact or logo.
  83.  Y        = int[0], Y coord, allow avoid some edge artefact or logo.
  84.  W        = int[0], W coord, allow avoid some edge artefact or logo.
  85.  H        = int[0], H coord, allow avoid some edge artefact or logo.
  86.  
  87.  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)
  88.  
  89.  PD       = False. New in v1.13, uses Pearsons Distance measure instead of RT_FrameDifference (well actually a limited variation of it).
  90.             To make the function work with both RT_FrameDifference and the PD=True methods, it is necessary for them  both to return similar-ish
  91.             value, ie 0.0 being identical and 255.0 being totally different. RT__FrameDifference returns the average pixel difference across the
  92.             whole frame (in X,Y,W,H area). For RT_FrameDifference can also weight in the U&V compnent differences by specifying ChromaWeight.
  93.             For RGB, a little new functionality has been added (RT_Stats v2.0). If ChromaWeight is specified as 0.0, then RT_FrameDifference
  94.             returns Exactly the same as LumaDifference, but if ChromaWeight is non 0.0, then for RGB, it will return the average channgel difference,
  95.             ie (RDif + GDif + BDif) / 3. [For LumaDifference mode, RGB converted to Luma-Y, uses Matrix arg].
  96.             Our limited version of Pearsons Distance goes like this
  97.                 PD = Min(1.0 - LumaCorrelation, 1.0) * 255.0, result in range 0.0 -> 255.0 where 0.0 means identical.
  98.             when PD=True, ChromaWeight has no function.
  99.             Pearsons distance, based on Correlation, is not so perturbed by small changes in frame bightness, and may be better for matching
  100.             than the standard Average Pixel Difference mode.
  101.             Correlation      limited PD
  102.                 1.00             00.00
  103.                 0.95             12.75
  104.                 0.90             25.50
  105.                 0.85             38.25
  106.                 0.80             51.00
  107.                 0.75             63.75
  108.                 0.70             76.50
  109.                 0.65             89.25
  110.                 0.60            102.00
  111.                 0.55            114.75
  112.                 0.50            127.50
  113.  
  114.  ##################################
  115.  
  116.  Returns newline [Chr(10)] separated list of results as a multiline String, OR results stored in DB Database File, where it returns
  117.   the number of records in the DB file (ie frames in Findclip f).
  118.  
  119.   STRING RESULT:-
  120.    Results string for a single frame find clip using default "LF_" prefix, as in format:-
  121.  
  122.      "LF_FOUND=1100   LF_FIND=0   LF_DIFF=0.006134 LF_START=1000   LF_END=1599   LF_XPCNT=0   LF_MATCH=0"
  123.  
  124.      LF_FOUND= Index of found clip frame
  125.      LF_FIND = Index of find clip frame
  126.      LF_DIFF = FrameDifference() between find and found (range 0.0 -> 255.0)
  127.      LF_START= Start frame searched
  128.      LF_END  = End frame searched
  129.      LF_XPCNT= Count of extra frames advanced due to eXtra Paranoia setting, See above XP.
  130.      LF_MATCH= Kind of match found.  # As for MatchFrames(), 0="BM", 1="(BM:T2)", 2="(T1:  )", 3="(T1:XP)"
  131.  
  132.            0= Best Match, where no frame was found with a Diff <= Thresh, the returned frame was best match found in search area.
  133.            1= Same as 0 but was an Ordered search & because Diff<Thresh2, then next frame search will start at Best Match+1.
  134.            2= Means that the found frame had a Diff <= Thresh.
  135.            3= Same as 2 but Xtra Paranoia (XP) successfully found a better matching frame following the one that
  136.               initially broke thresh. "XPCNT" will tell how many successive better frames were found after the initial
  137.               frame that broke Thresh.
  138.  
  139.    Can use RT_Stats functions eg
  140.      RT_TxtQueryLines() to inquire lines of text in result string (same as frames in find f clip).
  141.      RT_TxtGetLine() to extract a single result (if multiple find frames) from the combined results string.
  142.    Can use eg "Eval(s)" to set variables where s is a single line result string.
  143.  
  144.    The innards of LocateFrames are much like MatchFrames, but could be more useful as implemented to use results
  145.    programatically in other scripts.
  146.  
  147.    Use DebugView utility to view and capture output.
  148.  
  149.    Brief example usage:
  150.  
  151.     GScript("""
  152.        myName="StringResultScript:"
  153.        SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000)                                   # 1000 frame SearchClip
  154.        FindClip=SearchClip.SelectEvery(100,0).Blur(1.58)                                           # 10 frame FindClip, Make a bit Different
  155.        Results=LocateFrames(searchclip,findclip)
  156.        n = RT_TxtQueryLines(Results)                                                               # Same as number of frames in findclip.
  157.        Result = 0                                                                                  # Will become clip
  158.        for(i=0,n-1) {
  159.            s=RT_TxtGetLine(Results,Line=i)                                                         # Get individual result string
  160.            Eval(s)                                                                                 # Set variables for this find frame
  161.            RT_DebugF("Found frame %d for find frame %d Had a diff of %f",LF_FOUND,LF_FIND,LF_DIFF,name=myName)
  162.            Lft=FindClip.Trim(LF_FIND,-1).RT_SubTitle("%d DIFF=%f",LF_FIND,LF_DIFF)                 # Find Frame
  163.            Rgt=SearchClip.Trim(LF_FOUND,-1).RT_SubTitle("%d",LF_FOUND)                             # Found Frame
  164.            Stak = StackHorizontal(Lft,Rgt)
  165.            Result = (Result.IsClip) ? Result ++ Stak : Stak                                        # Append to clip so far
  166.        }
  167.        Return Result.AssumeFPS(1.0)
  168.     """)
  169.     Return Last
  170.  ##################################
  171.  
  172.  DBASE RESULT:- (actual result is Int, number of records in created DB, ie frames in FindClip)
  173.  
  174.     SearchClip=avisource("D:\avs\xmen2.avi").trim(4000,-1000)                                      # 1000 frame SearchClip
  175.     FindClip=SearchClip.SelectEvery(100,0).Blur(1.58)                                              # 10 frame FindClip, Make a bit Different
  176.     DEBUG=True
  177.     myName="DB_Script: "
  178.     DB="~MyDbase_" + RT_LocalTimeString(File=True)+".DB"                                           # Unique Temporary DBase filename
  179.     Records = LocateFrames(SearchClip,FindClip,debug=DEBUG,db=DB)                                  # Same as number of frames in FindClip.
  180.     RT_DebugF("I got %d Records",Records,name=myName)                                              # Send to DebugView
  181.     Result = 0                                                                                     # Will later be a clip
  182.     GScript("""
  183.         for(i=0,Records-1) {
  184.             FoundIx = RT_DBaseGetField(DB,i,0)                                                      # Frame we found (Int)
  185.             FindIx  = RT_DBaseGetField(DB,i,1)                                                      # Frame that we had to find (Int)
  186.             Diff    = RT_DBaseGetField(DB,i,2)                                                      # FrameDifference (Float)
  187.             RT_DebugF("%d ] Found frame %d with Difference of %f",FindIx,FoundIx,Diff,name=myName)
  188.             Lft=FindClip.Trim(FindIx,-1).RT_SubTitle("%d DIFF=%f",FindIx,Diff)                      # Find Frame
  189.             Rgt=SearchClip.Trim(FoundIx,-1).RT_SubTitle("%d",FoundIx)                               # Found Frame
  190.             Stak = StackHorizontal(Lft,Rgt)
  191.             Result = (Result.IsClip) ? Result ++ Stak : Stak                                        # Append to clip so far
  192.         }
  193.         RT_FileDelete(DB)                                                                           # Delete temp DB file
  194.     """)
  195.     Return Result.AssumeFPS(1.0)
  196. */
  197.  
  198.  ##################################
  199.     myName      = "LocateFrames: "
  200.     ver         = "v1.13 - 26 OCt 2016"                 # Version Number
  201.     c = c.Killaudio()   f = f.Killaudio()               # Audio not needed.
  202.     Thresh      = Default(Thresh, 0.0)                  # Threshold for declaring match, Default==0.0 to search for best possible match.
  203.     Thresh2     = Default(Thresh2,0.0)                  # Threshold2 Default==0.0, find clip f, not time ordered.
  204.     Start       = Default(Start,0)                      # Frame to start search from.
  205.     Stop        = Default(Stop,0)                       # Frame to stop search (0 == last frame + 1).
  206.     XP          = Default(XP,true)                      # Extra Paranoid, dont fully trust Thresh.
  207.     Chroma      = Default(Chroma,False)                 # Default Luma Only.
  208.     ChromaWeight= Default(ChromaWeight,1.0/3.0)         # Default, 33% of Total Difference (Combined U and V).
  209.     Prefix      = Default(Prefix,"LF_")
  210.     Debug       = Default(Debug,True)                   # v1.10, changed True
  211.     DB          = Default(DB,"")                        # DBase not default
  212.     X           = Default(X,0)
  213.     Y           = Default(Y,0)
  214.     W           = Default(W,0)
  215.     H           = Default(H,0)
  216.     Matrix      = Default(Matrix,2)                     # PC601
  217.     PD          = Default(PD,False)
  218.     Start       = (Start<0)?0:Start                     # Silent check
  219.     Stop=(Stop<=0||Stop>c.FrameCount)?c.FrameCount:Stop # Silent check
  220.     cfrms       = Stop-Start                            # Number of frames to scan in c
  221.     ChromaWeight=(Chroma)?ChromaWeight:0.0              # If Not Needed, ignore default weight.
  222.     Assert(c.Width==f.Width,myName+"- Clip Width mismatch")
  223.     Assert(c.Height==f.Height,myName+"- Clip Height mismatch")
  224.     Assert(RT_VarIsSame(c,f),myName+"- ColorSpace Mismatch")    # Same colorspace ?
  225.     Assert(cfrms>0,myName+"- Invalid Start>=Stop")
  226.     Assert(Thresh>=0.0,myName+"- Invalid Thresh")
  227.     Assert(f.Framecount<=cfrms,myName+"- f Frames > c[START,STOP] Frames")
  228.     Assert(ChromaWeight>=0.0&&ChromaWeight<=1.0,myName+"- ChromaWeight Range 0.0->1.0")
  229.     MODE = (DB!="")
  230.     Ordered  = Thresh < Thresh2                         # If true then: Find frames are in time order (match(f[n]) searches from match(f[n-1])+1
  231.     FMT="%sFOUND=%-6d %sFIND=%-6d %sDIFF=%f %sSTART=%d %sEND=%-6d %sXPCNT=%-3d %sMATCH=%d"
  232.     Result = ""
  233.     GScript("""
  234.        (DEBUG) ? RT_DebugF("\n%s %s (%s Mode)\n",myName, Ver,(!MODE)? "STRING" : "DBASE",name=myName) : NOP
  235.        if(MODE) {RT_DBaseAlloc(DB,0,"iifiiii")}
  236.        for (ix = 0, f.Framecount-1) {                  # Iterate through find frames clip.
  237.            s = Start                                   # Init Start search position
  238.            BestSoFar       = s                         # Search start position
  239.            BestSoFarDiff   = 255.0 + 1.0               # Maximum Possible + 1
  240.            sS =s                                       # Start offset this time
  241.            mS= 0                                       # " (BM:  )", Init to 'scanned all the way' message (Flag Best Match).
  242.            eterm=(Ordered)?Stop-f.Framecount+ix:Stop-1 # Init last frame to compare for this iteration.
  243.            e=eterm                                     # Init to 'scanned all the way'
  244.            Assert(s<=e,myName+"- Internal Error, s > e")  # Oops.
  245.            xpCnt=0                                     # Prep XP skip Count string
  246.            for(n=s, eterm) {               # Search c clip(s to eterm) or until satisfactory match found. (eterm evaluated on entry only)
  247.                # Difference to current find frame.
  248.                CurrDiff=(PD)
  249.                    \ ? 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
  250.                    \ : RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  251.                if(CurrDiff < BestSoFarDiff) {          # Better match than found so far ?
  252.                    BestSoFar       = n                 # Remember frame number
  253.                    BestSoFarDiff   = CurrDiff          # Remember difference
  254.                    if(BestSoFarDiff <= thresh) {       # Good enough to satisfy user requirement ?
  255.                        e=BestSoFar                     # Where we've scanned to so far
  256.                        mS=2                            # " (T1:  )", Found satisfactory frame, (Flag Thresh)
  257.                        if(XP && BestSoFar < eterm && BestSoFarDiff > 0.0) { # DBug will NOT enter here!, eterm condition will fail.
  258.                            tmp = BestSoFar             # Remember
  259.                            for(n=BestSoFar+1,eterm) {
  260.                                CurrDiff=(PD)
  261.                                    \ ? 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
  262.                                    \ : RT_FrameDifference(c,f,n=n,n2=ix,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  263.                                e=n                                 # We scanned more frames past original BestSoFar
  264.                                if(CurrDiff < BestSoFarDiff) {      # Better match ?
  265.                                    if(ix < f.Framecount-1) {
  266.                                        # Check if XP advance makes problem for next ix find
  267.                                        ChkDiff=(PD)
  268.                                            \ ? 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
  269.                                            \ : RT_FrameDifference(c,f,n=n,n2=ix+1,ChromaWeight=ChromaWeight,Matrix=Matrix,x=X,y=Y,w=W,h=H)
  270.                                        if(ChkDiff>CurrDiff) {              # OK, no problem for next ix iteration
  271.                                            BestSoFar    = n                # Remember frame number
  272.                                            BestSoFarDiff= CurrDiff         # Remember
  273.                                        } Else {            # Override XP advance
  274.                                            n = eterm+1     # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
  275.                                        }
  276.                                    } Else {
  277.                                        BestSoFar    = n                # Remember frame number
  278.                                        BestSoFarDiff= CurrDiff         # Remember
  279.                                    }
  280.                                } else {
  281.                                    n = eterm+1                     # Force Exit with current_frame == eterm + 2 (normally exit @ eterm+1)
  282.                                }
  283.                            }
  284.                            if(BestSoFar != tmp) {
  285.                                mS=3                   # " (T1:XP)", Found satisfactory frame, (Flag Thresh, and Xtra Paranoid found better frame)
  286.                                XpCnt=BestSoFar-tmp    # How many frames Xtra Paranoid skipped to find better match than Thresh.
  287.                            }
  288.                        }
  289.                        Start=(Ordered)?BestSoFar+1:Start   # If required, Next time search from BestSoFar + 1
  290.                        n = eterm + 1                       # Force Exit with current_frame == eterm + 2 (normally exit @ eterm + 1)
  291.                    }
  292.                }
  293.            }
  294.            if(Ordered && n == eterm+1 && BestSoFarDiff < Thresh2) {
  295.                mS = 1                                      # " (BM:T2)", For Log, Time ordered, (Flag, Best Match and Thresh2)
  296.                Start = BestSoFar + 1                       # Next time start from BEST MATCH found + 1.
  297.            }
  298.            if(MODE) {
  299.                (DEBUG) ? RT_DebugF(FMT,Prefix,BestSoFar,Prefix,ix,Prefix,BestSoFarDiff,Prefix,sS,Prefix,e,Prefix,XpCnt,Prefix,mS,name=myName) : NOP
  300.                RT_DBaseAppend(DB,BestSoFar,ix,BestSoFarDiff,sS,e,XpCnt,mS)
  301.            } Else {
  302.                Text = RT_String(FMT, Prefix,BestSoFar,Prefix,ix,Prefix,BestSoFarDiff,Prefix,sS,Prefix,e,Prefix,XpCnt,Prefix,mS)
  303.                Result = RT_TxtAddStr(Result,Text)              # Avoid string concatenation bug in v2.58 and v2.6a3.
  304.                (DEBUG) ? RT_DebugF("%s",Text,name=myName) : NOP
  305.            }
  306.        }
  307.    """) # End Of GScript
  308.     return (MODE) ? f.FrameCount : Result           # Int return for Dbase and String if not DBase
  309. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement