forked from tangger/lerobot
[skip ci] refactor(cameras): add warmup read + images different size testing opencv + compressed test artefacts
This commit is contained in:
@@ -27,7 +27,7 @@ repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
#- id: check-added-large-files
|
||||
- id: debug-statements
|
||||
- id: check-merge-conflict
|
||||
- id: check-case-conflict
|
||||
|
||||
@@ -34,7 +34,7 @@ class Camera(abc.ABC):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def connect(self) -> None:
|
||||
def connect(self, do_warmup_read: bool = True) -> None:
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
|
||||
@@ -302,7 +302,7 @@ class RealSenseCamera(Camera):
|
||||
)
|
||||
|
||||
# NOTE(Steven): Add a wamr-up period time config
|
||||
def connect(self):
|
||||
def connect(self, do_warmup_read: bool = True):
|
||||
"""
|
||||
Connects to the RealSense camera specified in the configuration.
|
||||
|
||||
@@ -337,8 +337,9 @@ class RealSenseCamera(Camera):
|
||||
logger.debug(f"Validating stream configuration for {self.serial_number}...")
|
||||
self._validate_capture_settings()
|
||||
|
||||
logger.debug(f"Reading a warm-up frame for {self.serial_number}...")
|
||||
self.read() # NOTE(Steven): For now we just read one frame, we could also loop for X secs
|
||||
if do_warmup_read:
|
||||
logger.debug(f"Reading a warm-up frame for {self.serial_number}...")
|
||||
self.read() # NOTE(Steven): For now we just read one frame, we could also loop for X secs
|
||||
|
||||
logger.info(f"Camera {self.serial_number} connected and configured successfully.")
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ class OpenCVCamera(Camera):
|
||||
self._validate_fps()
|
||||
self._validate_width_and_height()
|
||||
|
||||
def connect(self):
|
||||
def connect(self, do_warmup_read: bool = True):
|
||||
"""
|
||||
Connects to the OpenCV camera specified in the configuration.
|
||||
|
||||
@@ -206,8 +206,9 @@ class OpenCVCamera(Camera):
|
||||
logger.debug(f"Successfully opened camera {self.index_or_path}. Applying configuration...")
|
||||
self._configure_capture_settings()
|
||||
|
||||
logger.debug(f"Reading a warm-up frame for {self.serial_number}...")
|
||||
self.read() # NOTE(Steven): For now we just read one frame, we could also loop for X secs\
|
||||
if do_warmup_read:
|
||||
logger.debug(f"Reading a warm-up frame for {self.index_or_path}...")
|
||||
self.read() # NOTE(Steven): For now we just read one frame, we could also loop for X secs\
|
||||
|
||||
logger.debug(f"Camera {self.index_or_path} connected and configured successfully.")
|
||||
|
||||
|
||||
BIN
tests/artifacts/cameras/compressed_bag.tar.bz2
Normal file
BIN
tests/artifacts/cameras/compressed_bag.tar.bz2
Normal file
Binary file not shown.
BIN
tests/artifacts/cameras/compressed_fakecams.tar.bz2
Normal file
BIN
tests/artifacts/cameras/compressed_fakecams.tar.bz2
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 753 KiB |
Binary file not shown.
@@ -19,6 +19,8 @@
|
||||
# pytest tests/cameras/test_opencv.py::test_connect
|
||||
# ```
|
||||
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
@@ -26,8 +28,6 @@ from lerobot.common.cameras.configs import Cv2Rotation
|
||||
from lerobot.common.cameras.opencv import OpenCVCamera, OpenCVCameraConfig
|
||||
from lerobot.common.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError
|
||||
|
||||
# NOTE(Steven): Patch get/set calls
|
||||
|
||||
|
||||
def test_base_class_implementation():
|
||||
config = OpenCVCameraConfig(index_or_path=0)
|
||||
@@ -36,21 +36,21 @@ def test_base_class_implementation():
|
||||
|
||||
|
||||
def test_connect():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
assert camera.is_connected
|
||||
|
||||
|
||||
def test_connect_already_connected():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
with pytest.raises(DeviceAlreadyConnectedError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
def test_connect_invalid_camera_path():
|
||||
@@ -58,25 +58,34 @@ def test_connect_invalid_camera_path():
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
with pytest.raises(ConnectionError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
def test_invalid_width_connect():
|
||||
config = OpenCVCameraConfig(
|
||||
index_or_path="tests/artifacts/cameras/fake_cam.png",
|
||||
index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png",
|
||||
width=99999, # Invalid width to trigger error
|
||||
height=480,
|
||||
)
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
def test_read():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
@pytest.mark.parametrize(
|
||||
"index_or_path",
|
||||
[
|
||||
"tests/artifacts/cameras/fakecam_sd_640x480.png",
|
||||
"tests/artifacts/cameras/fakecam_hd_1280x720.png",
|
||||
"tests/artifacts/cameras/fakecam_fullhd_1920x1080.png",
|
||||
"tests/artifacts/cameras/fakecam_square_512x512.png",
|
||||
],
|
||||
)
|
||||
def test_read(index_or_path):
|
||||
config = OpenCVCameraConfig(index_or_path=index_or_path)
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.read()
|
||||
|
||||
@@ -84,7 +93,7 @@ def test_read():
|
||||
|
||||
|
||||
def test_read_before_connect():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
with pytest.raises(DeviceNotConnectedError):
|
||||
@@ -92,9 +101,9 @@ def test_read_before_connect():
|
||||
|
||||
|
||||
def test_disconnect():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
camera.disconnect()
|
||||
|
||||
@@ -102,17 +111,26 @@ def test_disconnect():
|
||||
|
||||
|
||||
def test_disconnect_before_connect():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
with pytest.raises(DeviceNotConnectedError):
|
||||
_ = camera.disconnect()
|
||||
|
||||
|
||||
def test_async_read():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
@pytest.mark.parametrize(
|
||||
"index_or_path",
|
||||
[
|
||||
"tests/artifacts/cameras/fakecam_sd_640x480.png",
|
||||
"tests/artifacts/cameras/fakecam_hd_1280x720.png",
|
||||
"tests/artifacts/cameras/fakecam_fullhd_1920x1080.png",
|
||||
"tests/artifacts/cameras/fakecam_square_512x512.png",
|
||||
],
|
||||
)
|
||||
def test_async_read(index_or_path):
|
||||
config = OpenCVCameraConfig(index_or_path=index_or_path)
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.async_read()
|
||||
|
||||
@@ -123,9 +141,9 @@ def test_async_read():
|
||||
|
||||
|
||||
def test_async_read_timeout():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
with pytest.raises(TimeoutError):
|
||||
camera.async_read(timeout_ms=0)
|
||||
@@ -134,13 +152,22 @@ def test_async_read_timeout():
|
||||
|
||||
|
||||
def test_async_read_before_connect():
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png")
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fakecam_sd_640x480.png")
|
||||
camera = OpenCVCamera(config)
|
||||
|
||||
with pytest.raises(DeviceNotConnectedError):
|
||||
_ = camera.async_read()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"index_or_path",
|
||||
[
|
||||
"tests/artifacts/cameras/fakecam_sd_640x480.png",
|
||||
"tests/artifacts/cameras/fakecam_hd_1280x720.png",
|
||||
"tests/artifacts/cameras/fakecam_fullhd_1920x1080.png",
|
||||
"tests/artifacts/cameras/fakecam_square_512x512.png",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"rotation",
|
||||
[
|
||||
@@ -150,21 +177,25 @@ def test_async_read_before_connect():
|
||||
Cv2Rotation.ROTATE_270,
|
||||
],
|
||||
)
|
||||
def test_all_rotations(rotation):
|
||||
config = OpenCVCameraConfig(index_or_path="tests/artifacts/cameras/fake_cam.png", rotation=rotation)
|
||||
def test_all_rotations(rotation, index_or_path):
|
||||
filename = os.path.basename(index_or_path)
|
||||
dimensions = filename.split("_")[-1].split(".")[0] # Assumes filenames format (_wxh.png)
|
||||
original_width, original_height = map(int, dimensions.split("x"))
|
||||
|
||||
config = OpenCVCameraConfig(index_or_path=index_or_path, rotation=rotation)
|
||||
camera = OpenCVCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.read()
|
||||
assert isinstance(img, np.ndarray)
|
||||
|
||||
if rotation in (Cv2Rotation.ROTATE_90, Cv2Rotation.ROTATE_270):
|
||||
assert camera.width == 480
|
||||
assert camera.height == 640
|
||||
assert img.shape[:2] == (640, 480)
|
||||
assert camera.width == original_height
|
||||
assert camera.height == original_width
|
||||
assert img.shape[:2] == (original_width, original_height)
|
||||
else:
|
||||
assert camera.width == 640
|
||||
assert camera.height == 480
|
||||
assert img.shape[:2] == (480, 640)
|
||||
assert camera.width == original_width
|
||||
assert camera.height == original_height
|
||||
assert img.shape[:2] == (original_height, original_width)
|
||||
|
||||
camera.disconnect()
|
||||
|
||||
@@ -47,28 +47,28 @@ def mock_rs_config_enable_device_bad_file(rs_config_instance, sn):
|
||||
return rs_config_instance.enable_device_from_file("non_existent_file.bag", repeat_playback=True)
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file)
|
||||
def test_connect(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42)
|
||||
camera = RealSenseCamera(config)
|
||||
|
||||
camera.connect()
|
||||
assert camera.is_connected
|
||||
|
||||
|
||||
def test_base_class_implementation():
|
||||
config = RealSenseCameraConfig(serial_number=42)
|
||||
_ = RealSenseCamera(config)
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file)
|
||||
def test_connect(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42)
|
||||
camera = RealSenseCamera(config)
|
||||
|
||||
camera.connect(do_warmup_read=False)
|
||||
assert camera.is_connected
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file)
|
||||
def test_connect_already_connected(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
with pytest.raises(DeviceAlreadyConnectedError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_bad_file)
|
||||
@@ -77,7 +77,7 @@ def test_connect_invalid_camera_path(mock_enable_device):
|
||||
camera = RealSenseCamera(config)
|
||||
|
||||
with pytest.raises(ConnectionError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file)
|
||||
@@ -86,14 +86,14 @@ def test_invalid_width_connect(mock_enable_device):
|
||||
camera = RealSenseCamera(config)
|
||||
|
||||
with pytest.raises(ConnectionError):
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
|
||||
@patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file)
|
||||
def test_read(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.read()
|
||||
assert isinstance(img, np.ndarray)
|
||||
@@ -111,7 +111,7 @@ def test_read_before_connect():
|
||||
def test_disconnect(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
camera.disconnect()
|
||||
|
||||
@@ -130,7 +130,7 @@ def test_disconnect_before_connect():
|
||||
def test_async_read(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.async_read()
|
||||
|
||||
@@ -144,7 +144,7 @@ def test_async_read(mock_enable_device):
|
||||
def test_async_read_timeout(mock_enable_device):
|
||||
config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
with pytest.raises(TimeoutError):
|
||||
camera.async_read(timeout_ms=0)
|
||||
@@ -173,7 +173,7 @@ def test_async_read_before_connect():
|
||||
def test_all_rotations(mock_enable_device, rotation):
|
||||
config = RealSenseCameraConfig(serial_number=42, rotation=rotation)
|
||||
camera = RealSenseCamera(config)
|
||||
camera.connect()
|
||||
camera.connect(do_warmup_read=False)
|
||||
|
||||
img = camera.read()
|
||||
assert isinstance(img, np.ndarray)
|
||||
|
||||
Reference in New Issue
Block a user