Skip to content
This repository was archived by the owner on Dec 30, 2025. It is now read-only.
Open
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
18 changes: 18 additions & 0 deletions tests/test_camera/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import zoloto.cameras
from tests.strategies import marker_types
from zoloto.exceptions import CameraOpenError
from zoloto.marker_type import MarkerType


Expand Down Expand Up @@ -57,3 +58,20 @@ def test_get_no_camera_ids(mocker: MockerFixture) -> None:
VideoCapture.return_value.isOpened.return_value = False
discovered_ids = list(zoloto.cameras.camera.find_camera_ids())
assert len(discovered_ids) == 0


def test_cannot_create_unopened_camera(mocker: MockerFixture) -> None:
VideoCapture = mocker.patch("zoloto.cameras.camera.VideoCapture")
VideoCapture.return_value.isOpened.return_value = False
with pytest.raises(CameraOpenError):
zoloto.cameras.Camera(0, marker_type=MarkerType.APRILTAG_36H11)


def test_cannot_create_unopened_snapshotcamera(mocker: MockerFixture) -> None:
VideoCapture = mocker.patch("zoloto.cameras.camera.VideoCapture")
VideoCapture.return_value.isOpened.return_value = False
camera = zoloto.cameras.camera.SnapshotCamera(
0, marker_type=MarkerType.APRILTAG_36H11
)
with pytest.raises(CameraOpenError):
camera.capture_frame()
14 changes: 10 additions & 4 deletions tests/test_camera/test_camera_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ def test_exposes_file_camera(camera_name: str) -> None:


@given(marker_types())
def test_camera_requires_marker_size(marker_type: MarkerType) -> None:
def test_camera_requires_marker_size(
marker_camera: zoloto.cameras.marker.MarkerCamera,
temp_image_file: Path,
marker_type: MarkerType,
) -> None:
marker_camera.save_frame(temp_image_file)

camera = zoloto.cameras.file.ImageFileCamera(
Path("test.png"), marker_type=marker_type
temp_image_file, marker_type=marker_type
)
with pytest.raises(ValueError):
camera.get_marker_size(0)
Expand All @@ -31,11 +37,11 @@ class TestCamera(zoloto.cameras.file.ImageFileCamera):
def get_marker_size(self, marker_id: int) -> int:
return 200

camera = TestCamera(Path("test.png"), marker_type=marker_type)
camera = TestCamera(temp_image_file, marker_type=marker_type)
assert camera.get_marker_size(0) == 200

camera = zoloto.cameras.file.ImageFileCamera(
Path("test.png"),
temp_image_file,
marker_type=marker_type,
marker_size=200,
)
Expand Down
21 changes: 21 additions & 0 deletions tests/test_camera/test_file_camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pathlib import Path

import pytest

from zoloto.cameras.file import ImageFileCamera, VideoFileCamera
from zoloto.exceptions import CameraOpenError
from zoloto.marker_type import MarkerType


def test_video_camera_unknown_file() -> None:
with pytest.raises(CameraOpenError):
VideoFileCamera(
Path.cwd() / "missing.mp4", marker_type=MarkerType.APRILTAG_36H11
)


def test_image_camera_unknown_file() -> None:
with pytest.raises(CameraOpenError):
ImageFileCamera(
Path.cwd() / "missing.png", marker_type=MarkerType.APRILTAG_36H11
)
9 changes: 8 additions & 1 deletion zoloto/cameras/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from cv2 import CAP_PROP_BUFFERSIZE, VideoCapture
from numpy import ndarray

from zoloto.exceptions import CameraOpenError
from zoloto.marker_type import MarkerType

from .base import BaseCamera
Expand Down Expand Up @@ -41,6 +42,9 @@ def __init__(
self.camera_id = camera_id
self.video_capture = self.get_video_capture(self.camera_id)

if not self.video_capture.isOpened():
raise CameraOpenError(f"Failed to open camera {self.camera_id}")

def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {self.camera_id}>"

Expand Down Expand Up @@ -90,7 +94,10 @@ def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {self.camera_id}>"

def get_video_capture(self, camera_id: int) -> VideoCapture:
return VideoCapture(camera_id)
capture = VideoCapture(camera_id)
if not capture.isOpened():
raise CameraOpenError(f"Failed to open camera {self.camera_id}")
return capture

def capture_frame(self) -> ndarray:
self.video_capture = self.get_video_capture(self.camera_id)
Expand Down
13 changes: 10 additions & 3 deletions zoloto/cameras/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from cv2 import VideoCapture, imread
from numpy import ndarray

from zoloto.exceptions import CameraReadError
from zoloto.exceptions import CameraOpenError, CameraReadError
from zoloto.marker_type import MarkerType

from .base import BaseCamera
Expand All @@ -20,18 +20,22 @@ def __init__(
marker_type: MarkerType,
calibration_file: Optional[Path] = None,
) -> None:
self.image_path = image_path
super().__init__(
marker_size=marker_size,
marker_type=marker_type,
calibration_file=calibration_file,
)
self.image_path = image_path
self._frame = imread(str(self.image_path))

if self._frame is None:
raise CameraOpenError(f"Failed to read file {self.image_path}")

def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {self.image_path}>"

def capture_frame(self) -> ndarray:
return imread(str(self.image_path))
return self._frame


class VideoFileCamera(
Expand All @@ -53,6 +57,9 @@ def __init__(
self.video_path = video_path
self.video_capture = VideoCapture(str(self.video_path))

if not self.video_capture.isOpened():
raise CameraOpenError(f"Failed to read file {self.video_path}")

def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {self.video_path}>"

Expand Down
4 changes: 4 additions & 0 deletions zoloto/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ class CameraReadError(ZolotoException):
def __init__(self, frame: Optional[ndarray]):
self.frame = frame
super().__init__()


class CameraOpenError(ZolotoException):
pass