Skip to content

feat(utils): add TkImageWindow and switch to opencv-python-headless#2320

Open
Borda wants to merge 41 commits into
developfrom
drop/cv2-gui
Open

feat(utils): add TkImageWindow and switch to opencv-python-headless#2320
Borda wants to merge 41 commits into
developfrom
drop/cv2-gui

Conversation

@Borda

@Borda Borda commented Jun 14, 2026

Copy link
Copy Markdown
Member
  • Add sv.TkImageWindow: tkinter+pillow desktop window replacing cv2.imshow/waitKey/destroyAllWindows under headless OpenCV; supports BGR/grayscale/BGRA frames, key polling, mouse callbacks, context manager
  • Switch pyproject.toml from opencv-python to opencv-python-headless (breaking: cv2.imshow/waitKey/namedWindow no longer provided transitively; restore with pip install opencv-python)
  • Migrate all 17 runnable examples from cv2.imshow/waitKey/destroyAllWindows to sv.TkImageWindow
  • Add docstring with webcam ownership pattern to VideoInfo.from_video_path and get_video_frames_generator
  • Add breaking-change CHANGELOG entry and two FAQ entries covering headless and webcam usage
  • Add 18 tests for TkImageWindow covering show(), wait_key(), close(), context manager, mouse callbacks, _bgr_to_pil

- Add sv.TkImageWindow: tkinter+pillow desktop window replacing cv2.imshow/waitKey/destroyAllWindows under headless OpenCV; supports BGR/grayscale/BGRA frames, key polling, mouse callbacks, context manager
- Switch pyproject.toml from opencv-python to opencv-python-headless (breaking: cv2.imshow/waitKey/namedWindow no longer provided transitively; restore with pip install opencv-python)
- Migrate all 17 runnable examples from cv2.imshow/waitKey/destroyAllWindows to sv.TkImageWindow
- Add docstring with webcam ownership pattern to VideoInfo.from_video_path and get_video_frames_generator
- Add breaking-change CHANGELOG entry and two FAQ entries covering headless and webcam usage
- Add 18 tests for TkImageWindow covering show(), wait_key(), close(), context manager, mouse callbacks, _bgr_to_pil

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 14, 2026 23:42
@Borda Borda requested a review from SkalskiP as a code owner June 14, 2026 23:42
@socket-security

socket-security Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedopencv-python-headless@​4.13.0.929910010010070

View full report

@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.29282% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 87%. Comparing base (9897b07) to head (bff69b4).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop   #2320    +/-   ##
========================================
  Coverage       87%     87%            
========================================
  Files           71      72     +1     
  Lines        10485   10664   +179     
========================================
+ Hits          9098    9254   +156     
- Misses        1387    1410    +23     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

Pull request overview

This PR introduces a tkinter+Pillow-based image display utility (sv.TkImageWindow) so runnable examples (and user code) can display frames without relying on OpenCV HighGUI, and switches the core dependency from opencv-python to opencv-python-headless to avoid pulling GUI libraries transitively.

Changes:

  • Added sv.TkImageWindow (plus _bgr_to_pil) and exported it from the top-level package.
  • Switched pyproject.toml (and lockfile) dependency to opencv-python-headless.
  • Migrated runnable examples away from cv2.imshow/cv2.waitKey to sv.TkImageWindow, added tests, and documented the breaking change in docs.

Reviewed changes

Copilot reviewed 24 out of 25 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
uv.lock Updates locked dependencies reflecting the move to opencv-python-headless.
pyproject.toml Switches runtime dependency from opencv-python to opencv-python-headless.
src/supervision/utils/image_window.py Adds TkImageWindow implementation and BGR/BGRA/grayscale conversion helper.
src/supervision/init.py Exports TkImageWindow at the package top level.
src/supervision/utils/video.py Adds/updates VideoInfo.from_video_path docstring content.
tests/utils/test_image_window.py Adds unit tests for TkImageWindow and _bgr_to_pil.
docs/faq.md Adds FAQ entries covering headless OpenCV GUI removal and webcam guidance.
docs/changelog.md Adds breaking-change entry describing the OpenCV wheel switch and mitigation.
examples/traffic_analysis/ultralytics_example.py Replaces cv2.imshow/waitKey usage with TkImageWindow.
examples/traffic_analysis/inference_example.py Replaces cv2.imshow/waitKey usage with TkImageWindow.
examples/time_in_zone/ultralytics_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI in streaming callback.
examples/time_in_zone/ultralytics_naive_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/time_in_zone/ultralytics_file_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/time_in_zone/scripts/draw_zones.py Migrates interactive zone drawing from OpenCV HighGUI to TkImageWindow mouse+key handling.
examples/time_in_zone/rfdetr_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI in streaming callback.
examples/time_in_zone/rfdetr_naive_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/time_in_zone/rfdetr_file_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/time_in_zone/inference_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI in streaming callback.
examples/time_in_zone/inference_naive_stream_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/time_in_zone/inference_file_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/speed_estimation/yolo_nas_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/speed_estimation/ultralytics_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/speed_estimation/inference_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/count_people_in_zone/ultralytics_example.py Uses TkImageWindow instead of OpenCV HighGUI.
examples/count_people_in_zone/inference_example.py Uses TkImageWindow instead of OpenCV HighGUI.

Comment thread src/supervision/utils/image_window.py
Comment thread src/supervision/utils/image_window.py
Comment thread src/supervision/utils/image_window.py Outdated
Comment thread docs/changelog.md Outdated
Comment thread src/supervision/utils/video.py
Comment thread docs/faq.md Outdated
Borda and others added 15 commits June 15, 2026 02:17
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
…failure

patch("PIL.ImageTk.PhotoImage") resolved via pkgutil.resolve_name on
Python 3.12+, which calls getattr(PIL, "ImageTk") — fails on headless
runners without python3-tk. Replace with patch.dict("sys.modules",
{"PIL.ImageTk": fake_imagetk}) which injects the mock before the
from PIL import ImageTk call inside show(), avoiding the import
entirely.

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
InferencePipeline calls on_prediction() from a worker thread; tkinter
requires all Tk calls from the thread that created Tk() root — macOS
enforces this strictly (crash), Linux is undefined behavior. Revert
inference_stream_example, rfdetr_stream_example, and
ultralytics_stream_example to cv2.imshow/waitKey (requires
opencv-python, not headless).

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
…ption docs

- Replace 'Drop-in replacement' with 'Functional replacement' — wait_key
  returns str not int, mouse callback signature differs from cv2, only
  left-button events captured
- Add 'Differences from cv2' section documenting all three breaking
  behavioural differences for migrating callers
- Correct documented failure mode for headless environments: raises
  AttributeError (PIL.ImageTk missing) not TclError when python3-tk absent;
  distinguish that from display-unavailable case (TclError)

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
PR description promised a webcam/VideoCapture note on this function but
the docstring was left without guidance. Add a Note section showing the
cv2.VideoCapture pattern with explicit release in a finally block for
callers wanting live camera access.

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
TkImageWindow is public API (exported in __all__) but had no docs page.
Add docs/utils/image_window.md and wire it into mkdocs.yml under Utils.

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

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.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 5 comments.

Comment thread src/supervision/utils/image_window.py Outdated
Comment thread src/supervision/utils/image_window.py
Comment thread examples/time_in_zone/ultralytics_stream_example.py Outdated
Comment thread examples/time_in_zone/rfdetr_stream_example.py Outdated
Comment thread examples/time_in_zone/inference_stream_example.py Outdated
- Replace bare `list[np.ndarray]` with `list[npt.NDArray[np.floating]]`
  in _merge_obb_corners signature — fixes mypy missing-type-args error
  introduced by #2312 OBB NMM merge

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
# Conflicts:
#	examples/time_in_zone/inference_stream_example.py
#	examples/time_in_zone/rfdetr_stream_example.py
#	examples/time_in_zone/ultralytics_stream_example.py
@SkalskiP

SkalskiP commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

General question: what happens when someone installs supervision together with inference or ultralytics in the same Python environment? Which OpenCV package gets installed, one or both? If both are installed, which one is used at runtime? Should we have any recommendations for users who run into this setup?

Comment thread examples/time_in_zone/inference_stream_example.py
Comment thread examples/time_in_zone/scripts/draw_zones.py
Comment thread src/supervision/utils/image_window.py Outdated
Comment thread src/supervision/utils/image_window.py Outdated
Comment thread src/supervision/utils/image_window.py
Comment thread docs/changelog.md Outdated
Comment thread docs/changelog.md Outdated
Comment thread docs/faq.md
Borda and others added 10 commits July 9, 2026 14:24
…xports

[resolve group] PR #2320 — item 2

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
…llow; drop banner comments

Bug: _on_mouse forwarded raw label-widget event.x/event.y unscaled while
_fit_image scales+letterboxes the displayed frame, so mouse coordinates
drifted from image-pixel space after any window resize (user-confirmed).
Fix stores display scale/offset at render time and inverts the transform
in _on_mouse, clamped to the original image bounds.

Also extends sv.cv2_to_pillow to support grayscale and BGRA inputs (it
previously only handled 3-channel BGR) and makes _bgr_to_pil delegate to
it instead of duplicating the conversion logic. Drops four decorative
section-separator comment blocks per reviewer request.

[resolve group] PR #2320 — items 1, 2, 5, 8

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
…ing admonition

Updates the TkImageWindow -> ImageWindow rename mention. Deduplicates the
repeated pip uninstall/install snippet under "How to restore GUI support"
and "Co-installation warning" into a single cross-referenced block, and
reframes the opencv-python-headless breaking-change note as a mkdocs
!!! warning admonition instead of a regular bullet so it is not mistaken
for a routine change.

[resolve group] PR #2320 — items 2, 6, 7

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
…1 section

The 0.29.1 tag is already released; filing this PR's changelog entries
there falsely implied the feature shipped in a past release. Moved the
ImageWindow "Added" bullet and the opencv-python-headless breaking-change
warning into the Unreleased section instead.

Also adds test coverage flagged by the QA gate: an end-to-end
resize-then-click path (_on_configure -> _on_mouse) and mouse-coordinate
mapping under keep_aspect_ratio=False (stretched mode), both previously
untested.

[resolve] PR #2320 — Step 9 QA gate fixes

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
- Add ImageWindow.is_open so display loops can stop cleanly when the Tk window is closed.\n\n- Update examples, docs, and FAQ guidance to use the new window-state check and clarify OpenCV wheel selection.\n\n- Tighten grayscale crop tests and cap opencv-python-headless below 5 for compatibility.

---

Co-authored-by: Codex <codex@openai.com>
@Borda Borda requested a review from SkalskiP July 10, 2026 15:51

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.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 3 comments.

Comment thread src/supervision/utils/image_window.py
Comment thread src/supervision/utils/image_window.py Outdated
Comment thread src/supervision/__init__.py
Borda and others added 2 commits July 10, 2026 18:08
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants