Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,29 @@ jobs:

- name: Run tests
if: matrix.os != 'windows-latest'
run: pytest tests -p no:cacheprovider -p no:faulthandler -p no:unraisableexception
run: |
mkdir -p "${{ github.workspace }}/test-reports"
pytest -vv --tb=long \
--junitxml="${{ github.workspace }}/test-reports/junit-${{ matrix.os }}-py${{ matrix.python-version }}.xml" \
tests -p no:cacheprovider -p no:faulthandler -p no:unraisableexception

- name: Run tests (Windows, disable MSMF)
if: matrix.os == 'windows-latest'
env:
OPENCV_VIDEOIO_PRIORITY_MSMF: "0"
run: pytest tests -p no:cacheprovider -p no:faulthandler -p no:unraisableexception
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path "${{ github.workspace }}/test-reports" | Out-Null
pytest -vv --tb=long `
--junitxml="${{ github.workspace }}/test-reports/junit-${{ matrix.os }}-py${{ matrix.python-version }}.xml" `
tests -p no:cacheprovider -p no:faulthandler -p no:unraisableexception

- name: Upload test report
if: always()
uses: actions/upload-artifact@v4
with:
name: pytest-junit-${{ matrix.os }}-py${{ matrix.python-version }}
path: ${{ github.workspace }}/test-reports/junit-${{ matrix.os }}-py${{ matrix.python-version }}.xml

build-docs:
runs-on: ubuntu-latest
Expand Down
10 changes: 8 additions & 2 deletions pyneon/video/marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ def generate_marker(
return img


def _normalize_marker_id(marker_id: int | np.ndarray) -> int:
"""Normalize marker IDs returned by OpenCV across shape variants."""
return int(np.asarray(marker_id).reshape(-1)[0])


@fill_doc
def detect_markers(
video: "Video",
Expand Down Expand Up @@ -133,6 +138,7 @@ def _process_frame(frame_idx: int, gray_frame: np.ndarray) -> list[dict]:

for corners, marker_id in zip(all_corners, all_ids):
corners = corners.reshape((4, 2))
marker_id_int = _normalize_marker_id(marker_id)
if fam_type == "april":
# For AprilTags, corners start with bottom right
# For ArUco, corners start with top left
Expand All @@ -147,8 +153,8 @@ def _process_frame(frame_idx: int, gray_frame: np.ndarray) -> list[dict]:
"timestamp [ns]": video.ts[frame_idx],
"frame index": frame_idx,
"marker family": fam_name,
"marker id": int(marker_id[0]),
"marker name": f"{fam_name}_{marker_id[0]}",
"marker id": marker_id_int,
"marker name": f"{fam_name}_{marker_id_int}",
"top left x [px]": corners[0, 0],
"top left y [px]": corners[0, 1],
"top right x [px]": corners[1, 0],
Expand Down
43 changes: 43 additions & 0 deletions tests/test_video_marker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import numpy as np
import pytest

from pyneon.video import marker


class _DummyVideo:
def __init__(self):
self.ts = np.array([123], dtype=np.int64)

def reset(self):
return None

def read_frame_at(self, frame_index: int):
return np.zeros((2, 2, 3), dtype=np.uint8)


@pytest.mark.parametrize("raw_marker_id", [7, np.array(7), np.array([7])])
def test_normalize_marker_id_shapes(raw_marker_id):
normalized_marker_id = marker._normalize_marker_id(raw_marker_id)
assert isinstance(normalized_marker_id, int)
assert normalized_marker_id == 7


@pytest.mark.parametrize("raw_marker_id", [7, np.array(7), np.array([7])])
def test_detect_markers_normalizes_marker_id_shapes(monkeypatch, raw_marker_id):
class _DummyDetector:
def detectMarkers(self, gray_frame):
corners = [
np.array(
[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]],
dtype=np.float32,
)
]
return corners, [raw_marker_id], None

monkeypatch.setattr(marker, "marker_family_to_dict", lambda _: ("aruco", object()))
monkeypatch.setattr(marker.cv2.aruco, "ArucoDetector", lambda *_: _DummyDetector())

detections = marker.detect_markers(_DummyVideo(), marker_family="5x5_50")

assert detections.data.iloc[0]["marker id"] == "7"
assert detections.data.iloc[0]["marker name"] == "5x5_50_7"
Loading