Source code for robotblockset.cameras.realsense_scan_profiles

"""Intel RealSense scan profile utilities."""

from __future__ import annotations

from typing import Dict, List, Sequence, Tuple

import numpy as np
import pyrealsense2 as rs  # type: ignore


[docs] def calculate_fov(width: int, height: int, fx: float, fy: float) -> Tuple[float, float]: """ Compute horizontal and vertical field-of-view angles in degrees. Parameters ---------- width : int Image width in pixels. height : int Image height in pixels. fx : float Focal length in x direction (pixels). fy : float Focal length in y direction (pixels). Returns ------- tuple[float, float] Horizontal and vertical FoV in degrees. Raises ------ ValueError If the dimensions or focal lengths are not positive and finite. """ if width <= 0 or height <= 0: raise ValueError("width and height must be positive") if not np.isfinite(fx) or not np.isfinite(fy) or fx <= 0 or fy <= 0: raise ValueError("fx and fy must be positive and finite") fov_x = np.rad2deg(2 * np.arctan2(width, 2 * fx)) fov_y = np.rad2deg(2 * np.arctan2(height, 2 * fy)) return (float(fov_x), float(fov_y))
[docs] def scan_profiles( stream_profiles: Sequence[rs.stream_profile], # type: ignore ) -> Tuple[Dict[Tuple[int, int], List[int]], Dict[Tuple[int, int], Tuple[float, float]]]: """ Scan stream profiles and collect supported resolution/FPS/FoV values. Parameters ---------- stream_profiles : List[rs.stream_profile] RealSense stream profiles to inspect. Returns ------- tuple[dict[tuple[int, int], list[int]], dict[tuple[int, int], tuple[float, float]]] Two mappings: supported FPS values per resolution and FoV per resolution. """ resolution_fps_combinations: Dict[Tuple[int, int], List[int]] = {} resolution_fov_combinations: Dict[Tuple[int, int], Tuple[float, float]] = {} for stream_profile in stream_profiles: if not stream_profile.is_video_stream_profile(): continue profile = stream_profile.as_video_stream_profile() if profile.format() != rs.format.rgb8 and profile.format() != rs.format.z16: continue if profile.stream_type() == rs.stream.infrared: continue resolution = (profile.width(), profile.height()) fps = int(profile.fps()) intrinsics = profile.get_intrinsics() fov_H, fov_V = calculate_fov(intrinsics.width, intrinsics.height, intrinsics.fx, intrinsics.fy) if resolution not in resolution_fps_combinations: resolution_fps_combinations[resolution] = [fps] resolution_fov_combinations[resolution] = (fov_H, fov_V) else: if fps not in resolution_fps_combinations[resolution]: resolution_fps_combinations[resolution].append(fps) # sort the fps lists in ascending order for resolution in resolution_fps_combinations: resolution_fps_combinations[resolution].sort() return resolution_fps_combinations, resolution_fov_combinations
[docs] def check_aligned_depth_resolutions( device_serial: str, color_framerates: Dict[Tuple[int, int], List[int]], depth_framerates: Dict[Tuple[int, int], List[int]], ) -> None: """Check depth-to-color alignment for each supported resolution pair.""" color_resolution_max_fps = {resolution: framerates[-1] for resolution, framerates in color_framerates.items()} depth_resolution_max_fps = {resolution: framerates[-1] for resolution, framerates in depth_framerates.items()} print("Checking aligned depth resolution (should equal color resolution):") for color_resolution, color_fps in color_resolution_max_fps.items(): for depth_resolution, depth_fps in depth_resolution_max_fps.items(): pipeline = rs.pipeline() config = rs.config() config.enable_device(device_serial) config.enable_stream(rs.stream.color, *color_resolution, rs.format.rgb8, color_fps) config.enable_stream(rs.stream.depth, *depth_resolution, rs.format.z16, depth_fps) pipeline_wrapper = rs.pipeline_wrapper(pipeline) if not config.can_resolve(pipeline_wrapper): print( f"color_resolution = {color_resolution}, depth_resolution = {depth_resolution}: " "unsupported stream combination" ) continue pipeline_started = False try: pipeline.start(config) pipeline_started = True composite_frame = pipeline.wait_for_frames() color_frame = composite_frame.get_color_frame() depth_frame = composite_frame.get_depth_frame() if not color_frame or not depth_frame: print( f"color_resolution = {color_resolution}, depth_resolution = {depth_resolution}: " "missing color or depth frame" ) continue aligned_frames = rs.align(rs.stream.color).process(composite_frame) aligned_depth_frame = aligned_frames.get_depth_frame() if not aligned_depth_frame: print( f"color_resolution = {color_resolution}, depth_resolution = {depth_resolution}: " "alignment did not produce a depth frame" ) continue aligned_resolution = (aligned_depth_frame.get_width(), aligned_depth_frame.get_height()) print( f"color_resolution = {color_resolution}, depth_resolution = {depth_resolution}, " f"aligned_depth = {aligned_resolution}" ) except RuntimeError as error: print( f"color_resolution = {color_resolution}, depth_resolution = {depth_resolution}: " f"RealSense error: {error}" ) finally: if pipeline_started: pipeline.stop()
[docs] def main() -> int: """Scan the first connected RealSense device and print its stream profiles.""" context = rs.context() devices = context.query_devices() if len(devices) == 0: print("No Intel RealSense device was found.") return 1 device = devices[0] try: color_sensor = device.first_color_sensor() depth_sensor = device.first_depth_sensor() except RuntimeError as error: print(f"The selected device does not provide the required color and depth sensors: {error}") return 1 device_name = device.get_info(rs.camera_info.name) device_serial = device.get_info(rs.camera_info.serial_number) print(f"Device Name: {device_name}") print(f"Serial Number: {device_serial}") color_framerates, color_fovs = scan_profiles(color_sensor.get_stream_profiles()) depth_framerates, depth_fovs = scan_profiles(depth_sensor.get_stream_profiles()) print("Available color resolutions, framerates and FoV:") print_profile_info(color_framerates, color_fovs) print("Available depth resolutions, framerates and FoV:") print_profile_info(depth_framerates, depth_fovs) if not color_framerates or not depth_framerates: print("No compatible RGB8 color and Z16 depth profiles were found.") return 1 check_aligned_depth_resolutions(device_serial, color_framerates, depth_framerates) return 0
if __name__ == "__main__": raise SystemExit(main())