              return_idx = return_indices[images[future]].pop()
              if with_metadata:
                  batch[return_idx], meta[return_idx] = future.result()
              else:
                  batch[return_idx] = future.result()
  
      batch = np.array(batch)
      retval = (batch, meta) if with_metadata else batch
      logger.trace("Returning images: (filenames: %s, batch shape: %s, with_metadata: %s)",
                   filenames, batch.shape, with_metadata)
 
</s> remove                 batch[return_idx], meta[return_idx] = future.result()
 </s> add                 batch[ret_idx], meta[ret_idx] = future.result() </s> remove             return_idx = return_indices[images[future]].pop()
 </s> add             ret_idx = images[future] </s> remove                                   raise_error=True, with_metadata=with_metadata): filename
                  for filename in filenames}
        batch = [None for _ in range(len(filenames))]
        if with_metadata:
            meta = [None for _ in range(len(filenames))]
        # There is no guarantee that the same filename will not be passed through multiple times
        # (and when shuffle is true this can definitely happen), so we can't just call
        # filenames.index().
        return_indices = {filename: [idx for idx, fname in enumerate(filenames)
                                     if fname == filename]
                          for filename in set(filenames)}
 </s> add                                   raise_error=True, with_metadata=with_metadata): idx
                  for idx, filename in enumerate(filenames)} </s> remove     executor = futures.ThreadPoolExecutor()
    with executor:
 </s> add     batch = [None for _ in range(len(filenames))]
    if with_metadata:
        meta = [None for _ in range(len(filenames))]

    with futures.ThreadPoolExecutor() as executor: </s> remove             processed["feed"] = [self._processing.warp(batch[..., :3],
                                                       self._warp_to_landmarks,
                                                       **warp_kwargs)]
 </s> add             warp_kwargs = {}

        warped = batch[..., :3] if self._no_warp else self._processing.warp(
            batch[..., :3],
            self._warp_to_landmarks,
            **warp_kwargs)

        if self._model_input_size != self._process_size:
            feed = self._to_float32(np.array([cv2.resize(image,
                                                         (self._model_input_size,
                                                          self._model_input_size),
                                                         cv2.INTER_AREA)
                                              for image in warped]))
        else:
            feed = self._to_float32(warped)
                batch[ret_idx] = future.result()
              return_idx = return_indices[images[future]].pop()
              if with_metadata:
                  batch[return_idx], meta[return_idx] = future.result()
              else:
                batch[ret_idx] = future.result()
  
      batch = np.array(batch)
      retval = (batch, meta) if with_metadata else batch
      logger.trace("Returning images: (filenames: %s, batch shape: %s, with_metadata: %s)",
                   filenames, batch.shape, with_metadata)
keep keep keep keep replace keep keep keep keep keep
 Data Augmentation update (#1263)

- lib.detected_face
    - Subclass Masks for Landmark based masks
    - Add training mask propery + methods to DetectedFace
  - lib.training_training
    - subclass TrainingDataGenerator for training and preview data
    - Split cache into own module
    - Reduce thread count to 1 to prevent image corruption + data re-use
    - Process on largest model input/output size rather than stored image size
    - Size and crop masks during caching stage
    - Implement ring buffer for data flow
    - Fix preview reload bug
  - augmentation
    - typing
    - switch color aug order
    - better initialization
    - Fix warp + landmark warp to correctly apply at different image scales
    - Slightly improved warp caching
    - Don't store whether image is_preview. Handle all data as training images implicitly
  - plugins.trainer: Typing and fixes to work with trainingdata refactor 
lib/image.py