          retval = MultiThread(getattr(self, "_{}".format(self._task)), *io_args, thread_count=1)
          logger.trace(retval)
          return retval
  
      # LOADING #
      def _load(self, *args):
          """ The load thread.
  
          Loads from a folder of images or from a video and puts to a queue
  
          Parameters
 
</s> remove         io_args = (self._queue) if io_args is None else (self._queue, *io_args)
        retval = MultiThread(getattr(self, "_{}".format(self._task)), *io_args, thread_count=1)
        logger.trace(retval)
        return retval
 </s> add         if self._is_video:
            self._count = int(count_frames(self.location, fast=fast_count))
            self._file_list = [self._dummy_video_framename(i + 1) for i in range(self.count)]
        else:
            if isinstance(self.location, (list, tuple)):
                self._file_list = self.location
            else:
                self._file_list = get_image_paths(self.location)
            self._count = len(self.file_list) </s> remove         io_args: tuple, optional
            The arguments to be passed to the load or save thread. Default: `None`.

        Returns
        -------
        :class:`lib.multithreading.MultiThread`: Thread containing the load/save function.
 </s> add         fast_count: bool
            When loading from video, the video needs to be parsed frame by frame to get an accurate
            count. This can be done quite quickly without guaranteed accuracy, or slower with
            guaranteed accuracy. Set to ``True`` to count quickly, or ``False`` to count slower
            but accurately. </s> remove         args: tuple
            The arguments to be passed to the load iterator
 </s> add         queue: queue.Queue()
            The ImageIO Queue </s> remove     Loads images or videos from a given location in a background thread.
    Saves images to the given location in a background thread.
    Images/Videos will be loaded or saved in deterministic order.
 </s> add     This is the parent thread for :class:`ImagesLoader` and :class:`ImagesSaver` and should not
    be called directly. </s> remove         images or a video file. For saving this must be an existing folder.
    task: {'load', 'save'}
        The task to be performed. ``'load'`` to load images/video frames, ``'save'`` to save
        images.
    load_with_hash: bool, optional
        When loading images, set to ``True`` to return the sha1 hash of the image along with the
        image. Default: ``False``.
 </s> add         images, video file or a list of image files. For saving this must be an existing folder.
    queue_size: int
        The amount of images to hold in the internal buffer.
    args: tuple, optional
        The arguments to be passed to the loader or saver thread. Default: ``None``

    See Also
    --------
    lib.image.ImagesLoader : Background Image Loader inheriting from this class.
    lib.image.ImagesSaver : Background Image Saver inheriting from this class.
    """

    def __init__(self, path, queue_size, args=None):
        logger.debug("Initializing %s: (path: %s, queue_size: %s, args: %s)",
                     self.__class__.__name__, path, queue_size, args)

        self._args = tuple() if args is None else args

        self._location = path
        self._check_location_exists()

        self._queue = queue_manager.get_queue(name=self.__class__.__name__, maxsize=queue_size)
        self._thread = None

    @property
    def location(self):
        """ str: The folder or video that was passed in as the :attr:`path` parameter. """
        return self._location

    def _check_location_exists(self):
        """ Check whether the input location exists.

        Raises
        ------
        FaceswapError
            If the given location does not exist
        """
        if isinstance(self.location, str) and not os.path.exists(self.location):
            raise FaceswapError("The location '{}' does not exist".format(self.location))
        if isinstance(self.location, (list, tuple)) and not all(os.path.exists(location)
                                                                for location in self.location):
            raise FaceswapError("Not all locations in the input list exist")

    def _set_thread(self):
        """ Set the load/save thread """
        if self._thread is not None:
            return
        self._thread = MultiThread(self._process,
                                   self._queue,
                                   name=self.__class__.__name__,
                                   thread_count=1)
        logger.trace(self._thread)
        self._thread.start()

    def _process(self, queue):
        """ Image IO process to be run in a thread. Override for loader/saver process.

        Parameters
        ----------
        queue: queue.Queue()
            The ImageIO Queue
        """
        raise NotImplementedError

    def close(self):
        """ Closes down and joins the internal threads """
        logger.debug("Received Close")
        self._thread.join()
        logger.debug("Closed")


class ImagesLoader(ImageIO):
    """ Perform image loading from a folder of images or a video.

    Images will be loaded and returned in the order that they appear in the folder, or in the video
    to ensure deterministic ordering. Loading occurs in a background thread, caching 8 images at a
    time so that other processes do not need to wait on disk reads.

    See also :class:`ImageIO` for additional attributes.

    Parameters
    ----------
    path: str or list
        The path to load images from. This can be a folder which contains images a video file or a
        list of image files.
        logger.debug("count: %s", self.count)
        logger.trace("filelist: %s", self.file_list)

    def _process(self, queue):
          retval = MultiThread(getattr(self, "_{}".format(self._task)), *io_args, thread_count=1)
          logger.trace(retval)
          return retval
  
        logger.debug("count: %s", self.count)
        logger.trace("filelist: %s", self.file_list)

    def _process(self, queue):
        logger.debug("count: %s", self.count)
        logger.trace("filelist: %s", self.file_list)

    def _process(self, queue):
          """ The load thread.
  
          Loads from a folder of images or from a video and puts to a queue
  
          Parameters
keep keep keep keep replace replace keep keep keep keep keep
 scripts.extract - code optimizations

Limit queue sizes to reduce RAM usage
Rename lib.image.BackgroundIO to ImageIO
Create separate ImagesLoader and ImagesSaver classes
Load/Save images from centralized lib.image.ImageIO
scripts.extract documentation 
lib/image.py