          """ Only called if the :attr:`_warp_to_landmarks` is ``True``. Gets the closest
          matched 68 point landmarks from the opposite training set. """
          logger.trace("Retrieving closest matched landmarks: (filenames: '%s', src_points: '%s'",
                       filenames, batch_src_points)
          landmarks = self._landmarks["a"] if side == "b" else self._landmarks["b"]
          closest_hashes = [self._nearest_landmarks.get(filename) for filename in filenames]
          if None in closest_hashes:
              closest_hashes = self._cache_closest_hashes(filenames, batch_src_points, landmarks)
  
          batch_dst_points = np.array([landmarks[choice(hsh)] for hsh in closest_hashes])
          logger.trace("Returning: (batch_dst_points: %s)", batch_dst_points.shape)
 
</s> remove     def _get_landmarks(self, filenames, side):
        """ Obtains the 68 Point Landmarks for the images in this batch. This is only called if
        config :attr:`_warp_to_landmarks` is ``True``. If the landmarks for an image cannot be
        found, then an error is raised. """
        logger.trace("Retrieving landmarks: (filenames: %s, side: '%s')", filenames, side)
        src_points = [self._landmarks[side].get(filename, None) for filename in filenames]
        # Raise error on missing alignments
        if not all(isinstance(pts, np.ndarray) for pts in src_points):
            missing = [filenames[idx] for idx, pts in enumerate(src_points) if pts is None]
            msg = ("Files missing alignments for this batch: {}"
                   "\nAt least one of your images does not have a matching entry in your "
                   "alignments file."
                   "\nIf you are using 'warp to landmarks' then every "
                   "face you intend to train on must exist within the alignments file."
                   "\nThe specific files that caused this failure are listed above."
                   "\nMost likely there will be more than just these files missing from the "
                   "alignments file. You can use the Alignments Tool to help identify missing "
                   "alignments".format(missing))
            raise FaceswapError(msg)

        logger.trace("Returning: (src_points: %s)", [str(src) for src in src_points])
        return np.array(src_points)

 </s> add  </s> remove             self._nearest_landmarks[filename] = closest_hashes
 </s> add             self._cache["nearest_landmarks"][filename] = closest_hashes </s> remove         retval = dict()
 </s> add  </s> remove         image = annotate.image
        self.frames.save_image(self.output_folder, frame, image)
 </s> add         self._frames.save_image(self._output_folder, frame_name, image)

    def _annotate_landmarks(self, image, landmarks):
        """ Annotate the extract boxes onto the frame.

        Parameters
        ----------
        image: :class:`numpy.ndarray`
            The frame that extract boxes are to be annotated on to
        landmarks: :class:`numpy.ndarray`
            The 68 point landmarks that are to be annotated onto the frame
        index: int
            The face index for the given face
        """
        # Mesh
        for area, indices in self._mesh_areas.items():
            fill = area in ("right_eye", "left_eye", "mouth")
            cv2.polylines(image, [landmarks[indices[0]:indices[1]]], fill, (255, 255, 0), 1)
        # Landmarks
        for (pos_x, pos_y) in landmarks:
            cv2.circle(image, (pos_x, pos_y), 1, (0, 255, 255), -1)

    @classmethod
    def _annotate_extract_boxes(cls, image, face, index):
        """ Annotate the mesh and landmarks boxes onto the frame.

        Parameters
        ----------
        image: :class:`numpy.ndarray`
            The frame that mesh and landmarks are to be annotated on to
        face: :class:`lib.align.AlignedFace`
            The aligned face
        """
        for area in ("face", "head"):
            face.load_aligned(image, centering=area, force=True)
            color = (0, 255, 0) if area == "face" else (0, 0, 255)
            top_left = face.aligned.original_roi[0]  # pylint:disable=unsubscriptable-object
            top_left = (top_left[0], top_left[1] - 10)
            cv2.putText(image, str(index), top_left, cv2.FONT_HERSHEY_DUPLEX, 1.0, color, 1)
            cv2.polylines(image, [face.aligned.original_roi], True, color, 1)

    @classmethod
    def _annotate_pose(cls, image, face):
        """ Annotate the pose onto the frame.

        Parameters
        ----------
        image: :class:`numpy.ndarray`
            The frame that pose is to be annotated on to
        face: :class:`lib.align.AlignedFace`
            The aligned face loaded for head centering
        """
        center = np.int32((face.aligned.size / 2, face.aligned.size / 2)).reshape(1, 2)
        center = np.rint(face.aligned.transform_points(center, invert=True)).astype("int32")
        points = face.aligned.pose.xyz_2d * face.aligned.size
        points = np.rint(face.aligned.transform_points(points, invert=True)).astype("int32")
        cv2.line(image, tuple(center), tuple(points[1]), (0, 255, 0), 2)
        cv2.line(image, tuple(center), tuple(points[0]), (255, 0, 0), 2)
        cv2.line(image, tuple(center), tuple(points[2]), (0, 0, 255), 2)
        lm_side = "a" if side == "b" else "b"
        landmarks = {key: aligned.landmarks
                     for key, aligned in self._aligned_faces[lm_side].items()}
        closest_hashes = [self._cache["nearest_landmarks"].get(filename) for filename in filenames]
          """ Only called if the :attr:`_warp_to_landmarks` is ``True``. Gets the closest
          matched 68 point landmarks from the opposite training set. """
          logger.trace("Retrieving closest matched landmarks: (filenames: '%s', src_points: '%s'",
                       filenames, batch_src_points)
        lm_side = "a" if side == "b" else "b"
        landmarks = {key: aligned.landmarks
                     for key, aligned in self._aligned_faces[lm_side].items()}
        closest_hashes = [self._cache["nearest_landmarks"].get(filename) for filename in filenames]
        lm_side = "a" if side == "b" else "b"
        landmarks = {key: aligned.landmarks
                     for key, aligned in self._aligned_faces[lm_side].items()}
        closest_hashes = [self._cache["nearest_landmarks"].get(filename) for filename in filenames]
          if None in closest_hashes:
              closest_hashes = self._cache_closest_hashes(filenames, batch_src_points, landmarks)
  
          batch_dst_points = np.array([landmarks[choice(hsh)] for hsh in closest_hashes])
          logger.trace("Returning: (batch_dst_points: %s)", batch_dst_points.shape)
keep keep keep keep replace replace keep keep keep keep keep
 Extract - Increase area and move centering (#1095)

* Extract
  - Implement aligner re-feeding
  - Add extract type to pipeline.ExtractMedia
  - Add pose annotation to debug
* Convert
  - implement centering
  - remove usage of feed and reference face properties
  - Remove distributed option from convert
  - Force update of alignments file on legacy receive
* Train
  - Resize preview image to model output size
  - Force legacy centering if centering does not exist in model's state file
  - Enable training on legacy face sets

* Alignments Tool
  - Update draw to include head/pose
  - Remove DFL drop + linting
  - Remove remove-frames job
  - remove align-eyes option
  - Update legacy masks to new extract type
  - Exit if attempting to merge version 1.0 alignments files with version 2.0 alignments files
  - Re-generate thumbnails on legacy upgrade
* Mask Tool
  - Update for new extract + bugfix full frame
* Manual Tool
  - Update to new extraction method
   - Disable legacy alignments,
   - extract box bugfix
   - extract faces - size to 512 and center on head
* Preview Tool
  - Display based on model centering
* Sort Tool
  - Use alignments for sort by face

* lib.aligner
  - Add Pose Class
  - Add AlignedFace Class
  - center _MEAN_FACE on x
  - Add meta information with versioning to alignments file
  - lib.aligner.get_align_matrix to use landmarks not face
  - Refactor aligned faces in lib.faces_detect
* lib.logger
  - larger file log padding
* lib.config
  - Fix global changeable_items
* lib.face_filter
  - Use new extracted face images
* lib.image
  - bump thumbnail default size to 96px 
lib/training_data.py