Ejemplo n.º 1
0
    def _annotate_image(self, frame_name):
        """ Annotate the frame with each face that appears in the alignments file.

        Parameters
        ----------
        frame_name: str
            The full path to the original frame
        """
        logger.trace("Annotating frame: '%s'", frame_name)
        image = self._frames.load_image(frame_name)

        for idx, alignment in enumerate(
                self._alignments.get_faces_in_frame(frame_name)):
            face = DetectedFace()
            face.from_alignment(alignment, image=image)
            # Bounding Box
            cv2.rectangle(image, (face.left, face.top),
                          (face.right, face.bottom), (255, 0, 0), 1)
            self._annotate_landmarks(
                image,
                np.rint(face.landmarks_xy).astype("int32"))
            self._annotate_extract_boxes(image, face, idx)
            self._annotate_pose(image, face)  # Pose (head is still loaded)

        self._frames.save_image(self._output_folder, frame_name, image)
Ejemplo n.º 2
0
    def _alignments_faces(self, frame_name, image):
        """ Return detected faces from an alignments file.

        Parameters
        ----------
        frame_name: str
            The name of the frame to return the detected faces for
        image: :class:`numpy.ndarray`
            The frame that the detected faces exist in

        Returns
        -------
        list
            List of :class:`lib.align.DetectedFace` objects
        """
        if not self._check_alignments(frame_name):
            return list()

        faces = self._alignments.get_faces_in_frame(frame_name)
        detected_faces = list()

        for rawface in faces:
            face = DetectedFace()
            face.from_alignment(rawface, image=image)
            detected_faces.append(face)
        return detected_faces
Ejemplo n.º 3
0
 def extract_one_face(self, alignment, image):
     """ Extract one face from image """
     logger.trace("Extracting one face: (frame: '%s', alignment: %s)",
                  self.current_frame, alignment)
     face = DetectedFace()
     face.from_alignment(alignment, image=image)
     face.load_aligned(image, size=self.size, centering="head")
     face.thumbnail = generate_thumbnail(face.aligned.face, size=80, quality=60)
     return face
Ejemplo n.º 4
0
 def load(self):
     """ Load the faces from the alignments file, convert to
     :class:`~lib.align.DetectedFace`. objects and add to :attr:`_frame_faces`. """
     for key in sorted(self._alignments.data):
         this_frame_faces = []
         for item in self._alignments.data[key]["faces"]:
             face = DetectedFace()
             face.from_alignment(item, with_thumb=True)
             this_frame_faces.append(face)
         self._frame_faces.append(this_frame_faces)
Ejemplo n.º 5
0
 def load(self):
     """ Load the faces from the alignments file, convert to
     :class:`~lib.align.DetectedFace`. objects and add to :attr:`_frame_faces`. """
     for key in sorted(self._alignments.data):
         this_frame_faces = []
         for item in self._alignments.data[key]["faces"]:
             face = DetectedFace()
             face.from_alignment(item, with_thumb=True)
             face.load_aligned(None)
             _ = face.aligned.average_distance  # cache the distances
             this_frame_faces.append(face)
         self._frame_faces.append(this_frame_faces)
     self._sorted_frame_names = sorted(self._alignments.data)
Ejemplo n.º 6
0
    def _update_png_headers(self):
        """ Update the EXIF iTXt field of any face PNGs that have had their face index changed.

        Notes
        -----
        This could be quicker if parellizing in threads, however, Windows (at least) does not seem
        to like this and has a tendency to throw permission errors, so this remains single threaded
        for now.
        """
        to_update = [  # Items whose face index has changed
            x for x in self._items.file_list_sorted if x["face_index"] !=
            self._items.items[x["source_filename"]].index(x["face_index"])
        ]

        for file_info in tqdm(to_update,
                              desc="Updating PNG Headers",
                              leave=False):
            frame = file_info["source_filename"]
            face_index = file_info["face_index"]
            new_index = self._items.items[frame].index(face_index)

            fullpath = os.path.join(self._items.folder,
                                    file_info["current_filename"])
            logger.debug(
                "Updating png header for '%s': face index from %s to %s",
                fullpath, face_index, new_index)

            # Update file_list_sorted for rename task
            orig_filename = "{}_{}.png".format(
                os.path.splitext(frame)[0], new_index)
            file_info["face_index"] = new_index
            file_info["original_filename"] = orig_filename

            face = DetectedFace()
            face.from_alignment(
                self._alignments.get_faces_in_frame(frame)[new_index])
            meta = dict(
                alignments=face.to_png_meta(),
                source=dict(
                    alignments_version=file_info["alignments_version"],
                    original_filename=orig_filename,
                    face_index=new_index,
                    source_filename=frame,
                    source_is_video=file_info["source_is_video"],
                    source_frame_dims=file_info.get("source_frame_dims")))
            update_existing_metadata(fullpath, meta)

        logger.info(
            "%s Extracted face(s) had their header information updated",
            len(to_update))
Ejemplo n.º 7
0
    def _get_detected_face(alignment):
        """ Convert an alignment dict item to a detected_face object

        Parameters
        ----------
        alignment: dict
            The alignment dict for a face

        Returns
        -------
        :class:`lib.FacesDetect.detected_face`:
            The corresponding detected_face object for the alignment
        """
        detected_face = DetectedFace()
        detected_face.from_alignment(alignment)
        return detected_face
Ejemplo n.º 8
0
    def process(self):
        """ Run the job to remove faces from an alignments file that do not exist within a faces
        folder. """
        logger.info("[REMOVE FACES FROM ALIGNMENTS]")  # Tidy up cli output

        frame_face_indices = self._items.items

        if not frame_face_indices:
            logger.error(
                "No matching faces found in your faces folder. This would remove all "
                "faces from your alignments file. Process aborted.")
            return

        pre_face_count = self._alignments.faces_count
        self._alignments.filter_faces(frame_face_indices, filter_out=False)
        del_count = pre_face_count - self._alignments.faces_count
        if del_count == 0:
            logger.info("No changes made to alignments file. Exiting")
            return

        logger.info("%s alignment(s) were removed from alignments file",
                    del_count)

        # PNG Header Updates
        updated_headers = 0
        for file_info in tqdm(self._items.file_list_sorted,
                              desc="Updating PNG Headers"):
            frame = file_info["source_filename"]
            face_index = file_info["face_index"]
            new_index = frame_face_indices[frame].index(face_index)

            if new_index == face_index:  # face index has not changed
                continue
            fullpath = os.path.join(self._items.folder,
                                    file_info["current_filename"])
            logger.debug(
                "Updating png header for '%s': face index from %s to %s",
                fullpath, face_index, new_index)

            # Update file_list_sorted for rename task
            orig_filename = "{}_{}.png".format(
                os.path.splitext(frame)[0], new_index)
            file_info["face_index"] = new_index
            file_info["original_filename"] = orig_filename

            face = DetectedFace()
            face.from_alignment(
                self._alignments.get_faces_in_frame(frame)[new_index])
            meta = dict(alignments=face.to_png_meta(),
                        source=dict(
                            alignments_version=file_info["alignments_version"],
                            original_filename=orig_filename,
                            face_index=new_index,
                            source_filename=frame,
                            source_is_video=file_info["source_is_video"]))
            update_existing_metadata(fullpath, meta)
            updated_headers += 1

        logger.info(
            "%s Extracted face(s) had their header information updated",
            updated_headers)

        self._alignments.save()

        rename = Rename(self._alignments, None, self._items)
        rename.process()
Ejemplo n.º 9
0
    def __init__(self, arguments):
        logger.debug("Initializing %s: (args: %s)", self.__class__.__name__, arguments)
        self._args = arguments

        # load faces
        faces_alignments = AlignmentsBase(self._args.faces_align_dir)
        print()
        print(f'Faces alignments: {len(faces_alignments._data.keys())}')
        print(faces_alignments._data.keys())

        self._faces = {}
        faces_loader = ImagesLoader(self._args.faces_dir)
        for filename, image in faces_loader.load():
            face_name = os.path.basename(filename)

            faces = faces_alignments.get_faces_in_frame(face_name)
            detected_faces = list()
            for rawface in faces:
                face = DetectedFace()
                face.from_alignment(rawface, image=image)

                feed_face = AlignedFace(face.landmarks_xy,
                                        image=image,
                                        centering='face',
                                        size=image.shape[0],
                                        coverage_ratio=1.0,
                                        dtype="float32")

                detected_faces.append(feed_face)

            self._faces[face_name] = (filename, image, detected_faces)

        print('Faces:', len(self._faces))
        print(self._faces.keys())
        print()

        self._patch_threads = None
        self._images = ImagesLoader(self._args.input_dir, fast_count=True)
        self._alignments = Alignments(self._args, False, self._images.is_video)

        if self._alignments.version == 1.0:
            logger.error("The alignments file format has been updated since the given alignments "
                         "file was generated. You need to update the file to proceed.")
            logger.error("To do this run the 'Alignments Tool' > 'Extract' Job.")
            sys.exit(1)

        self._opts = OptionalActions(self._args, self._images.file_list, self._alignments)

        self._add_queues()
        self._disk_io = DiskIO(self._alignments, self._images, arguments)
        self._predictor = Predict(self._disk_io.load_queue, self._queue_size, self._faces, arguments)
        self._validate()
        get_folder(self._args.output_dir)

        configfile = self._args.configfile if hasattr(self._args, "configfile") else None
        self._converter = Converter(self._predictor.output_size,
                                    self._predictor.coverage_ratio,
                                    self._predictor.centering,
                                    self._disk_io.draw_transparent,
                                    self._disk_io.pre_encode,
                                    arguments,
                                    configfile=configfile)

        logger.debug("Initialized %s", self.__class__.__name__)