reachy2_sdk.media.camera

Reachy Camera module.

Define the RGB Camera of Reachy's head (Teleop) and the RGBD Camera of its torso (Depth). Provide access to the frames (color, depth, disparity) and the camera parameters.

  1"""Reachy Camera module.
  2
  3Define the RGB Camera of Reachy's head (Teleop) and the RGBD Camera of its torso (Depth).
  4Provide access to the frames (color, depth, disparity) and the camera parameters.
  5"""
  6
  7import logging
  8from enum import Enum
  9from typing import Optional, Tuple
 10
 11import cv2
 12import numpy as np
 13import numpy.typing as npt
 14from reachy2_sdk_api.video_pb2 import CameraFeatures, View, ViewRequest
 15from reachy2_sdk_api.video_pb2_grpc import VideoServiceStub
 16
 17from ..utils.utils import invert_affine_transformation_matrix
 18
 19
 20class CameraView(Enum):
 21    """Enumeration for different camera views.
 22
 23    The `CameraView` enum provides options for specifying the view from which
 24    to capture images or video frames. For monocular cameras, LEFT is used as default.
 25    """
 26
 27    LEFT = View.LEFT
 28    RIGHT = View.RIGHT
 29    DEPTH = View.DEPTH
 30
 31
 32class CameraType(Enum):
 33    """Camera names defined in pollen-vision."""
 34
 35    TELEOP = "teleop_head"
 36    DEPTH = "depth_camera"
 37
 38
 39class Camera:
 40    """Camera class represents an RGB camera on the robot.
 41
 42    The Camera class is primarily used for teleoperation cameras but can also be
 43    utilized for the RGB component of the RGB-D torso camera. It provides access
 44    to camera frames and parameters such as intrinsic, extrinsic matrices, and
 45    distortion coefficients. Additionally, it allows for converting pixel coordinates
 46    to world coordinates.
 47    """
 48
 49    def __init__(self, cam_info: CameraFeatures, video_stub: VideoServiceStub) -> None:
 50        """Initialize a Camera instance.
 51
 52        This constructor sets up a camera instance by storing the camera's
 53        information and gRPC video stub for accessing camera-related services.
 54
 55        Args:
 56            cam_info: An instance of `CameraFeatures` containing the camera's
 57                details, such as its name, capabilities, and settings.
 58            video_stub: A `VideoServiceStub` for making gRPC calls to the video
 59                service, enabling access to camera frames, parameters, and other
 60                camera-related functionality.
 61        """
 62        self._logger = logging.getLogger(__name__)
 63        self._cam_info = cam_info
 64        self._video_stub = video_stub
 65
 66    def get_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[npt.NDArray[np.uint8], int]]:
 67        """Retrieve an RGB frame from the camera.
 68
 69        Args:
 70            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
 71
 72        Returns:
 73            A tuple containing the frame as a NumPy array in OpenCV format and the timestamp in nanoseconds.
 74            Returns None if no frame is retrieved.
 75        """
 76        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
 77        if frame.data == b"":
 78            self._logger.warning("No frame retrieved")
 79            return None
 80        np_data = np.frombuffer(frame.data, np.uint8)
 81        img = cv2.imdecode(np_data, cv2.IMREAD_COLOR).astype(np.uint8)
 82        return img, frame.timestamp.ToNanoseconds()
 83
 84    def get_compressed_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[bytes, int]]:
 85        """Retrieve an RGB frame in a JPEG format from the camera.
 86
 87        Args:
 88            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
 89
 90        Returns:
 91            A bytes array containing the jpeg frame and the timestamp in nanoseconds.
 92            Returns None if no frame is retrieved.
 93        """
 94        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
 95        if frame.data == b"":
 96            self._logger.warning("No frame retrieved")
 97            return None
 98        return frame.data, frame.timestamp.ToNanoseconds()
 99
100    def get_parameters(
101        self, view: CameraView = CameraView.LEFT
102    ) -> Optional[
103        Tuple[int, int, str, npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64]]
104    ]:
105        """Retrieve camera parameters including intrinsic matrix.
106
107        Args:
108            view: The camera view for which parameters should be retrieved. Default is CameraView.LEFT.
109
110        Returns:
111            A tuple containing height, width, distortion model, distortion coefficients, intrinsic matrix,
112            rotation matrix, and projection matrix. Returns None if no parameters are retrieved.
113        """
114        params = self._video_stub.GetParameters(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
115        if params.K == []:
116            self._logger.warning("No parameter retrieved")
117            return None
118
119        D = np.array(params.D)
120        K = np.array(params.K).reshape((3, 3))
121        R = np.array(params.R).reshape((3, 3))
122        P = np.array(params.P).reshape((3, 4))
123
124        return params.height, params.width, params.distortion_model, D, K, R, P
125
126    def get_extrinsics(self, view: CameraView = CameraView.LEFT) -> Optional[npt.NDArray[np.float64]]:
127        """Retrieve the 4x4 extrinsic matrix of the camera.
128
129        Args:
130            view: The camera view for which the extrinsic matrix should be retrieved. Default is CameraView.LEFT.
131
132        Returns:
133            The extrinsic matrix as a NumPy array. Returns None if no matrix is retrieved.
134        """
135        res = self._video_stub.GetExtrinsics(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
136        if res.extrinsics is None:
137            self._logger.warning("No extrinsic matrix retrieved")
138            return None
139        return np.array(res.extrinsics.data).reshape((4, 4))
140
141    def pixel_to_world(
142        self, u: int, v: int, z_c: float = 1.0, view: CameraView = CameraView.LEFT
143    ) -> Optional[npt.NDArray[np.float64]]:
144        """Convert pixel coordinates to XYZ coordinate in Reachy coordinate system.
145
146        Args:
147            u: The x-coordinate (pixel) in the camera view (horizontal axis, left-to-right).
148            v: The y-coordinate (pixel) in the camera view (vertical axis, top-to-bottom).
149            z_c: The depth value in meters at the given pixel. Default is 1.0.
150            view: The camera view to use for the conversion. Default is CameraView.LEFT.
151
152        Returns:
153            A NumPy array containing the [X, Y, Z] world coordinates in meters. Returns None if the conversion fails.
154        """
155        params = self.get_parameters(view)
156
157        if params is None:
158            return None
159
160        height, width, distortion_model, D, K, R, P = params
161
162        if u < 0 or u > width:
163            self._logger.warning(f"u value should be between 0 and {width}")
164            return None
165        if v < 0 or v > height:
166            self._logger.warning(f"v value should be between 0 and {height}")
167            return None
168
169        T_cam_world = self.get_extrinsics(view)
170        if T_cam_world is None:
171            return None
172
173        T_world_cam = invert_affine_transformation_matrix(T_cam_world)
174
175        uv_homogeneous = np.array([u, v, 1])
176        camera_coords = np.linalg.inv(K) @ uv_homogeneous
177        camera_coords_homogeneous = np.array([camera_coords[0] * z_c, camera_coords[1] * z_c, z_c, 1])
178
179        world_coords_homogeneous = T_world_cam @ camera_coords_homogeneous
180
181        return np.array(world_coords_homogeneous[:3])
182
183    def __repr__(self) -> str:
184        """Clean representation of a RGB camera."""
185        if self._cam_info.name == CameraType.TELEOP.value:
186            name = "teleop"
187        elif self._cam_info.name == CameraType.DEPTH.value:
188            name = "depth"
189        else:
190            name = self._cam_info.name
191        return f"""<Camera name="{name}" stereo={self._cam_info.stereo}> """
192
193
194class DepthCamera(Camera):
195    """DepthCamera class represents the depth component of the RGB-D torso camera.
196
197    It provides access to depth frames and extends the functionality
198    of the Camera class, allowing users to retrieve depth information.
199    """
200
201    def get_depth_frame(self, view: CameraView = CameraView.DEPTH) -> Optional[Tuple[npt.NDArray[np.uint16], int]]:
202        """Retrieve a depth frame from the camera.
203
204        Args:
205            view: The camera view to retrieve the depth frame from. Default is CameraView.DEPTH.
206
207        Returns:
208            A tuple containing the depth frame as a NumPy array in 16-bit format and the timestamp in nanoseconds.
209            Returns None if no frame is retrieved.
210        """
211        frame = self._video_stub.GetDepth(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
212        if frame.data == b"":
213            self._logger.error("No frame retrieved")
214            return None
215
216        if frame.encoding != "16UC1":
217            self._logger.error("Depth is not encoded in 16bit")
218        np_data = np.frombuffer(frame.data, np.uint16)
219        np_data = np_data.reshape((frame.height, frame.width))
220
221        return np_data, frame.timestamp.ToNanoseconds()
class CameraView(enum.Enum):
21class CameraView(Enum):
22    """Enumeration for different camera views.
23
24    The `CameraView` enum provides options for specifying the view from which
25    to capture images or video frames. For monocular cameras, LEFT is used as default.
26    """
27
28    LEFT = View.LEFT
29    RIGHT = View.RIGHT
30    DEPTH = View.DEPTH

Enumeration for different camera views.

The CameraView enum provides options for specifying the view from which to capture images or video frames. For monocular cameras, LEFT is used as default.

LEFT = <CameraView.LEFT: 0>
RIGHT = <CameraView.RIGHT: 1>
DEPTH = <CameraView.DEPTH: 2>
Inherited Members
enum.Enum
name
value
class CameraType(enum.Enum):
33class CameraType(Enum):
34    """Camera names defined in pollen-vision."""
35
36    TELEOP = "teleop_head"
37    DEPTH = "depth_camera"

Camera names defined in pollen-vision.

TELEOP = <CameraType.TELEOP: 'teleop_head'>
DEPTH = <CameraType.DEPTH: 'depth_camera'>
Inherited Members
enum.Enum
name
value
class Camera:
 40class Camera:
 41    """Camera class represents an RGB camera on the robot.
 42
 43    The Camera class is primarily used for teleoperation cameras but can also be
 44    utilized for the RGB component of the RGB-D torso camera. It provides access
 45    to camera frames and parameters such as intrinsic, extrinsic matrices, and
 46    distortion coefficients. Additionally, it allows for converting pixel coordinates
 47    to world coordinates.
 48    """
 49
 50    def __init__(self, cam_info: CameraFeatures, video_stub: VideoServiceStub) -> None:
 51        """Initialize a Camera instance.
 52
 53        This constructor sets up a camera instance by storing the camera's
 54        information and gRPC video stub for accessing camera-related services.
 55
 56        Args:
 57            cam_info: An instance of `CameraFeatures` containing the camera's
 58                details, such as its name, capabilities, and settings.
 59            video_stub: A `VideoServiceStub` for making gRPC calls to the video
 60                service, enabling access to camera frames, parameters, and other
 61                camera-related functionality.
 62        """
 63        self._logger = logging.getLogger(__name__)
 64        self._cam_info = cam_info
 65        self._video_stub = video_stub
 66
 67    def get_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[npt.NDArray[np.uint8], int]]:
 68        """Retrieve an RGB frame from the camera.
 69
 70        Args:
 71            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
 72
 73        Returns:
 74            A tuple containing the frame as a NumPy array in OpenCV format and the timestamp in nanoseconds.
 75            Returns None if no frame is retrieved.
 76        """
 77        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
 78        if frame.data == b"":
 79            self._logger.warning("No frame retrieved")
 80            return None
 81        np_data = np.frombuffer(frame.data, np.uint8)
 82        img = cv2.imdecode(np_data, cv2.IMREAD_COLOR).astype(np.uint8)
 83        return img, frame.timestamp.ToNanoseconds()
 84
 85    def get_compressed_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[bytes, int]]:
 86        """Retrieve an RGB frame in a JPEG format from the camera.
 87
 88        Args:
 89            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
 90
 91        Returns:
 92            A bytes array containing the jpeg frame and the timestamp in nanoseconds.
 93            Returns None if no frame is retrieved.
 94        """
 95        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
 96        if frame.data == b"":
 97            self._logger.warning("No frame retrieved")
 98            return None
 99        return frame.data, frame.timestamp.ToNanoseconds()
100
101    def get_parameters(
102        self, view: CameraView = CameraView.LEFT
103    ) -> Optional[
104        Tuple[int, int, str, npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64]]
105    ]:
106        """Retrieve camera parameters including intrinsic matrix.
107
108        Args:
109            view: The camera view for which parameters should be retrieved. Default is CameraView.LEFT.
110
111        Returns:
112            A tuple containing height, width, distortion model, distortion coefficients, intrinsic matrix,
113            rotation matrix, and projection matrix. Returns None if no parameters are retrieved.
114        """
115        params = self._video_stub.GetParameters(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
116        if params.K == []:
117            self._logger.warning("No parameter retrieved")
118            return None
119
120        D = np.array(params.D)
121        K = np.array(params.K).reshape((3, 3))
122        R = np.array(params.R).reshape((3, 3))
123        P = np.array(params.P).reshape((3, 4))
124
125        return params.height, params.width, params.distortion_model, D, K, R, P
126
127    def get_extrinsics(self, view: CameraView = CameraView.LEFT) -> Optional[npt.NDArray[np.float64]]:
128        """Retrieve the 4x4 extrinsic matrix of the camera.
129
130        Args:
131            view: The camera view for which the extrinsic matrix should be retrieved. Default is CameraView.LEFT.
132
133        Returns:
134            The extrinsic matrix as a NumPy array. Returns None if no matrix is retrieved.
135        """
136        res = self._video_stub.GetExtrinsics(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
137        if res.extrinsics is None:
138            self._logger.warning("No extrinsic matrix retrieved")
139            return None
140        return np.array(res.extrinsics.data).reshape((4, 4))
141
142    def pixel_to_world(
143        self, u: int, v: int, z_c: float = 1.0, view: CameraView = CameraView.LEFT
144    ) -> Optional[npt.NDArray[np.float64]]:
145        """Convert pixel coordinates to XYZ coordinate in Reachy coordinate system.
146
147        Args:
148            u: The x-coordinate (pixel) in the camera view (horizontal axis, left-to-right).
149            v: The y-coordinate (pixel) in the camera view (vertical axis, top-to-bottom).
150            z_c: The depth value in meters at the given pixel. Default is 1.0.
151            view: The camera view to use for the conversion. Default is CameraView.LEFT.
152
153        Returns:
154            A NumPy array containing the [X, Y, Z] world coordinates in meters. Returns None if the conversion fails.
155        """
156        params = self.get_parameters(view)
157
158        if params is None:
159            return None
160
161        height, width, distortion_model, D, K, R, P = params
162
163        if u < 0 or u > width:
164            self._logger.warning(f"u value should be between 0 and {width}")
165            return None
166        if v < 0 or v > height:
167            self._logger.warning(f"v value should be between 0 and {height}")
168            return None
169
170        T_cam_world = self.get_extrinsics(view)
171        if T_cam_world is None:
172            return None
173
174        T_world_cam = invert_affine_transformation_matrix(T_cam_world)
175
176        uv_homogeneous = np.array([u, v, 1])
177        camera_coords = np.linalg.inv(K) @ uv_homogeneous
178        camera_coords_homogeneous = np.array([camera_coords[0] * z_c, camera_coords[1] * z_c, z_c, 1])
179
180        world_coords_homogeneous = T_world_cam @ camera_coords_homogeneous
181
182        return np.array(world_coords_homogeneous[:3])
183
184    def __repr__(self) -> str:
185        """Clean representation of a RGB camera."""
186        if self._cam_info.name == CameraType.TELEOP.value:
187            name = "teleop"
188        elif self._cam_info.name == CameraType.DEPTH.value:
189            name = "depth"
190        else:
191            name = self._cam_info.name
192        return f"""<Camera name="{name}" stereo={self._cam_info.stereo}> """

Camera class represents an RGB camera on the robot.

The Camera class is primarily used for teleoperation cameras but can also be utilized for the RGB component of the RGB-D torso camera. It provides access to camera frames and parameters such as intrinsic, extrinsic matrices, and distortion coefficients. Additionally, it allows for converting pixel coordinates to world coordinates.

Camera( cam_info: video_pb2.CameraFeatures, video_stub: reachy2_sdk_api.video_pb2_grpc.VideoServiceStub)
50    def __init__(self, cam_info: CameraFeatures, video_stub: VideoServiceStub) -> None:
51        """Initialize a Camera instance.
52
53        This constructor sets up a camera instance by storing the camera's
54        information and gRPC video stub for accessing camera-related services.
55
56        Args:
57            cam_info: An instance of `CameraFeatures` containing the camera's
58                details, such as its name, capabilities, and settings.
59            video_stub: A `VideoServiceStub` for making gRPC calls to the video
60                service, enabling access to camera frames, parameters, and other
61                camera-related functionality.
62        """
63        self._logger = logging.getLogger(__name__)
64        self._cam_info = cam_info
65        self._video_stub = video_stub

Initialize a Camera instance.

This constructor sets up a camera instance by storing the camera's information and gRPC video stub for accessing camera-related services.

Arguments:
  • cam_info: An instance of CameraFeatures containing the camera's details, such as its name, capabilities, and settings.
  • video_stub: A VideoServiceStub for making gRPC calls to the video service, enabling access to camera frames, parameters, and other camera-related functionality.
def get_frame( self, view: CameraView = <CameraView.LEFT: 0>) -> Optional[Tuple[numpy.ndarray[Any, numpy.dtype[numpy.uint8]], int]]:
67    def get_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[npt.NDArray[np.uint8], int]]:
68        """Retrieve an RGB frame from the camera.
69
70        Args:
71            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
72
73        Returns:
74            A tuple containing the frame as a NumPy array in OpenCV format and the timestamp in nanoseconds.
75            Returns None if no frame is retrieved.
76        """
77        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
78        if frame.data == b"":
79            self._logger.warning("No frame retrieved")
80            return None
81        np_data = np.frombuffer(frame.data, np.uint8)
82        img = cv2.imdecode(np_data, cv2.IMREAD_COLOR).astype(np.uint8)
83        return img, frame.timestamp.ToNanoseconds()

Retrieve an RGB frame from the camera.

Arguments:
  • view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
Returns:

A tuple containing the frame as a NumPy array in OpenCV format and the timestamp in nanoseconds. Returns None if no frame is retrieved.

def get_compressed_frame( self, view: CameraView = <CameraView.LEFT: 0>) -> Optional[Tuple[bytes, int]]:
85    def get_compressed_frame(self, view: CameraView = CameraView.LEFT) -> Optional[Tuple[bytes, int]]:
86        """Retrieve an RGB frame in a JPEG format from the camera.
87
88        Args:
89            view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
90
91        Returns:
92            A bytes array containing the jpeg frame and the timestamp in nanoseconds.
93            Returns None if no frame is retrieved.
94        """
95        frame = self._video_stub.GetFrame(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
96        if frame.data == b"":
97            self._logger.warning("No frame retrieved")
98            return None
99        return frame.data, frame.timestamp.ToNanoseconds()

Retrieve an RGB frame in a JPEG format from the camera.

Arguments:
  • view: The camera view to retrieve the frame from. Default is CameraView.LEFT.
Returns:

A bytes array containing the jpeg frame and the timestamp in nanoseconds. Returns None if no frame is retrieved.

def get_parameters( self, view: CameraView = <CameraView.LEFT: 0>) -> Optional[Tuple[int, int, str, numpy.ndarray[Any, numpy.dtype[numpy.float64]], numpy.ndarray[Any, numpy.dtype[numpy.float64]], numpy.ndarray[Any, numpy.dtype[numpy.float64]], numpy.ndarray[Any, numpy.dtype[numpy.float64]]]]:
101    def get_parameters(
102        self, view: CameraView = CameraView.LEFT
103    ) -> Optional[
104        Tuple[int, int, str, npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64]]
105    ]:
106        """Retrieve camera parameters including intrinsic matrix.
107
108        Args:
109            view: The camera view for which parameters should be retrieved. Default is CameraView.LEFT.
110
111        Returns:
112            A tuple containing height, width, distortion model, distortion coefficients, intrinsic matrix,
113            rotation matrix, and projection matrix. Returns None if no parameters are retrieved.
114        """
115        params = self._video_stub.GetParameters(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
116        if params.K == []:
117            self._logger.warning("No parameter retrieved")
118            return None
119
120        D = np.array(params.D)
121        K = np.array(params.K).reshape((3, 3))
122        R = np.array(params.R).reshape((3, 3))
123        P = np.array(params.P).reshape((3, 4))
124
125        return params.height, params.width, params.distortion_model, D, K, R, P

Retrieve camera parameters including intrinsic matrix.

Arguments:
  • view: The camera view for which parameters should be retrieved. Default is CameraView.LEFT.
Returns:

A tuple containing height, width, distortion model, distortion coefficients, intrinsic matrix, rotation matrix, and projection matrix. Returns None if no parameters are retrieved.

def get_extrinsics( self, view: CameraView = <CameraView.LEFT: 0>) -> Optional[numpy.ndarray[Any, numpy.dtype[numpy.float64]]]:
127    def get_extrinsics(self, view: CameraView = CameraView.LEFT) -> Optional[npt.NDArray[np.float64]]:
128        """Retrieve the 4x4 extrinsic matrix of the camera.
129
130        Args:
131            view: The camera view for which the extrinsic matrix should be retrieved. Default is CameraView.LEFT.
132
133        Returns:
134            The extrinsic matrix as a NumPy array. Returns None if no matrix is retrieved.
135        """
136        res = self._video_stub.GetExtrinsics(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
137        if res.extrinsics is None:
138            self._logger.warning("No extrinsic matrix retrieved")
139            return None
140        return np.array(res.extrinsics.data).reshape((4, 4))

Retrieve the 4x4 extrinsic matrix of the camera.

Arguments:
  • view: The camera view for which the extrinsic matrix should be retrieved. Default is CameraView.LEFT.
Returns:

The extrinsic matrix as a NumPy array. Returns None if no matrix is retrieved.

def pixel_to_world( self, u: int, v: int, z_c: float = 1.0, view: CameraView = <CameraView.LEFT: 0>) -> Optional[numpy.ndarray[Any, numpy.dtype[numpy.float64]]]:
142    def pixel_to_world(
143        self, u: int, v: int, z_c: float = 1.0, view: CameraView = CameraView.LEFT
144    ) -> Optional[npt.NDArray[np.float64]]:
145        """Convert pixel coordinates to XYZ coordinate in Reachy coordinate system.
146
147        Args:
148            u: The x-coordinate (pixel) in the camera view (horizontal axis, left-to-right).
149            v: The y-coordinate (pixel) in the camera view (vertical axis, top-to-bottom).
150            z_c: The depth value in meters at the given pixel. Default is 1.0.
151            view: The camera view to use for the conversion. Default is CameraView.LEFT.
152
153        Returns:
154            A NumPy array containing the [X, Y, Z] world coordinates in meters. Returns None if the conversion fails.
155        """
156        params = self.get_parameters(view)
157
158        if params is None:
159            return None
160
161        height, width, distortion_model, D, K, R, P = params
162
163        if u < 0 or u > width:
164            self._logger.warning(f"u value should be between 0 and {width}")
165            return None
166        if v < 0 or v > height:
167            self._logger.warning(f"v value should be between 0 and {height}")
168            return None
169
170        T_cam_world = self.get_extrinsics(view)
171        if T_cam_world is None:
172            return None
173
174        T_world_cam = invert_affine_transformation_matrix(T_cam_world)
175
176        uv_homogeneous = np.array([u, v, 1])
177        camera_coords = np.linalg.inv(K) @ uv_homogeneous
178        camera_coords_homogeneous = np.array([camera_coords[0] * z_c, camera_coords[1] * z_c, z_c, 1])
179
180        world_coords_homogeneous = T_world_cam @ camera_coords_homogeneous
181
182        return np.array(world_coords_homogeneous[:3])

Convert pixel coordinates to XYZ coordinate in Reachy coordinate system.

Arguments:
  • u: The x-coordinate (pixel) in the camera view (horizontal axis, left-to-right).
  • v: The y-coordinate (pixel) in the camera view (vertical axis, top-to-bottom).
  • z_c: The depth value in meters at the given pixel. Default is 1.0.
  • view: The camera view to use for the conversion. Default is CameraView.LEFT.
Returns:

A NumPy array containing the [X, Y, Z] world coordinates in meters. Returns None if the conversion fails.

class DepthCamera(Camera):
195class DepthCamera(Camera):
196    """DepthCamera class represents the depth component of the RGB-D torso camera.
197
198    It provides access to depth frames and extends the functionality
199    of the Camera class, allowing users to retrieve depth information.
200    """
201
202    def get_depth_frame(self, view: CameraView = CameraView.DEPTH) -> Optional[Tuple[npt.NDArray[np.uint16], int]]:
203        """Retrieve a depth frame from the camera.
204
205        Args:
206            view: The camera view to retrieve the depth frame from. Default is CameraView.DEPTH.
207
208        Returns:
209            A tuple containing the depth frame as a NumPy array in 16-bit format and the timestamp in nanoseconds.
210            Returns None if no frame is retrieved.
211        """
212        frame = self._video_stub.GetDepth(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
213        if frame.data == b"":
214            self._logger.error("No frame retrieved")
215            return None
216
217        if frame.encoding != "16UC1":
218            self._logger.error("Depth is not encoded in 16bit")
219        np_data = np.frombuffer(frame.data, np.uint16)
220        np_data = np_data.reshape((frame.height, frame.width))
221
222        return np_data, frame.timestamp.ToNanoseconds()

DepthCamera class represents the depth component of the RGB-D torso camera.

It provides access to depth frames and extends the functionality of the Camera class, allowing users to retrieve depth information.

def get_depth_frame( self, view: CameraView = <CameraView.DEPTH: 2>) -> Optional[Tuple[numpy.ndarray[Any, numpy.dtype[numpy.uint16]], int]]:
202    def get_depth_frame(self, view: CameraView = CameraView.DEPTH) -> Optional[Tuple[npt.NDArray[np.uint16], int]]:
203        """Retrieve a depth frame from the camera.
204
205        Args:
206            view: The camera view to retrieve the depth frame from. Default is CameraView.DEPTH.
207
208        Returns:
209            A tuple containing the depth frame as a NumPy array in 16-bit format and the timestamp in nanoseconds.
210            Returns None if no frame is retrieved.
211        """
212        frame = self._video_stub.GetDepth(request=ViewRequest(camera_feat=self._cam_info, view=view.value))
213        if frame.data == b"":
214            self._logger.error("No frame retrieved")
215            return None
216
217        if frame.encoding != "16UC1":
218            self._logger.error("Depth is not encoded in 16bit")
219        np_data = np.frombuffer(frame.data, np.uint16)
220        np_data = np_data.reshape((frame.height, frame.width))
221
222        return np_data, frame.timestamp.ToNanoseconds()

Retrieve a depth frame from the camera.

Arguments:
  • view: The camera view to retrieve the depth frame from. Default is CameraView.DEPTH.
Returns:

A tuple containing the depth frame as a NumPy array in 16-bit format and the timestamp in nanoseconds. Returns None if no frame is retrieved.