Esempio n. 1
0
    def _launch_folder(self):
        """ Launch :class:`lib.multithreading.MultiThread` to retrieve faces from a
        folder of images.

        Goes through the file list one at a time, passing each file to a separate background
        thread for some speed up.
        """
        reader = SingleFrameLoader(self._location)
        num_threads = min(reader.count, self._num_threads)
        frame_split = reader.count // self._num_threads
        logger.debug("total images: %s, num_threads: %s, frames_per_thread: %s",
                     reader.count, num_threads, frame_split)
        for idx in range(num_threads):
            is_final = idx == num_threads - 1
            start_idx = idx * frame_split
            end_idx = reader.count if is_final else start_idx + frame_split
            thread = MultiThread(self._load_from_folder, reader, start_idx, end_idx)
            thread.start()
            self._threads.append(thread)
Esempio n. 2
0
 def _load_images(self, frames_location, video_meta_data):
     """ Load the images in a background thread. """
     self._loader = SingleFrameLoader(frames_location,
                                      video_meta_data=video_meta_data)
     self._globals.set_frame_count(self._loader.count)
Esempio n. 3
0
class FrameLoader():
    """ Loads the frames, sets the frame count to :attr:`TkGlobals.frame_count` and handles the
    return of the correct frame for the GUI.

    Parameters
    ----------
    tk_globals: :class:`~tools.manual.manual.TkGlobals`
        The tkinter variables that apply to the whole of the GUI
    frames_location: str
        The path to the input frames
    video_meta_data: dict
        The meta data held within the alignments file, if it exists and the input is a video
    """
    def __init__(self, tk_globals, frames_location, video_meta_data):
        logger.debug(
            "Initializing %s: (tk_globals: %s, frames_location: '%s', "
            "video_meta_data: %s)", self.__class__.__name__, tk_globals,
            frames_location, video_meta_data)
        self._globals = tk_globals
        self._loader = None
        self._current_idx = 0
        self._init_thread = self._background_init_frames(
            frames_location, video_meta_data)
        self._globals.tk_frame_index.trace("w", self._set_frame)
        logger.debug("Initialized %s", self.__class__.__name__)

    @property
    def is_initialized(self):
        """ bool: ``True`` if the Frame Loader has completed initialization otherwise
        ``False``. """
        thread_is_alive = self._init_thread.is_alive()
        if thread_is_alive:
            self._init_thread.check_and_raise_error()
        else:
            self._init_thread.join()
            # Setting the initial frame cannot be done in the thread, so set when queried from main
            self._set_frame(initialize=True)
        return not thread_is_alive

    @property
    def video_meta_data(self):
        """ dict: The pts_time and key frames for the loader. """
        return self._loader.video_meta_data

    def _background_init_frames(self, frames_location, video_meta_data):
        """ Launch the images loader in a background thread so we can run other tasks whilst
        waiting for initialization. """
        thread = MultiThread(self._load_images,
                             frames_location,
                             video_meta_data,
                             thread_count=1,
                             name="{}.init_frames".format(
                                 self.__class__.__name__))
        thread.start()
        return thread

    def _load_images(self, frames_location, video_meta_data):
        """ Load the images in a background thread. """
        self._loader = SingleFrameLoader(frames_location,
                                         video_meta_data=video_meta_data)
        self._globals.set_frame_count(self._loader.count)

    def _set_frame(self, *args, initialize=False):  # pylint:disable=unused-argument
        """ Set the currently loaded frame to :attr:`_current_frame` and trigger a full GUI update.

        If the loader has not been initialized, or the navigation position is the same as the
        current position and the face is not zoomed in, then this returns having done nothing.

        Parameters
        ----------
        args: tuple
            :class:`tkinter.Event` arguments. Required but not used.
        initialize: bool, optional
            ``True`` if initializing for the first frame to be displayed otherwise ``False``.
            Default: ``False``
        """
        position = self._globals.frame_index
        if not initialize and (position == self._current_idx
                               and not self._globals.is_zoomed):
            logger.trace(
                "Update criteria not met. Not updating: (initialize: %s, position: %s, "
                "current_idx: %s, is_zoomed: %s)", initialize, position,
                self._current_idx, self._globals.is_zoomed)
            return
        if position == -1:
            filename = "No Frame"
            frame = np.ones(self._globals.frame_display_dims + (3, ),
                            dtype="uint8")
        else:
            filename, frame = self._loader.image_from_index(position)
        logger.trace("filename: %s, frame: %s, position: %s", filename,
                     frame.shape, position)
        self._globals.set_current_frame(frame, filename)
        self._current_idx = position
        self._globals.tk_update.set(True)
        self._globals.tk_update_active_viewport.set(True)