  
      Example
      -------
      >>> image_filenames = ["/path/to/image_1.png", "/path/to/image_2.png", "/path/to/image_3.png"]
      >>> images = read_image_batch(image_filenames)
      """
      logger.trace("Requested batch: '%s'", filenames)
      executor = futures.ThreadPoolExecutor()
      with executor:
          images = [executor.submit(read_image, filename, raise_error=True)
 
</s> remove         images = [executor.submit(read_image, filename, raise_error=True)
                  for filename in filenames]
        batch = np.array([future.result() for future in futures.as_completed(images)])
    logger.trace("Returning images: %s", batch.shape)
    return batch
 </s> add         images = {executor.submit(read_image, filename, raise_error=True): filename
                  for filename in filenames}
        batch = []
        filenames = []
        for future in futures.as_completed(images):
            batch.append(future.result())
            filenames.append(images[future])
        batch = np.array(batch)
    logger.trace("Returning images: (filenames: %s, batch shape: %s)", filenames, batch.shape)
    return filenames, batch </s> remove         """ Timelapse samples """
        batch = next(self.timelapse_feed)
 </s> add         """ Compile the sample images for creating a time-lapse frame.

        Returns
        -------
        list
            The list of samples, targets and masks as :class:`numpy.ndarrays` for creating a
            time-lapse frame
        """
        batch = next(self._timelapse_feed) </s> remove     def get_alignments(self):
        """ Obtain the landmarks for each faceset """
        landmarks = dict()
        for side, fullpath in self.paths.items():
 </s> add     # Load alignments
    @staticmethod
    def _get_image_hashes(image_list):
        """ Return the hashes for all images used for training.

        Parameters
        ----------
        image_list: dict
            The file paths for the images to be trained on for each side. The dictionary should
            contain 2 keys ("a" and "b") with the values being a list of full paths corresponding
            to each side.

        Returns
        -------
        dict
            For keys "a" and "b" the values are a ``dict`` containing keys "hashes" and "filenames"
            with their values being a list of hashes and filenames that exist within the training
            data folder
        """
        hashes = {key: dict(hashes=[], filenames=[]) for key in image_list}
        pbar = tqdm(desc="Reading training images",
                    total=sum(len(val) for val in image_list.values()))
        for side, filelist in image_list.items():
            logger.debug("side: %s, file count: %s", side, len(filelist))
            for filename, hsh in read_image_hash_batch(filelist):
                hashes[side]["hashes"].append(hsh)
                hashes[side]["filenames"].append(filename)
                pbar.update(1)
        pbar.close()
        logger.trace(hashes)
        return hashes

    def _load_alignments(self):
        """ Load the alignments and convert to :class:`lib.faces_detect.DetectedFace` objects.

        Returns
        -------
        dict
            For keys "a" and "b" values are a list of :class:`lib.faces_detect.DetectedFace`
            objects.
        """
        logger.debug("Loading alignments")
        retval = dict()
        for side, fullpath in self._training_opts["alignments"].items():
            logger.debug("side: '%s', path: '%s'", side, fullpath) </s> remove             output = str(get_folder(os.path.join(str(self.model.model_dir),
                                                 "{}_timelapse".format(self.model.name))))
        self.output_file = str(output)
        logger.debug("Timelapse output set to '%s'", self.output_file)
 </s> add             output = str(get_folder(os.path.join(str(self._model.model_dir),
                                                 "{}_timelapse".format(self._model.name))))
        self._output_file = str(output)
        logger.debug("Time-lapse output set to '%s'", self._output_file) </s> remove         batch = read_image_batch(filenames)
 </s> add         filenames, batch = read_image_batch(filenames)
        batch = self._apply_mask(filenames, batch, side)
    >>> filenames, images = read_image_batch(image_filenames)
  
      Example
      -------
      >>> image_filenames = ["/path/to/image_1.png", "/path/to/image_2.png", "/path/to/image_3.png"]
    >>> filenames, images = read_image_batch(image_filenames)
      """
      logger.trace("Requested batch: '%s'", filenames)
      executor = futures.ThreadPoolExecutor()
      with executor:
          images = [executor.submit(read_image, filename, raise_error=True)
keep keep keep keep replace keep keep keep keep keep
 Smart Masks - Training Implementation (#914)

* Smart Masks - Training

- Reinstate smart mask training code
- Reinstate mask_type back to model.config
- change 'replicate_input_mask to 'learn_mask'
- Add learn mask option
- Add mask loading from alignments to plugins.train.trainer
- Add mask_blur and mask threshold options
- _base.py - Pass mask options through training_opts dict
- plugins.train.model - check for mask_type not None for learn_mask and penalized_mask_loss
- Limit alignments loading to just those faces that appear in the training folder
- Raise error if not all training images have an alignment, and alignment file is required
- lib.training_data - Mask generation code
- lib.faces_detect - cv2 dimension stripping bugfix
- Remove cv2 linting code

* Update mask helptext in cli.py

* Fix Warp to Landmarks
Remove SHA1 hashing from training data

* Update mask training config

* Capture missing masks at training init

* lib.image.read_image_batch - Return filenames with batch for ordering

* scripts.train - Documentation

* plugins.train.trainer - documentation

* Ensure backward compatibility.
Fix convert for new predicted masks

* Update removed masks to components for legacy models. 
lib/image.py