      def extract_one_face(self, alignment, image):
          """ Extract one face from image """
          face = DetectedFace()
          face.from_alignment(alignment, image=image)
          return self.extractor.extract(image, face, self.size, self.align_eyes)
  
      def original_roi(self, matrix):
          """ Return the original ROI of an extracted face """
          points = np.array([[0, 0], [0, self.size - 1],
                             [self.size - 1, self.size - 1],
                             [self.size - 1, 0]], np.int32)
          points = points.reshape((-1, 1, 2))
  
          mat = matrix * (self.size - 2 * self.padding)
          mat[:, 2] += self.padding
          mat = cv2.invertAffineTransform(mat)
          return [cv2.transform(points, mat)]
 
</s> remove         mat = matrix * (self.size - 2 * self.padding)
        mat[:, 2] += self.padding
        mat = cv2.invertAffineTransform(mat)
        return [cv2.transform(points, mat)]

    def get_faces_for_frame(self, frame, update=False):
 </s> add     def get_faces_in_frame(self, frame, update=False): </s> remove 

class Extract():
    """ Based on the original https://www.reddit.com/r/deepfakes/
        code sample + contribs """

    def extract(self, image, face, size, align_eyes):
        """ Extract a face from an image """
        alignment = get_align_mat(face, size, align_eyes)
        extracted = self.transform(image, alignment, size, 48)
        return extracted, alignment

    @staticmethod
    def transform(image, mat, size, padding=0):
        """ Transform Image """
        matrix = mat * (size - 2 * padding)
        matrix[:, 2] += padding
        return cv2.warpAffine(image, matrix, (size, size))

    @staticmethod
    def transform_points(points, mat, size, padding=0):
        """ Transform points along matrix """
        matrix = mat * (size - 2 * padding)
        matrix[:, 2] += padding
        points = np.expand_dims(points, axis=1)
        points = cv2.transform(points, matrix, points.shape)
        points = np.squeeze(points)
        return points

    @staticmethod
    def get_feature_mask(aligned_landmarks_68, size,
                         padding=0, dilation=30):
        """ Return the face feature mask """
        scale = size - 2*padding
        translation = padding
        pad_mat = np.matrix([[scale, 0.0, translation],
                             [0.0, scale, translation]])
        aligned_landmarks_68 = np.expand_dims(aligned_landmarks_68, axis=1)
        aligned_landmarks_68 = cv2.transform(aligned_landmarks_68,
                                             pad_mat,
                                             aligned_landmarks_68.shape)
        aligned_landmarks_68 = np.squeeze(aligned_landmarks_68)

        (l_start, l_end) = FACIAL_LANDMARKS_IDXS["left_eye"]
        (r_start, r_end) = FACIAL_LANDMARKS_IDXS["right_eye"]
        (m_start, m_end) = FACIAL_LANDMARKS_IDXS["mouth"]
        (n_start, n_end) = FACIAL_LANDMARKS_IDXS["nose"]
        (lb_start, lb_end) = FACIAL_LANDMARKS_IDXS["left_eyebrow"]
        (rb_start, rb_end) = FACIAL_LANDMARKS_IDXS["right_eyebrow"]
        (c_start, c_end) = FACIAL_LANDMARKS_IDXS["chin"]

        l_eye_points = aligned_landmarks_68[l_start:l_end].tolist()
        l_brow_points = aligned_landmarks_68[lb_start:lb_end].tolist()
        r_eye_points = aligned_landmarks_68[r_start:r_end].tolist()
        r_brow_points = aligned_landmarks_68[rb_start:rb_end].tolist()
        nose_points = aligned_landmarks_68[n_start:n_end].tolist()
        chin_points = aligned_landmarks_68[c_start:c_end].tolist()
        mouth_points = aligned_landmarks_68[m_start:m_end].tolist()
        l_eye_points = l_eye_points + l_brow_points
        r_eye_points = r_eye_points + r_brow_points
        mouth_points = mouth_points + nose_points + chin_points

        l_eye_hull = cv2.convexHull(np.array(l_eye_points).reshape(
            (-1, 2)).astype(int)).flatten().reshape((-1, 2))
        r_eye_hull = cv2.convexHull(np.array(r_eye_points).reshape(
            (-1, 2)).astype(int)).flatten().reshape((-1, 2))
        mouth_hull = cv2.convexHull(np.array(mouth_points).reshape(
            (-1, 2)).astype(int)).flatten().reshape((-1, 2))

        mask = np.zeros((size, size, 3), dtype=float)
        cv2.fillConvexPoly(mask, l_eye_hull, (1, 1, 1))
        cv2.fillConvexPoly(mask, r_eye_hull, (1, 1, 1))
        cv2.fillConvexPoly(mask, mouth_hull, (1, 1, 1))

        if dilation > 0:
            kernel = np.ones((dilation, dilation), np.uint8)
            mask = cv2.dilate(mask, kernel, iterations=1)

        return mask
 </s> add  </s> remove         for alignment in alignments:
            face, matrix = self.extract_one_face(alignment, image.copy())
            self.faces.append(face)
            self.matrices.append(matrix)
 </s> add         self.faces = [self.extract_one_face(alignment, image.copy())
                      for alignment in alignments] </s> remove         """ Crop an image around bounding box to the face """
 </s> add         """ Crop an image around bounding box to the face
            and capture it's dimensions """ </s> remove         dst = os.path.splitext(self.file)[0]
        dst += ".{}".format(self.serializer.ext)
        self.backup_alignments()

        print("Saving alignments to {}".format(dst))
        with open(dst, self.serializer.woptions) as align:
            align.write(self.serializer.marshal(self.alignments))

    def backup_alignments(self):
        """ Backup copy of old alignments """
        if not os.path.isfile(self.file):
            return
        now = datetime.now().strftime("%Y%m%d_%H%M%S")
        src = self.file
        dst = src.split(".")
        dst[0] += "_" + now + "."
        dst = dst[0] + dst[1]
        print("Backing up original alignments to {}".format(dst))
        os.rename(src, dst)

    def get_alignments_one_image(self):
        """ Return the face alignments for one image """
        for frame_fullname, alignments in self.alignments.items():
            frame_name = frame_fullname[:frame_fullname.rindex(".")]
            number_alignments = len(alignments)
            yield frame_name, alignments, number_alignments, frame_fullname

    @staticmethod
    def get_one_alignment_index_reverse(image_alignments, number_alignments):
        """ Return the correct original index for
            alignment in reverse order """
        for idx, _ in enumerate(reversed(image_alignments)):
            original_idx = number_alignments - 1 - idx
            yield original_idx

    def get_alignments_for_frame(self, frame):
        """ Return the alignments for the selected frame """
        return self.alignments.get(frame, list())

    def frame_in_alignments(self, frame):
        """ Return true if frame exists in alignments file """
        return bool(self.alignments.get(frame, -1) != -1)

    def frame_has_faces(self, frame):
        """ Return true if frame exists and has faces """
        return bool(self.alignments.get(frame, list()))

    def frame_has_multiple_faces(self, frame):
        """ Return true if frame exists and has faces """
        if not frame:
            return False
        return bool(len(self.alignments.get(frame, list())) > 1)

    def get_full_frame_name(self, frame):
        """ Return a frame with extension for when the extension is
            not known """
        return next(key for key in self.alignments.keys()
                    if key.startswith(frame))

    def count_alignments_in_frame(self, frame):
        """ Return number of alignments within frame """
        return len(self.alignments.get(frame, list()))

    def delete_alignment_at_index(self, frame, idx):
        """ Delete the face alignment for given frame at given index """
        idx = int(idx)
        if idx + 1 > self.count_alignments_in_frame(frame):
            return False
        del self.alignments[frame][idx]
        return True

    def add_alignment(self, frame, alignment):
        """ Add a new alignment for a frame and return it's index """
        self.alignments[frame].append(alignment)
        return self.count_alignments_in_frame(frame) - 1

    def update_alignment(self, frame, idx, alignment):
        """ Replace an alignment for given frame and index """
        self.alignments[frame][idx] = alignment

    def get_rotated(self):
        """ Return list of keys for alignments containing
            rotated frames """
        keys = list()
        for key, val in self.alignments.items():
            if any(alignment.get("r", None) for alignment in val):
                keys.append(key)
        return keys

    def rotate_existing_landmarks(self, frame, dimensions):
        """ Backwards compatability fix. Rotates the landmarks to
            their correct position and sets r to 0 """
        for alignment in self.alignments.get(frame, list()):
            angle = alignment.get("r", 0)
            if not angle:
                return
            rotation_matrix = self.get_original_rotation_matrix(dimensions,
                                                                angle)
            rotate_landmarks(alignment, rotation_matrix)
            del alignment["r"]

    @staticmethod
    def get_original_rotation_matrix(dimensions, angle):
        """ Calculate original rotation matrix and invert """
        height, width = dimensions
        center = (width/2, height/2)
        rotation_matrix = cv2.getRotationMatrix2D(center, -1.0*angle, 1.)

        abs_cos = abs(rotation_matrix[0, 0])
        abs_sin = abs(rotation_matrix[0, 1])
        rotated_width = int(height*abs_sin + width*abs_cos)
        rotated_height = int(height*abs_cos + width*abs_sin)
        rotation_matrix[0, 2] += rotated_width/2 - center[0]
        rotation_matrix[1, 2] += rotated_height/2 - center[1]

        return rotation_matrix
 </s> add         self.backup()
        super().save()
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
      def extract_one_face(self, alignment, image):
          """ Extract one face from image """
          face = DetectedFace()
          face.from_alignment(alignment, image=image)
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
        face.load_aligned(image,
                          size=self.size,
                          padding=self.padding,
                          align_eyes=self.align_eyes)
        return face
  
          mat = matrix * (self.size - 2 * self.padding)
          mat[:, 2] += self.padding
          mat = cv2.invertAffineTransform(mat)
          return [cv2.transform(points, mat)]
keep keep keep keep replace replace replace replace replace replace replace replace keep keep keep keep keep
 Fix convert-adjust (#531)

* Add dimensions to alignments + refactor

* Add frame_dims + funcs to DetectFaces. Add alignments lib

* Convert Adjust working

* Refactor and tidy up 
tools/lib_alignments/media.py