refactor: enrich KeyPoints with visibility mask, split confidence fields, and redesign uncertainty annotator#2286
Conversation
…lds, and redesign uncertainty annotator
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #2286 +/- ##
=======================================
- Coverage 80% 80% -0%
=======================================
Files 66 66
Lines 8787 8799 +12
=======================================
+ Hits 7046 7050 +4
- Misses 1741 1749 +8 🚀 New features to boost your workflow:
|
* fix: resolve ruff line-length and mypy union syntax errors in keypoints module Co-authored-by: Cursor <cursoragent@cursor.com> * docs: add API design principles to CONTRIBUTING.md --------- Co-authored-by: Cursor <cursoragent@cursor.com>
… add API design principles to CONTRIBUTING.md
#2293) * feat: support per-class skeleton edges in EdgeAnnotator via dict[int, edges] mapping * fix(pre_commit): 🎨 auto format pre-commit hooks * docs: simplify EdgeAnnotator edges parameter docstring * test: add multi-skeleton EdgeAnnotator tests and demo script Co-authored-by: Cursor <cursoragent@cursor.com> * fix(pre_commit): 🎨 auto format pre-commit hooks * refactor: add multi-skeleton support to EdgeAnnotator and VertexLabelAnnotator * fix(pre_commit): 🎨 auto format pre-commit hooks * chore: remove test script from tracking and gitignore it * mypy passes * Add unified docstring examples for all keypoint annotators with Python syntax highlighting and multi-skeleton demos * Add label validation to VertexLabelAnnotator and parametrized tests for _resolve_labels * fix(pre_commit): 🎨 auto format pre-commit hooks * Add label validation and parametrized tests for VertexLabelAnnotator._resolve_labels * Add color list length validation to _resolve_color_list and parametrized tests * Cast NumPy class_id to int and raise ValueError on misconfigured edge dicts --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the KeyPoints container to better represent keypoint- and detection-level confidence while adding a per-keypoint visible mask, and then propagates those semantics through keypoint annotators (including a redesign of the uncertainty visualizer). It also refreshes validators, tests, and documentation to match the new API, and adds explicit API design principles to CONTRIBUTING.
Changes:
- Refactors
KeyPointsto addkeypoint_confidence,detection_confidence, and optionalvisible, while keepingconfidenceas a deprecated forwarder. - Updates keypoint annotators (
VertexAnnotator,EdgeAnnotator,VertexLabelAnnotator) to honorvisible, adds multi-skeleton support (per-class edges/labels), and replacesVertexEllipseAnnotatorwithVertexUncertaintyAnnotator. - Cleans up validators and adjusts tests/docs to cover and demonstrate the new behavior.
Quality (n/5):
- Code quality: 4/5
- Testing: 4/5
- Docs: 3/5
Reviewed changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Bumps dev version metadata and relaxes pydeprecate upper bound. |
tests/key_points/test_from_rfdetr.py |
Removes RF-DETR conversion tests (conversion path removed). |
tests/key_points/test_core.py |
Adds coverage for detection_confidence filtering and visible propagation; updates confidence naming. |
tests/key_points/test_annotators.py |
Adds visibility behavior tests; updates uncertainty annotator tests to new class. |
tests/helpers.py |
Updates KeyPoints factory helper to support detection_confidence and visible. |
src/supervision/validators/__init__.py |
Splits detection vs keypoint confidence validation and adds validate_visible. |
src/supervision/key_points/core.py |
Implements new KeyPoints fields, deprecates .confidence, updates slicing/filtering behavior. |
src/supervision/key_points/annotators.py |
Honors visible, adds per-class skeleton/labels support, and introduces VertexUncertaintyAnnotator. |
src/supervision/__init__.py |
Exports VertexUncertaintyAnnotator instead of VertexEllipseAnnotator. |
docs/keypoint/annotators.md |
Renames the uncertainty annotator section and API references. |
.gitignore |
Ignores a local test script. |
.github/CONTRIBUTING.md |
Adds explicit API design principles for integrations/annotators/containers. |
| detection_confidence_selected = ( | ||
| self.detection_confidence[i] | ||
| if self.detection_confidence is not None | ||
| else None | ||
| ) |
…split Co-authored-by: Cursor <cursoragent@cursor.com>
d095a78 to
b8aa64f
Compare
… and simplify its constructor API
…r` to `VertexEllipseAnnotator`, simplifying its parameters (`sigma`, `color`, removing `covariance_data_key`), unifying `opacity` docstrings across all annotators, removing the `opacity` validation guard, and converting all keypoint annotator examples into executable doctests.
4c32bc6 to
ce4c5a6
Compare
… full allowed line length.
…into a ``!!!` warning admonition, renamed `max_axis_length` to `max_axis`, and fixed the `VertexEllipseAnnotator` docs example by removing the manual covariance block and invalid `thickness` parameter.
| max_axis_length: float | None = None, | ||
| line_style: Literal["solid", "dashed"] = "solid", | ||
| dash_length: int = 16, | ||
| sigma: float | Sequence[float] = (1.0, 2.0, 3.0), |
There was a problem hiding this comment.
I would probably go with just one as default but that is also fine
| line_style: Literal["solid", "dashed"] = "solid", | ||
| dash_length: int = 16, | ||
| sigma: float | Sequence[float] = (1.0, 2.0, 3.0), | ||
| color: Color | Sequence[Color] = (Color.GREEN, Color.YELLOW, Color.RED), |
There was a problem hiding this comment.
could be good to have also just palet as input and colours will be sapled based on nb sigmas
| color: The color for each sigma level. Accepts a single | ||
| ``Color`` or a sequence of colors (one per sigma level). | ||
| Defaults to ``(Color.GREEN, Color.YELLOW, Color.RED)``. | ||
| opacity: Opacity of the overlay mask. Must be between ``0`` and |
There was a problem hiding this comment.
To match the colors, can we also have optical for each sigma?
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
docs/keypoint/annotators.md:96
- The
VertexEllipseAnnotatorexample no longer setskey_points.data['covariance'], butVertexEllipseAnnotator.annotate()raises aValueErrorwhen covariance is missing. As written, this snippet won’t run.
```python
import supervision as sv
image = ...
key_points = sv.KeyPoints(...)
ellipse_annotator = sv.VertexEllipseAnnotator(
color=sv.Color.GREEN,
sigma=2.0,
)
annotated_frame = ellipse_annotator.annotate(
scene=image.copy(),
key_points=key_points,
)
```
| if not isinstance(visible, np.ndarray) or visible.ndim != 2: | ||
| raise ValueError( | ||
| f"visible must be a 2D np.ndarray with shape (n, m), but " | ||
| f"got shape {actual_shape}" | ||
| ) |
| sigma_seq: Sequence[float] = ( | ||
| (sigma,) if isinstance(sigma, (int, float)) else sigma | ||
| ) | ||
| color_seq: Sequence[Color] = (color,) if isinstance(color, Color) else color |
| for j in range(points_count): | ||
| if key_points.visible is not None: | ||
| if not key_points.visible[i, j]: | ||
| continue | ||
| elif np.allclose(xy[j], 0): | ||
| continue |
| detection_confidence_selected = None | ||
| if self.detection_confidence is not None: | ||
| detection_confidence_selected = self.detection_confidence[i] | ||
|
|
| if self.visible is not None: | ||
| visible_selected = self.visible[i, j] | ||
|
|
||
| class_id_selected = self.class_id[i] if self.class_id is not None else None |
| class VertexEllipseAnnotator(BaseKeyPointAnnotator): | ||
| """ | ||
| A class that draws covariance ellipses around skeleton vertices. | ||
| Draws concentric covariance ellipses at multiple sigma levels around each | ||
| keypoint, each ring in a different color. This produces a bullseye-like | ||
| uncertainty visualization where inner rings represent higher probability |
| Args: | ||
| xy: Keypoint coordinates in `(x, y)` format for | ||
| each detection. | ||
| confidence: Confidence scores for each keypoint. | ||
| confidence: Per-keypoint confidence scores. | ||
| class_id: Class identifiers for each keypoint set. | ||
| detection_confidence: Detection-level confidence scores. | ||
| data: Additional data to be associated with | ||
| each keypoint set. |
| color: The color to use for each keypoint label. If a list is | ||
| provided, the colors will be used in order for each keypoint. | ||
| text_color: The color to use for the labels. If a list is | ||
| provided, the colors will be used in order for each keypoint. |
There was a problem hiding this comment.
seems like your IDE does not follow max docsting length
Summary
keypoint_confidence(per-keypoint, shape(N, M)) anddetection_confidence(per-detection, shape(N,)). The oldconfidenceattribute is preserved as a deprecated property that forwards tokeypoint_confidence.visiblemask: A boolean array(N, M)that lets callers mark keypoints as occluded/invisible without dropping data.VertexAnnotatorandEdgeAnnotatornow skip keypoints (and edges) wherevisibleisFalse.VertexEllipseAnnotatorwithVertexUncertaintyAnnotator, which draws concentric filled ellipses at configurable sigma levels with opacity blending and a red-yellow-green color gradient.validate_keypoint_confidence,validate_keypoints_fields), renamevalidate_confidencetovalidate_detection_confidence, and addvalidate_visible. Improve error messages with dimension-specific diagnostics.