Source code for robotblockset.cameras.camera_discovery

"""Connected camera discovery utilities.

Module to automatically resolve the desired connected camera.
Useful when you want to support both ZED and RealSense cameras in your scripts and CLIs.
"""

from enum import Enum
from typing import Any, Callable, Optional

from robotblockset.cameras.interfaces import RGBDCamera

# from loguru import logger
from robotblockset.tools import get_logger

logger = get_logger(__name__)


# Note: the order of this enum also determines the order in which the cameras are tried
[docs] class CameraBrand(Enum): ZED = "zed" REALSENSE = "realsense"
SUPPORTED_CAMERAS = [m.value for m in CameraBrand]
[docs] def discover_camera(brand: Optional[str], serial_number: Optional[str] = None, **kwargs: Any) -> RGBDCamera: """ Find a connected camera, optionally filtering by brand and serial number. Parameters ---------- brand : str, optional Camera brand to search for. serial_number : str, optional Serial number of the camera to use. **kwargs : Any Additional arguments passed to the camera constructor. Returns ------- RGBDCamera The discovered camera instance. """ logger.info(f"Resolving camera with brand {brand} and serial number {serial_number}.") if brand is None: for brand in SUPPORTED_CAMERAS: try: return discover_camera(brand, serial_number=serial_number, **kwargs) except Exception: pass raise RuntimeError("Could not find camera with the requested parameters.") brand = brand.lower() brand_enum = CameraBrand(brand) # Attempt to convert to enum if brand_enum == CameraBrand.ZED: from robotblockset.cameras.zed import Zed camera = Zed(serial_number=serial_number, **kwargs) elif brand_enum == CameraBrand.REALSENSE: from robotblockset.cameras.realsense import Realsense camera = Realsense(serial_number=serial_number, **kwargs) # type: ignore else: raise RuntimeError(f"Camera brand {brand} not supported.") # Should be unreachable due to enum logger.info(f"Found {brand_enum.value} camera.") return camera
[docs] def click_camera_options(f: Callable) -> Callable: """ Add camera selection options to a Click command. This decorator adds command-line options for camera brand and serial number to a Click command function. Parameters ---------- f : Callable Function to decorate with the additional command-line arguments. Returns ------- Callable Decorated Click command function. """ import click camera_brand_help = f"The brand of the camera to use, one of {SUPPORTED_CAMERAS}" camera_serial_number_help = "Serial number of the camera to use (if you have multiple cameras connected)." f = click.option("--camera_brand", help=camera_brand_help)(f) f = click.option("--camera_serial_number", default=None, type=str, help=camera_serial_number_help)(f) return f
if __name__ == "__main__": import click import cv2 from robotblockset.cameras.image_converter import ImageConverter @click.command() @click_camera_options def show_camera_feed(camera_brand: str, camera_serial_number: str) -> None: """Script to test the automatic camera discovery.""" camera = discover_camera(camera_brand, camera_serial_number) window_name = "Camera feed" cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) print("Press Q to quit.") while True: image_rgb = camera.get_rgb_image_as_int() image = ImageConverter.from_numpy_int_format(image_rgb).image_in_opencv_format cv2.imshow(window_name, image) key = cv2.waitKey(1) if key == ord("q"): break show_camera_feed()