class_docstr: Frames matches inside a set of frames.
  
  You can instantiate it passing a list of FramesMatch objects or
  using the class methods ``load`` and ``from_clip``.
  
  Parameters
  ----------
  
  lst : list
    Iterable of FramesMatch objects.
class_docstr_tok: ["Frames","matches","inside","a","set","of","frames",".","You","can","instantiate","it","passing","a","list","of","FramesMatch","objects","or","using","the","class","methods","``","load","``","and","``","from_clip","``",".","Parameters","--","--","--","--","--","lst",":","list","Iterable","of","FramesMatch","objects","."]
docstr: Finds all the frames that look alike in a clip, for instance to make
  a looping GIF.
  
  Parameters
  ----------
  
  clip : moviepy.video.VideoClip.VideoClip
    A MoviePy video clip.
  
  distance_threshold : float
    Distance above which a match is rejected.
  
  max_duration : float
    Maximal duration (in seconds) between two matching frames.
  
  fps : int, optional
    Frames per second (default will be ``clip.fps``).
  
  logger : str, optional
    Either ``"bar"`` for progress bar or ``None`` or any Proglog logger.
  
  Returns
  -------
  
  FramesMatches
      All pairs of frames with ``end_time - start_time < max_duration``
      and whose distance is under ``distance_threshold``.
  
  Examples
  --------
  
  We find all matching frames in a given video and turn the best match
  with a duration of 1.5 seconds or more into a GIF:
  
  >>> from moviepy import VideoFileClip
  >>> from moviepy.video.tools.cuts import FramesMatches
  >>>
  >>> clip = VideoFileClip("foo.mp4").resize(width=200)
  >>> matches = FramesMatches.from_clip(
  ...     clip, distance_threshold=10, max_duration=3,  # will take time
  ... )
  >>> best = matches.filter(lambda m: m.time_span > 1.5).best()
  >>> clip.subclip(best.start_time, best.end_time).write_gif("foo.gif")
docstr_tok: ["Finds","all","the","frames","that","look","alike","in","a","clip",",","for","instance","to","make","a","looping","GIF",".","Parameters","--","--","--","--","--","clip",":","moviepy.video.VideoClip.VideoClip","A","MoviePy","video","clip",".","distance_threshold",":","float","Distance","above","which","a","match","is","rejected",".","max_duration",":","float","Maximal","duration","(","in","seconds",")","between","two","matching","frames",".","fps",":","int",",","optional","Frames","per","second","(","default","will","be","``","clip.fps","``",")",".","logger",":","str",",","optional","Either","``","``","bar","''","``","for","progress","bar","or","``","None","``","or","any","Proglog","logger",".","Returns","--","--","--","-","FramesMatches","All","pairs","of","frames","with","``","end_time","-","start_time","<","max_duration","``","and","whose","distance","is","under","``","distance_threshold","``",".","Examples","--","--","--","--","We","find","all","matching","frames","in","a","given","video","and","turn","the","best","match","with","a","duration","of","1.5","seconds","or","more","into","a","GIF",":",">",">",">","from","moviepy","import","VideoFileClip",">",">",">","from","moviepy.video.tools.cuts","import","FramesMatches",">",">",">",">",">",">","clip","=","VideoFileClip","(","``","foo.mp4","''",")",".resize","(","width=200",")",">",">",">","matches","=","FramesMatches.from_clip","(","...","clip",",","distance_threshold=10",",","max_duration=3",",","#","will","take","time","...",")",">",">",">","best","=","matches.filter","(","lambda","m",":","m.time_span",">","1.5",")",".best","(",")",">",">",">","clip.subclip","(","best.start_time",",","best.end_time",")",".write_gif","(","``","foo.gif","''",")"]
code: def from_clip(
      clip, distance_threshold, max_duration, fps=None, logger="bar"
  ):
      """Finds all the frames that look alike in a clip, for instance to make
      a looping GIF.
  
      Parameters
      ----------
  
      clip : moviepy.video.VideoClip.VideoClip
        A MoviePy video clip.
  
      distance_threshold : float
        Distance above which a match is rejected.
  
      max_duration : float
        Maximal duration (in seconds) between two matching frames.
  
      fps : int, optional
        Frames per second (default will be ``clip.fps``).
  
      logger : str, optional
        Either ``"bar"`` for progress bar or ``None`` or any Proglog logger.
  
      Returns
      -------
  
      FramesMatches
          All pairs of frames with ``end_time - start_time < max_duration``
          and whose distance is under ``distance_threshold``.
  
      Examples
      --------
  
      We find all matching frames in a given video and turn the best match
      with a duration of 1.5 seconds or more into a GIF:
  
      >>> from moviepy import VideoFileClip
      >>> from moviepy.video.tools.cuts import FramesMatches
      >>>
      >>> clip = VideoFileClip("foo.mp4").resize(width=200)
      >>> matches = FramesMatches.from_clip(
      ...     clip, distance_threshold=10, max_duration=3,  # will take time
      ... )
      >>> best = matches.filter(lambda m: m.time_span > 1.5).best()
      >>> clip.subclip(best.start_time, best.end_time).write_gif("foo.gif")
      """
      N_pixels = clip.w * clip.h * 3
  
      def dot_product(F1, F2):
          return (F1 * F2).sum() / N_pixels
  
      frame_dict = (
          {}
      )  # will store the frames and their mutual distances
  
      def distance(t1, t2):
          uv = dot_product(
              frame_dict[t1]["frame"], frame_dict[t2]["frame"]
          )
          u, v = frame_dict[t1]["|F|sq"], frame_dict[t2]["|F|sq"]
          return np.sqrt(u + v - 2 * uv)
  
      matching_frames = []  # the final result.
  
      for t, frame in clip.iter_frames(with_times=True, logger=logger):
          flat_frame = 1.0 * frame.flatten()
          F_norm_sq = dot_product(flat_frame, flat_frame)
          F_norm = np.sqrt(F_norm_sq)
  
          for t2 in list(frame_dict.keys()):
              # forget old frames, add 't' to the others frames
              # check for early rejections based on differing norms
              if (t - t2) > max_duration:
                  frame_dict.pop(t2)
              else:
                  frame_dict[t2][t] = {
                      "min": abs(frame_dict[t2]["|F|"] - F_norm),
                      "max": frame_dict[t2]["|F|"] + F_norm,
                  }
                  frame_dict[t2][t]["rejected"] = (
                      frame_dict[t2][t]["min"] > distance_threshold
                  )
  
          t_F = sorted(frame_dict.keys())
  
          frame_dict[t] = {
              "frame": flat_frame,
              "|F|sq": F_norm_sq,
              "|F|": F_norm,
          }
  
          for i, t2 in enumerate(t_F):
              # Compare F(t) to all the previous frames
  
              if frame_dict[t2][t]["rejected"]:
                  continue
  
              dist = distance(t, t2)
              frame_dict[t2][t]["min"] = frame_dict[t2][t]["max"] = dist
              frame_dict[t2][t]["rejected"] = dist >= distance_threshold
  
              for t3 in t_F[i + 1 :]:
                  # For all the next times t3, use d(F(t), F(end_time)) to
                  # update the bounds on d(F(t), F(t3)). See if you can
                  # conclude on whether F(t) and F(t3) match.
                  t3t, t2t3 = frame_dict[t3][t], frame_dict[t2][t3]
                  t3t["max"] = min(t3t["max"], dist + t2t3["max"])
                  t3t["min"] = max(
                      t3t["min"], dist - t2t3["max"], t2t3["min"] - dist
                  )
  
                  if t3t["min"] > distance_threshold:
                      t3t["rejected"] = True
  
          # Store all the good matches (end_time,t)
          matching_frames += [
              (
                  t1,
                  t,
                  frame_dict[t1][t]["min"],
                  frame_dict[t1][t]["max"],
              )
              for t1 in frame_dict
              if (t1 != t) and not frame_dict[t1][t]["rejected"]
          ]
  
      return FramesMatches([FramesMatch(*e) for e in matching_frames])
  
imports: from collections import defaultdict
  import numpy
  from moviepy.decorators import convert_parameter_to_seconds, use_clip_fps_by_default
label_desc: Use image node_id 6 for calling the FramesMatches obj's underlying member method code with example usage: obj.from_clip(clip, distance_threshold, max_duration, fps, logger) and returns: FramesMatches, unknown, np