  
      >>> loader = ImagesLoader('/path/to/video.mp4')
      >>> for filename, image in loader.load():
      >>>     <do processing>
  
      Loading faces with their sha1 hash:
  
      >>> loader = ImagesLoader('/path/to/faces/folder', load_with_hash=True)
      >>> for filename, image, sha1_hash in loader.load():
      >>>     <do processing>
      """
  
      def __init__(self, path, queue_size=8, load_with_hash=False, fast_count=True, skip_list=None):
          logger.debug("Initializing %s: (path: %s, queue_size: %s, load_with_hash: %s, "
                       "fast_count: %s, skip_list: %s)", self.__class__.__name__, path, queue_size,
 
</s> remove     def __init__(self, path, queue_size=8, load_with_hash=False, fast_count=True, skip_list=None):
        logger.debug("Initializing %s: (path: %s, queue_size: %s, load_with_hash: %s, "
                     "fast_count: %s, skip_list: %s)", self.__class__.__name__, path, queue_size,
                     load_with_hash, fast_count, skip_list)
 </s> add     def __init__(self,
                 path,
                 queue_size=8,
                 fast_count=True,
                 skip_list=None,
                 count=None):
        logger.debug("Initializing %s: (path: %s, queue_size: %s, fast_count: %s, skip_list: %s, "
                     "count: %s)", self.__class__.__name__, path, queue_size, fast_count,
                     skip_list, count) </s> remove         args = (load_with_hash, )
        super().__init__(path, queue_size=queue_size, args=args)
 </s> add         super().__init__(path, queue_size=queue_size) </s> remove         self._thread.join()
 </s> add         self.close()


class FacesLoader(ImagesLoader):
    """ Loads faces from a faces folder along with the face's hash.

    Examples
    --------
    Loading faces with their sha1 hash:

    >>> loader = FacesLoader('/path/to/faces/folder')
    >>> for filename, face, sha1_hash in loader.load():
    >>>     <do processing>
    """
    def __init__(self, path, skip_list=None, count=None):
        logger.debug("Initializing %s: (path: %s, count: %s)", self.__class__.__name__,
                     path, count)
        super().__init__(path, queue_size=8, skip_list=skip_list, count=count)

    def _from_folder(self):
        """ Generator for loading images from a folder
        Faces will only ever be loaded from a folder, so this is the only function requiring
        an override

        Yields
        ------
        filename: str
            The filename of the loaded image.
        image: numpy.ndarray
            The loaded image.
        sha1_hash: str
            The sha1 hash of the loaded image.
        """
        logger.debug("Loading images from folder: '%s'", self.location)
        for idx, filename in enumerate(self.file_list):
            if idx in self._skip_list:
                logger.trace("Skipping face %s due to skip list")
                continue
            image_read = read_image(filename, raise_error=False, with_hash=True)
            retval = filename, *image_read
            if retval[1] is None:
                logger.warning("Face not loaded: '%s'", filename)
                continue
            yield retval


class SingleFrameLoader(ImagesLoader):
    """ Allows direct access to a frame by filename or frame index.

    As we are interested in instant access to frames, there is no requirement to process in a
    background thread, as either way we need to wait for the frame to load.

    Parameters
    ----------
    video_meta_data: dict, optional
        Existing video meta information containing the pts_time and iskey flags for the given
        video. Used in conjunction with single_frame_reader for faster seeks. Providing this means
        that the video does not need to be scanned again. Set to ``None`` if the video is to be
        scanned. Default: ``None``
     """
    def __init__(self, path, video_meta_data=None):
        logger.debug("Initializing %s: (path: %s, video_meta_data: %s)",
                     self.__class__.__name__, path, video_meta_data)
        self._video_meta_data = dict() if video_meta_data is None else video_meta_data
        self._reader = None
        super().__init__(path, queue_size=1, fast_count=False)

    @property
    def video_meta_data(self):
        """ dict: For videos contains the keys `frame_pts` holding a list of time stamps for each
        frame and `keyframes` holding the frame index of each key frame.

        Notes
        -----
        Only populated if the input is a video and single frame reader is being used, otherwise
        returns ``None``.
        """
        return self._video_meta_data

    def _get_count_and_filelist(self, fast_count, count):
        if self._is_video:
            self._reader = imageio.get_reader(self.location, "ffmpeg")
            count, video_meta_data = self._reader.get_frame_info(
                frame_pts=self._video_meta_data.get("pts_time", None),
                keyframes=self._video_meta_data.get("keyframes", None))
            self._video_meta_data = video_meta_data
        super()._get_count_and_filelist(fast_count, count)

    def image_from_index(self, index):
        """ Return a single image from :attr:`file_list` for the given index.

        Parameters
        ----------
        index: int
            The index number (frame number) of the frame to retrieve. NB: The first frame is
            index `0`

        Returns
        -------
        filename: str
            The filename of the returned image
        image: :class:`numpy.ndarray`
            The image for the given index

        Notes
        -----
        Retrieving frames from video files can be slow as the whole video file needs to be
        iterated to retrieve the requested frame. If a frame has already been retrieved, then
        retrieving frames of a higher index will be quicker than retrieving frames of a lower
        index, as iteration needs to start from the beginning again when navigating backwards.

        We do not use a background thread for this task, as it is assumed that requesting an image
        by index will be done when required.
        """
        if self.is_video:
            image = self._reader.get_data(index)[..., ::-1]
            filename = self._dummy_video_framename(index)
        else:
            filename = self.file_list[index]
            image = read_image(filename, raise_error=True)
            filename = os.path.basename(filename)
        logger.trace("index: %s, filename: %s image shape: %s", index, filename, image.shape)
        return filename, image </s> remove                 self._skip_count += 1
 </s> add                 self._counts["skip"] += 1 </s> remove         self._output_opts = dict(blur_kernel=arguments.blur_kernel, threshold=arguments.threshold)
        self._output_type = arguments.output_type
        self._output_full_frame = arguments.full_frame
        self._output_suffix = self._get_output_suffix()

        self._face_count = 0
        self._skip_count = 0
        self._update_count = 0
 </s> add         self._output = dict(opts=dict(blur_kernel=arguments.blur_kernel,
                                      threshold=arguments.threshold),
                            type=arguments.output_type,
                            full_frame=arguments.full_frame,
                            suffix=self._get_output_suffix())
        self._counts = dict(face=0, skip=0, update=0)
  
      >>> loader = ImagesLoader('/path/to/video.mp4')
      >>> for filename, image in loader.load():
      >>>     <do processing>






      """
  
      def __init__(self, path, queue_size=8, load_with_hash=False, fast_count=True, skip_list=None):
          logger.debug("Initializing %s: (path: %s, queue_size: %s, load_with_hash: %s, "
                       "fast_count: %s, skip_list: %s)", self.__class__.__name__, path, queue_size,
keep keep keep keep replace replace replace replace replace replace keep keep keep keep keep
 Core Update (#995)

* lib.alignments - Add Video Meta Data methods

* lib.image - Monkey Path ImageIO for video scanning 
lib/image.py