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
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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)
            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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
@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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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)
        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
69
70
71
72
def setFilter(self, filter_idx: int):
    """Set filter (by number) for which files in directory to show."""
    self.filter_idx = filter_idx
    self.poll()