Merge pull request 'changes-wrt-feedback' (#1) from changes-wrt-feedback into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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/<name>/ # 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/<name>/ # 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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
@@ -213,9 +222,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 +252,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)
|
||||
@@ -264,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():
|
||||
@@ -272,19 +284,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
|
||||
@@ -408,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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user