                                      source_is_video=self._images.is_video,
                                      source_frame_dims=extract_media.image_size))
              image = encode_image(face.aligned.face, extension, metadata=meta)
  
              if not self._args.skip_saving_faces:
                  saver.save(output_filename, image)
              final_faces.append(face.to_alignment())
          self._alignments.data[os.path.basename(extract_media.filename)] = dict(faces=final_faces)
          del extract_media
 
</s> remove                 self._threaded_redirector("reload", detected_faces)
        if not self._args.skip_saving_faces:
 </s> add                 self._threaded_redirector("reload", (detected_faces, ))
        if saver is not None: </s> remove             logger.trace("Reloading image: '%s'", filename)
 </s> add             logger.trace("Reloading image: '%s'", filename)  # type: ignore </s> remove     def _process_full(self, side, images, prediction_size, color):
 </s> add     def _process_full(self,
                      side: Literal["a", "b"],
                      images: np.ndarray,
                      prediction_size: int,
                      color: Tuple[int, int, int]) -> np.ndarray: </s> remove         self._samples.images = self._feeder.compile_timelapse_sample()
 </s> add         self._samples.images = self._feeder.generate_preview(is_timelapse=True) </s> remove         logger.trace("size: %s, area: %s, aligned: %s, dilation: %s, blur_kernel: %s, as_zip: %s",
                     size, area, aligned, dilation, blur_kernel, as_zip)
        areas = dict(mouth=[slice(48, 60)], eyes=[slice(36, 42), slice(42, 48)])
        if aligned:
            face = AlignedFace(self.landmarks_xy, centering=centering, size=size)
            landmarks = face.landmarks
            size = (size, size)
        else:
            landmarks = self.landmarks_xy
        points = [landmarks[zone] for zone in areas[area]]  # pylint:disable=unsubscriptable-object
        mask = _LandmarksMask(size, points, dilation=dilation, blur_kernel=blur_kernel)
        retval = mask.get(as_zip=as_zip)
        return retval
 </s> add         logger.trace("area: %s, dilation: %s", area, dilation)  # type: ignore
        areas = dict(mouth=[slice(48, 60)], eye=[slice(36, 42), slice(42, 48)])
        points = [self.aligned.landmarks[zone]
                  for zone in areas[area]]

        lmmask = LandmarksMask(points,
                               storage_size=self.aligned.size,
                               storage_centering=self.aligned.centering,
                               dilation=dilation)
        lmmask.set_blur_and_threshold(blur_kernel=blur_kernel)
        lmmask.generate_mask(
            self.aligned.adjusted_matrix,
            self.aligned.interpolators[1])
        return lmmask.mask

    def store_training_masks(self,
                             masks: List[Optional[np.ndarray]],
                             delete_masks: bool = False) -> None:
        """ Concatenate and compress the given training masks and store for retrieval.

        Parameters
        ----------
        masks: list
            A list of training mask. Must be all be uint-8 3D arrays of the same size in
            0-255 range
        delete_masks: bool, optional
            ``True`` to delete any of the :class:`Mask` objects owned by this detected face. Use to
            free up unrequired memory usage. Default: ``False``
        """
        if delete_masks:
            del self.mask
            self.mask = {}

        valid = [msk for msk in masks if msk is not None]
        if not valid:
            return
        combined = np.concatenate(valid, axis=-1)
        self._training_masks = (compress(combined), combined.shape)

    def get_training_masks(self) -> Optional[np.ndarray]:
        """ Obtain the decompressed combined training masks.

        Returns
        -------
        :class:`numpy.ndarray`
            A 3D array containing the decompressed training masks as uint8 in 0-255 range if
            training masks are present otherwise ``None``
        """
        if not self._training_masks:
            return None
        return np.frombuffer(decompress(self._training_masks[0]),
                             dtype="uint8").reshape(self._training_masks[1])
            if saver is not None:
                                      source_is_video=self._images.is_video,
                                      source_frame_dims=extract_media.image_size))
              image = encode_image(face.aligned.face, extension, metadata=meta)
  
            if saver is not None:
                  saver.save(output_filename, image)
              final_faces.append(face.to_alignment())
          self._alignments.data[os.path.basename(extract_media.filename)] = dict(faces=final_faces)
          del extract_media
keep keep keep keep replace 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 
scripts/extract.py