From 2820edc871f52c35301fc030fc388d9e2ca8e616 Mon Sep 17 00:00:00 2001 From: asreva Date: Wed, 3 Jun 2026 11:47:45 +0200 Subject: [PATCH 1/5] docs: add river annotation reference link to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ea2cf5..f68d029 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ The `clips_file` (the list of clip filenames to annotate) is always read from th ## Usage +> **River annotation reference:** If you are annotating river footage, consult the [river annotation guide](https://docs.google.com/document/d/1iPN9JxiDtb60kC0yjO8tTM0XEfDTGM5ysw33WY-BEDQ/edit?usp=sharing) for guidance on how to draw masks correctly. + ```sh uv run python -m clip_annotator # or, if you have the venv activated: -- 2.47.3 From 16f891e6ebdad7455d084a916c937a174d831ee4 Mon Sep 17 00:00:00 2001 From: asreva Date: Wed, 3 Jun 2026 11:50:14 +0200 Subject: [PATCH 2/5] fix: corrected paths in config example --- config/config.example.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.example.yaml b/config/config.example.yaml index c197db8..4cfa720 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -1,8 +1,8 @@ storage: local # 'local' or 's3' # Required: set these to your actual paths (local path or bucket/prefix for S3) -data_dir: # e.g. /data/clips or for S3: hydroscan-data/GRAMMONT/clips -out_dir: # e.g. /data/out or for S3: hydroscan-data/annotations// # Put your name here +data_dir: # e.g. data/clips or for S3: hydroscan-data/GRAMMONT/ +out_dir: # e.g. data/out or for S3: hydroscan-data/annotations// # Put your name here # For S3 credentials, copy .env.example to .env and fill in: # S3_ACCESS_KEY, S3_SECRET_ACCESS_KEY, S3_ENDPOINT_URL -- 2.47.3 From 8c793e44884034e4b9dcd9fd30a05e5ac65a54b1 Mon Sep 17 00:00:00 2001 From: asreva Date: Wed, 3 Jun 2026 11:56:10 +0200 Subject: [PATCH 3/5] ui: maximize canvas area and compact side panels --- src/clip_annotator/annotator.py | 17 +++++++++-------- src/clip_annotator/mask_canvas.py | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/clip_annotator/annotator.py b/src/clip_annotator/annotator.py index c6adcee..ac37da5 100644 --- a/src/clip_annotator/annotator.py +++ b/src/clip_annotator/annotator.py @@ -213,9 +213,9 @@ class Annotator(QMainWindow): vert_panel = QHBoxLayout() vert_panel.setContentsMargins(0, 0, 4, 0) for label_text, slider, reset_btn in [ - ("Brightness", self.mc.brightness_slider, self.mc.brightness_reset), - ("Contrast", self.mc.contrast_slider, self.mc.contrast_reset), - ("Gamma", self.mc.gamma_slider, self.mc.gamma_reset), + ("B", self.mc.brightness_slider, self.mc.brightness_reset), + ("C", self.mc.contrast_slider, self.mc.contrast_reset), + ("G", self.mc.gamma_slider, self.mc.gamma_reset), ]: col = QVBoxLayout() lbl = QLabel(label_text) @@ -243,8 +243,9 @@ class Annotator(QMainWindow): right_widget.setLayout(question_panel) main = QHBoxLayout() - main.addWidget(left_widget, 3) - main.addWidget(right_widget, 1) + right_widget.setMaximumWidth(160) + main.addWidget(left_widget, 1) + main.addWidget(right_widget, 0) container = QWidget() container.setLayout(main) @@ -272,19 +273,19 @@ class Annotator(QMainWindow): for key, label, options, default in qs: gvbox.addWidget(QLabel(label)) btn_group = QButtonGroup(self) - row = QHBoxLayout() + col = QVBoxLayout() buttons = [] for opt in options: btn = QRadioButton(opt) btn_group.addButton(btn) - row.addWidget(btn) + col.addWidget(btn) buttons.append(btn) if default == opt: btn.setChecked(True) if default is None and buttons: buttons[-1].setChecked(True) self.q_widgets[key] = (btn_group, buttons, options) - gvbox.addLayout(row) + gvbox.addLayout(col) group.setLayout(gvbox) vbox.addWidget(group) return vbox diff --git a/src/clip_annotator/mask_canvas.py b/src/clip_annotator/mask_canvas.py index c52e167..060f070 100644 --- a/src/clip_annotator/mask_canvas.py +++ b/src/clip_annotator/mask_canvas.py @@ -41,6 +41,7 @@ class MaskCanvas: def _build_figure(self, frames): self.fig = Figure(figsize=(self.dw / 80, self.dh / 80)) + self.fig.subplots_adjust(left=0, right=1, top=0.97, bottom=0) self.canvas = FigureCanvas(self.fig) self.ax = self.fig.add_subplot(111) self.ax.axis("off") -- 2.47.3 From da53d6cd4a101f2eda334d725a2e0bc7d9fef7ea Mon Sep 17 00:00:00 2001 From: asreva Date: Wed, 3 Jun 2026 11:58:48 +0200 Subject: [PATCH 4/5] ui: show clip position counter in window title --- src/clip_annotator/annotator.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/clip_annotator/annotator.py b/src/clip_annotator/annotator.py index ac37da5..91c2bbd 100644 --- a/src/clip_annotator/annotator.py +++ b/src/clip_annotator/annotator.py @@ -148,6 +148,15 @@ class Annotator(QMainWindow): return None return self._json_read(meta_path) + # ── helpers ──────────────────────────────────────────────────── + def _update_window_title(self): + total = len(self.selector.clips) + try: + idx = self.selector.clips.index(self.filename) + 1 + except ValueError: + idx = "?" + self.setWindowTitle(f"Clip Annotator ({idx} / {total})") + # ── UI setup ─────────────────────────────────────────────────── def _init_ui(self): self.mc = MaskCanvas(self.frames, self.dh, self.dw) @@ -265,6 +274,8 @@ class Annotator(QMainWindow): self._set_answers(self._pending_answers) self._pending_answers = None + self._update_window_title() + def _build_question_panel(self) -> QVBoxLayout: vbox = QVBoxLayout() for section, qs in self.cfg.get_questions(): @@ -409,6 +420,7 @@ class Annotator(QMainWindow): self._set_answers(self._pending_answers) self._pending_answers = None self.btn_prev.setEnabled(self.history_pos > 0) + self._update_window_title() def _advance_clip(self): if self.history_pos < len(self.history) - 1: -- 2.47.3 From 281a5e104c2a68af421b164d513ebf2a3a34e285 Mon Sep 17 00:00:00 2001 From: asreva Date: Wed, 3 Jun 2026 12:13:21 +0200 Subject: [PATCH 5/5] config: update annotation questions for flow, lighting, weather and sediments --- config/questions.yaml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/config/questions.yaml b/config/questions.yaml index 4a5740c..5bdfb78 100644 --- a/config/questions.yaml +++ b/config/questions.yaml @@ -1,34 +1,38 @@ - section: River items: - key: flow - label: Flow Regime - options: [Turbulent, Laminar, Uncertain] - default: Laminar + label: Flow + options: ["No", Standard, High, Uncertain] + default: Standard - key: shadows label: Strong Shadows - options: [Yes, No, Uncertain] - default: No + options: ["Yes", "No", Uncertain] + default: "No" + - key: sediments + label: Sediments + options: ["Yes", "No", Uncertain] + default: "No" - key: artifacts label: Artifacts on River - options: [Yes, No, Uncertain] - default: No + options: ["Yes", "No", Uncertain] + default: "No" - section: Scene items: - key: lighting label: Lighting - options: [Day, Night, Uncertain] - default: Day + options: [Bright, Dark, Uncertain] + default: Bright - key: exposure label: Exposure options: [Overexposed, Underexposed, Both, Normal, Uncertain] default: Normal - section: Weather items: - - key: snowing - label: Snowing - options: [Yes, No, Uncertain] - default: No + - key: precipitation + label: Precipitation + options: ["Yes", "No", Uncertain] + default: "No" - key: snow_on_ground label: Snow on Ground - options: [Yes, No, Uncertain] - default: No + options: ["Yes", "No", Uncertain] + default: "No" -- 2.47.3