Skip to content

Add bounding box overlay and frame/video export to jabs-viewer - #568

Merged
gbeane merged 3 commits into
mainfrom
feat/viewer-bbox-export
Nov 5, 2026
Merged

gbeane merged 3 commits into
mainfrom
feat/viewer-bbox-export

Conversation

@gbeane

@gbeane gbeane commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds three features to jabs-viewer:

  • View → Overlay Bounding Boxes (B, also on the toolbar): toggles the bounding box overlay. On by default; enabled only for v8+ pose files that contain boxes. Previously the viewer always drew v8 boxes with no way to turn them off.
  • File → Export Frame... (Ctrl+E): like the main GUI, saves the bare frame plus an optional -overlay.png copy drawn with the overlays currently enabled in the View menu. With a pose file open without a video, only the overlaid frame is saved.
  • File → Export Video with Overlays...: reuses the main GUI's options dialog (pose / segmentation / bounding boxes, defaulting to what is shown, unavailable overlays disabled with a reason), then exports in a background thread with a cancelable progress dialog. Also works for a pose file opened without video, drawing over the same blank background at the current frame size.

Changes to shared code

  • New jabs.overlay_drawing.bounding_box (draw_identity_bounding_box, pose_has_bounding_boxes) for native-resolution box + identity tab drawing in exports. The on-screen overlay keeps its own palette-colored, clickable implementation.
  • render_overlay_frame, export_overlay_video, VideoExportThread and PlayerWidget.get_overlay_frame gain a draw_bounding_boxes option, default off, so the main GUI and jabs-cli export-video are unchanged.
  • export_overlay_video / VideoExportThread accept frames: BlankFrameReader to export pose data without a video; the source path (the pose file) is still protected from being overwritten. BlankFrameReader is now a context manager.
  • VideoExportOptionsDialog gains an optional bounding box checkbox (offer_bounding_boxes) and can hide the label/prediction checkboxes (offer_labels). The main GUI does not offer bounding boxes yet.
  • PlayerWidget.overlay_bounding_boxes() toggles the bounding box overlay.
  • Viewer user guide updated (both docs/user-guide/ and in-app copies).

Testing

  • New tests for the bbox drawing, renderer and writer options, blank-frame export, options dialog, viewer window wiring and OverlayExporter.
  • Full root suite: 2177 passed, 7 skipped.
  • Manually smoke-tested offscreen with a real 1080p v8 video: exported frames show boxes and ID tabs aligned with pose and segmentation; pose-only video export writes all frames.

@gbeane gbeane self-assigned this Nov 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical export-thread lifecycle issues can crash or corrupt the application during viewer closure or repeated exports, and the advertised macOS shortcut is not correctly registered.

3 open issues
What changed in this PR

Adds toggleable bounding-box overlays plus frame and video export capabilities to jabs-viewer, including pose-only exports rendered over blank frames. Shared rendering, export, dialog, documentation, and test infrastructure are extended while existing main-GUI and CLI defaults remain unchanged.

Changes:

  • Adds v8 bounding-box visualization with toolbar/menu controls and identity tabs.
  • Adds PNG frame export and configurable background video export.
  • Supports pose-only exports using generated blank frames.
  • Extends shared renderers, video writers, export threads, dialogs, documentation, and tests.

This pull request requires changes.

File Review summary
tests/​video_export/​test_video_writer.py Tests bounding-box option propagation, blank-frame export, and source-overwrite protection.
tests/​video_export/​test_frame_renderer.py Tests optional bounding-box rendering in exported frames.
tests/​ui/​test_viewer_window.py Tests viewer controls, export actions, overlay availability, and pose-only sources.
tests/​ui/​test_viewer_overlay_export.py Tests frame/video export workflows, worker wiring, and cancellation behavior.
tests/​ui/​test_video_export_options_dialog.py Tests bounding-box options and configurable label/prediction controls.
tests/​overlay_drawing/​test_bounding_box.py Tests bounding-box drawing, identity tabs, availability, and scaling.
src/​jabs/​video_reader/​blank_frame_reader.py Makes blank-frame readers usable as context managers.
src/​jabs/​video_export/​video_writer.py Supports optional bounding boxes and blank-frame video sources.
src/​jabs/​video_export/​frame_renderer.py Adds optional bounding-box rendering to exported frames.
src/​jabs/​ui/​viewer/​viewer_window.py Wires viewer actions, overlay state, frame export, video export, and pose-only sources. The documented macOS ⌘E shortcut does not match the literal Ctrl+E binding (moderate, 2 votes).
src/​jabs/​ui/​viewer/​overlay_export.py Implements frame and asynchronous video export. Export shutdown needs close-time cancellation and thread waiting (critical, 1 vote); concurrent exports must be prevented and thread ownership cleared safely (critical, 1 vote). Also improve unavailable-box wording (nit, 1 vote) and preserve worker tracebacks in error logs (nit, 1 vote).
src/​jabs/​ui/​video_export_thread.py Passes bounding-box and blank-frame options to background exports.
src/​jabs/​ui/​player_widget/​player_widget.py Adds configurable overlay rendering and bounding-box toggling.
src/​jabs/​ui/​player_widget/​frame_with_overlays.py Exposes the on-screen bounding-box overlay state.
src/​jabs/​ui/​dialogs/​video_export_options_dialog.py Adds optional bounding-box selection and configurable label visibility.
src/​jabs/​resources/​docs/​user_guide/​viewer.md Updates the packaged viewer guide. Clarify that v8 pose files must also contain generated bounding boxes (nit, 1 vote).
src/​jabs/​overlay_drawing/​bounding_box.py Adds shared native-resolution bounding-box and identity-tab drawing utilities.
src/​jabs/​overlay_drawing/​__init__.py Exports the new bounding-box drawing API.
docs/​user-guide/​viewer.md Updates the source viewer guide. Clarify that v8 pose files must also contain generated bounding boxes (nit, 1 vote).

Review effort: Lite

output_path,
pose_est,
options.draw_segmentation,
parent=self._window,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2c63eff: ViewerWindow.closeEvent now calls OverlayExporter.shutdown(), which requests termination of a running export and waits for the thread before the window is destroyed.

Comment on lines +229 to +230
self._video_export_thread = thread
self._run_video_export(thread, output_path)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2c63eff: export_video refuses to start while an export thread is still alive (it can outlive the progress dialog after Cancel), and release_thread only clears the field if it still holds the thread that finished.

self._exporter = OverlayExporter(self, self._player, self.statusBar().showMessage)

self._export_frame_action = QtGui.QAction("Export &Frame...", self)
self._export_frame_action.setShortcut(QtGui.QKeySequence("Ctrl+E"))

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change needed: Qt maps Ctrl in a QKeySequence to the Command key on macOS (Qt::ControlModifier is Command unless AA_MacDontSwapCtrlAndMeta is set, which this app doesn't). QKeySequence("Ctrl+E") already binds and displays as ⌘E.

@gbeane
gbeane merged commit d76f9e1 into main Nov 5, 2026
5 checks passed
@gbeane
gbeane deleted the feat/viewer-bbox-export branch November 5, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants