Skip to content

imagedir

sleap.gui.widgets.imagedir

Qt widget for showing images from a directory.

There's a seekbar to move between images, and an optional drop-down menu to select different filename filters (e.g., "validation.*.png").

The typical use-case is to show predictions for each training epoch on the training/validation images. For this use-case, there's a factory method which creates widgets with relevant filters from a given training run path.

Classes:

Name Description
QtImageDirectoryWidget

Qt widget (window) for showing images from directory with seekbar.

QtImageDirectoryWidget

Bases: QtVideoPlayer

Qt widget (window) for showing images from directory with seekbar.

Call poll() method to check directory for new files.

Parameters:

Name Type Description Default
directory Text

The path for which to search for image files.

required
filters Optional[List[Tuple[Text, Text]]]

Filename filters, given as (display name, filter)-tuples, e.g., ("Validation", "validation.*.png")

None

Methods:

Name Description
make_training_vizualizer

Factory method for only currently use-case of this widget.

poll

Re-scans directory (using current filter) and updates widget.

setFilter

Set filter (by number) for which files in directory to show.

Source code in sleap/gui/widgets/imagedir.py
class QtImageDirectoryWidget(QtVideoPlayer):
    """
    Qt widget (window) for showing images from directory with seekbar.

    Call `poll()` method to check directory for new files.

    Arguments:
        directory: The path for which to search for image files.
        filters: Filename filters, given as (display name, filter)-tuples,
            e.g., ("Validation", "validation.*.png")
    """

    def __init__(
        self, directory: Text, filters: Optional[List[Tuple[Text, Text]]] = None
    ):
        self.directory = directory
        self.filters = filters
        self.files = []

        super(QtImageDirectoryWidget, self).__init__()
        self.seekbar.tick_index_offset = 0  # show frame numbers indexed by 0
        self.changedPlot.connect(
            lambda vp, idx, select_idx: self.setWindowTitle(
                self._get_win_title_for_frame(idx)
            )
        )

        self.resize(360, 400)

        if self.filters:
            self.filter_menu = QtWidgets.QComboBox()
            self.filter_menu.addItems([filter[0] for filter in self.filters])
            self.filter_menu.currentIndexChanged.connect(self.setFilter)
            self.layout.addWidget(self.filter_menu)

            self.setFilter(self.filter_menu.currentIndex())
        else:
            self.poll()

    def _get_win_title_for_frame(self, frame_idx: int) -> Text:
        """Get window title to use based on specified frame."""
        return (
            os.path.basename(self.files[frame_idx])
            if frame_idx < len(self.files)
            else ""
        )

    def setFilter(self, filter_idx: int):
        """Set filter (by number) for which files in directory to show."""
        self.filter_idx = filter_idx
        self.poll()

    @property
    def _current_filter_mask(self) -> Text:
        if not self.filters:
            return "*"
        return self.filters[self.filter_idx][1]

    def poll(self):
        """Re-scans directory (using current filter) and updates widget."""
        path = os.path.join(self.directory, self._current_filter_mask)
        print(f"Polling: {path}")

        files = glob.glob(path)
        files.sort()

        if not files:
            return

        if files != self.files:
            was_on_last_image = False
            if self.video is None:
                was_on_last_image = True
                self.show()
            elif self.state["frame_idx"] == get_last_frame_idx(self.video):
                was_on_last_image = True

            self.files = files
            import sleap_io as sio

            self.video = sio.load_video(files, plugin="imageio")
            self.load_video(video=self.video)

            if was_on_last_image:
                self.state["frame_idx"] = get_last_frame_idx(self.video)
            elif self.state["frame_idx"]:
                # self.state["frame_idx"] = min(
                #     self.state["frame_idx"], self.video.last_frame_idx
                # )
                self.state["frame_idx"] = min(
                    self.state["frame_idx"], get_last_frame_idx(self.video)
                )

    @classmethod
    def make_training_vizualizer(cls, run_path: Text) -> "QtImageDirectoryWidget":
        """
        Factory method for only currently use-case of this widget.

        Args:
            run_path: The run path directory for model, should contain viz
                subdirectory.

        Returns:
            Instance of `QtImageDirectoryWidget` widget.
        """
        dir = os.path.join(run_path, "viz")
        filters = [("Validation", "validation.*.png"), ("Training", "train.*.png")]
        win = QtImageDirectoryWidget(dir, filters=filters)
        return win

make_training_vizualizer(run_path) classmethod

Factory method for only currently use-case of this widget.

Parameters:

Name Type Description Default
run_path Text

The run path directory for model, should contain viz subdirectory.

required

Returns:

Type Description
QtImageDirectoryWidget

Instance of QtImageDirectoryWidget widget.

Source code in sleap/gui/widgets/imagedir.py
@classmethod
def make_training_vizualizer(cls, run_path: Text) -> "QtImageDirectoryWidget":
    """
    Factory method for only currently use-case of this widget.

    Args:
        run_path: The run path directory for model, should contain viz
            subdirectory.

    Returns:
        Instance of `QtImageDirectoryWidget` widget.
    """
    dir = os.path.join(run_path, "viz")
    filters = [("Validation", "validation.*.png"), ("Training", "train.*.png")]
    win = QtImageDirectoryWidget(dir, filters=filters)
    return win

poll()

Re-scans directory (using current filter) and updates widget.

Source code in sleap/gui/widgets/imagedir.py
def poll(self):
    """Re-scans directory (using current filter) and updates widget."""
    path = os.path.join(self.directory, self._current_filter_mask)
    print(f"Polling: {path}")

    files = glob.glob(path)
    files.sort()

    if not files:
        return

    if files != self.files:
        was_on_last_image = False
        if self.video is None:
            was_on_last_image = True
            self.show()
        elif self.state["frame_idx"] == get_last_frame_idx(self.video):
            was_on_last_image = True

        self.files = files
        import sleap_io as sio

        self.video = sio.load_video(files, plugin="imageio")
        self.load_video(video=self.video)

        if was_on_last_image:
            self.state["frame_idx"] = get_last_frame_idx(self.video)
        elif self.state["frame_idx"]:
            # self.state["frame_idx"] = min(
            #     self.state["frame_idx"], self.video.last_frame_idx
            # )
            self.state["frame_idx"] = min(
                self.state["frame_idx"], get_last_frame_idx(self.video)
            )

setFilter(filter_idx)

Set filter (by number) for which files in directory to show.

Source code in sleap/gui/widgets/imagedir.py
def setFilter(self, filter_idx: int):
    """Set filter (by number) for which files in directory to show."""
    self.filter_idx = filter_idx
    self.poll()