visiongraph.input.BaseDepthCamera

  1from abc import ABC, abstractmethod
  2from argparse import ArgumentParser, Namespace, ArgumentError
  3from typing import Tuple, Optional
  4
  5import cv2
  6import numpy as np
  7
  8from visiongraph.input.BaseCamera import BaseCamera
  9from visiongraph.input.BaseDepthInput import BaseDepthInput
 10from visiongraph.model.CameraStreamType import CameraStreamType
 11from visiongraph.util import MathUtils
 12
 13
 14class BaseDepthCamera(BaseCamera, BaseDepthInput, ABC):
 15    """
 16    Abstract base class for depth cameras that handle both color and depth input streams.
 17    """
 18
 19    def __init__(self):
 20        """
 21        Initializes the BaseDepthCamera with default settings.
 22        """
 23        super().__init__()
 24        self.use_infrared = False
 25
 26    def configure(self, args: Namespace):
 27        """
 28        Configures the camera settings based on command line arguments.
 29
 30        :param args: The command line arguments namespace.
 31        """
 32        super().configure(args)
 33        self.use_infrared = args.infrared
 34
 35    def _calculate_depth_coordinates(self, x: float, y: float, width: int, height: int) -> Tuple[int, int]:
 36        """
 37        Calculates depth coordinates from given normalized coordinates.
 38
 39        :param x: The x coordinate (normalized).
 40        :param y: The y coordinate (normalized).
 41        :param width: The width of the image.
 42        :param height: The height of the image.
 43
 44        :return: The calculated pixel coordinates (ix, iy).
 45        """
 46        x, y = MathUtils.transform_coordinates(x, y, self.rotate, self.flip)
 47
 48        if self.crop is not None:
 49            norm_crop = self.crop.scale(1.0 / width, 1.0 / height)
 50            x = MathUtils.map_value(x, 0.0, 1.0, norm_crop.x_min, norm_crop.x_max)
 51            y = MathUtils.map_value(y, 0.0, 1.0, norm_crop.y_min, norm_crop.y_max)
 52
 53        ix, iy = width * x, height * y
 54
 55        ix = round(MathUtils.constrain(ix, upper=width - 1))
 56        iy = round(MathUtils.constrain(iy, upper=height - 1))
 57
 58        return ix, iy
 59
 60    @staticmethod
 61    def _colorize(
 62        image: np.ndarray,
 63        clipping_range: Tuple[Optional[int], Optional[int]] = (None, None),
 64        colormap: Optional[int] = None,
 65    ) -> np.ndarray:
 66        """
 67        Colorizes a depth image within a specified clipping range.
 68
 69        :param image: The image to colorize.
 70        :param clipping_range: The clipping range for normalization.
 71        :param colormap: The OpenCV colormap to apply.
 72
 73        :return: The colorized image.
 74        """
 75        if clipping_range[0] is not None and clipping_range[1] is not None:
 76            low, high = clipping_range
 77            delta = high - low
 78
 79            img = image.clip(low, high)
 80            img = (((img - low) / delta) * 255).astype(np.uint8)
 81        else:
 82            img = image
 83            img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
 84
 85        if colormap is not None:
 86            img = cv2.applyColorMap(img, colormap)
 87        return img
 88
 89    @abstractmethod
 90    def pre_process_image(
 91        self, image: np.ndarray, stream_type: CameraStreamType = CameraStreamType.Color
 92    ) -> Optional[np.ndarray]:
 93        """
 94        Pre-processes the input image based on the stream type.
 95
 96        :param image: The image to be pre-processed.
 97        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
 98
 99        :return: The pre-processed image or None if unprocessable.
100        """
101        return image
102
103    @abstractmethod
104    def get_raw_image(self, stream_type: CameraStreamType = CameraStreamType.Color) -> Optional[np.ndarray]:
105        """
106        Retrieves the raw image from the camera based on the stream type.
107
108        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
109
110        :return: The raw image or None if unavailable.
111        """
112        pass
113
114    def get_image(
115        self,
116        stream_type: CameraStreamType = CameraStreamType.Color,
117        pre_processed: bool = True,
118        post_processed: bool = True,
119    ) -> Optional[np.ndarray]:
120        """
121        Retrieves and processes the image from the camera stream.
122
123        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
124        :param pre_processed: Whether to pre-process the image (default is True).
125        :param post_processed: Whether to post-process the image (default is True).
126
127        :return: The processed image or None if unavailable.
128        """
129        frame = self.get_raw_image(stream_type)
130
131        if frame is None:
132            return None
133
134        # apply camera pre-processing
135        if pre_processed:
136            frame = self.pre_process_image(frame, stream_type)
137
138        # apply base camera post-processing
139        if post_processed:
140            _, frame = self._post_process(0, frame)
141            return frame
142
143        return frame
144
145    @property
146    def color_image(self) -> Optional[np.ndarray]:
147        """
148        Returns the processed color image.
149
150        :return: The processed color image or None if unavailable.
151        """
152        return self.get_image(CameraStreamType.Color, True, True)
153
154    @property
155    def depth_image(self) -> Optional[np.ndarray]:
156        """
157        Returns the processed depth image.
158
159        :return: The processed depth image or None if unavailable.
160        """
161        return self.get_image(CameraStreamType.Depth, True, True)
162
163    @property
164    def infrared_image(self) -> Optional[np.ndarray]:
165        """
166        Returns the processed infrared image.
167
168        :return: The processed infrared image or None if unavailable.
169        """
170        return self.get_image(CameraStreamType.Infrared, True, True)
171
172    @property
173    def raw_color_image(self) -> Optional[np.ndarray]:
174        """
175        Returns the raw color image from the camera.
176
177        :return: The raw color image or None if unavailable.
178        """
179        return self.get_raw_image(CameraStreamType.Color)
180
181    @property
182    def raw_depth_image(self) -> Optional[np.ndarray]:
183        """
184        Returns the raw depth image from the camera.
185
186        :return: The raw depth image or None if unavailable.
187        """
188        return self.get_raw_image(CameraStreamType.Depth)
189
190    @property
191    def raw_infrared_image(self) -> Optional[np.ndarray]:
192        """
193        Returns the raw infrared image from the camera.
194
195        :return: The raw infrared image or None if unavailable.
196        """
197        return self.get_raw_image(CameraStreamType.Infrared)
198
199    @staticmethod
200    def add_params(parser: ArgumentParser):
201        """
202        Adds camera-specific parameters to the argument parser.
203
204        :param parser: The argument parser instance.
205        """
206        super(BaseDepthCamera, BaseDepthCamera).add_params(parser)
207        BaseDepthInput.add_params(parser)
208
209        try:
210            parser.add_argument("-ir", "--infrared", action="store_true", help="Use infrared as input stream.")
211        except ArgumentError as ex:
212            if ex.message.startswith("conflicting"):
213                return
214            raise ex
215
216    @property
217    def is_playback(self) -> bool:
218        """
219        Indicates whether the camera is in playback mode.
220
221        :return: False since this is a real-time camera.
222        """
223        return False
class BaseDepthCamera(visiongraph.GraphNode.GraphNode[NoneType, numpy.ndarray], abc.ABC):
 15class BaseDepthCamera(BaseCamera, BaseDepthInput, ABC):
 16    """
 17    Abstract base class for depth cameras that handle both color and depth input streams.
 18    """
 19
 20    def __init__(self):
 21        """
 22        Initializes the BaseDepthCamera with default settings.
 23        """
 24        super().__init__()
 25        self.use_infrared = False
 26
 27    def configure(self, args: Namespace):
 28        """
 29        Configures the camera settings based on command line arguments.
 30
 31        :param args: The command line arguments namespace.
 32        """
 33        super().configure(args)
 34        self.use_infrared = args.infrared
 35
 36    def _calculate_depth_coordinates(self, x: float, y: float, width: int, height: int) -> Tuple[int, int]:
 37        """
 38        Calculates depth coordinates from given normalized coordinates.
 39
 40        :param x: The x coordinate (normalized).
 41        :param y: The y coordinate (normalized).
 42        :param width: The width of the image.
 43        :param height: The height of the image.
 44
 45        :return: The calculated pixel coordinates (ix, iy).
 46        """
 47        x, y = MathUtils.transform_coordinates(x, y, self.rotate, self.flip)
 48
 49        if self.crop is not None:
 50            norm_crop = self.crop.scale(1.0 / width, 1.0 / height)
 51            x = MathUtils.map_value(x, 0.0, 1.0, norm_crop.x_min, norm_crop.x_max)
 52            y = MathUtils.map_value(y, 0.0, 1.0, norm_crop.y_min, norm_crop.y_max)
 53
 54        ix, iy = width * x, height * y
 55
 56        ix = round(MathUtils.constrain(ix, upper=width - 1))
 57        iy = round(MathUtils.constrain(iy, upper=height - 1))
 58
 59        return ix, iy
 60
 61    @staticmethod
 62    def _colorize(
 63        image: np.ndarray,
 64        clipping_range: Tuple[Optional[int], Optional[int]] = (None, None),
 65        colormap: Optional[int] = None,
 66    ) -> np.ndarray:
 67        """
 68        Colorizes a depth image within a specified clipping range.
 69
 70        :param image: The image to colorize.
 71        :param clipping_range: The clipping range for normalization.
 72        :param colormap: The OpenCV colormap to apply.
 73
 74        :return: The colorized image.
 75        """
 76        if clipping_range[0] is not None and clipping_range[1] is not None:
 77            low, high = clipping_range
 78            delta = high - low
 79
 80            img = image.clip(low, high)
 81            img = (((img - low) / delta) * 255).astype(np.uint8)
 82        else:
 83            img = image
 84            img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
 85
 86        if colormap is not None:
 87            img = cv2.applyColorMap(img, colormap)
 88        return img
 89
 90    @abstractmethod
 91    def pre_process_image(
 92        self, image: np.ndarray, stream_type: CameraStreamType = CameraStreamType.Color
 93    ) -> Optional[np.ndarray]:
 94        """
 95        Pre-processes the input image based on the stream type.
 96
 97        :param image: The image to be pre-processed.
 98        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
 99
100        :return: The pre-processed image or None if unprocessable.
101        """
102        return image
103
104    @abstractmethod
105    def get_raw_image(self, stream_type: CameraStreamType = CameraStreamType.Color) -> Optional[np.ndarray]:
106        """
107        Retrieves the raw image from the camera based on the stream type.
108
109        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
110
111        :return: The raw image or None if unavailable.
112        """
113        pass
114
115    def get_image(
116        self,
117        stream_type: CameraStreamType = CameraStreamType.Color,
118        pre_processed: bool = True,
119        post_processed: bool = True,
120    ) -> Optional[np.ndarray]:
121        """
122        Retrieves and processes the image from the camera stream.
123
124        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
125        :param pre_processed: Whether to pre-process the image (default is True).
126        :param post_processed: Whether to post-process the image (default is True).
127
128        :return: The processed image or None if unavailable.
129        """
130        frame = self.get_raw_image(stream_type)
131
132        if frame is None:
133            return None
134
135        # apply camera pre-processing
136        if pre_processed:
137            frame = self.pre_process_image(frame, stream_type)
138
139        # apply base camera post-processing
140        if post_processed:
141            _, frame = self._post_process(0, frame)
142            return frame
143
144        return frame
145
146    @property
147    def color_image(self) -> Optional[np.ndarray]:
148        """
149        Returns the processed color image.
150
151        :return: The processed color image or None if unavailable.
152        """
153        return self.get_image(CameraStreamType.Color, True, True)
154
155    @property
156    def depth_image(self) -> Optional[np.ndarray]:
157        """
158        Returns the processed depth image.
159
160        :return: The processed depth image or None if unavailable.
161        """
162        return self.get_image(CameraStreamType.Depth, True, True)
163
164    @property
165    def infrared_image(self) -> Optional[np.ndarray]:
166        """
167        Returns the processed infrared image.
168
169        :return: The processed infrared image or None if unavailable.
170        """
171        return self.get_image(CameraStreamType.Infrared, True, True)
172
173    @property
174    def raw_color_image(self) -> Optional[np.ndarray]:
175        """
176        Returns the raw color image from the camera.
177
178        :return: The raw color image or None if unavailable.
179        """
180        return self.get_raw_image(CameraStreamType.Color)
181
182    @property
183    def raw_depth_image(self) -> Optional[np.ndarray]:
184        """
185        Returns the raw depth image from the camera.
186
187        :return: The raw depth image or None if unavailable.
188        """
189        return self.get_raw_image(CameraStreamType.Depth)
190
191    @property
192    def raw_infrared_image(self) -> Optional[np.ndarray]:
193        """
194        Returns the raw infrared image from the camera.
195
196        :return: The raw infrared image or None if unavailable.
197        """
198        return self.get_raw_image(CameraStreamType.Infrared)
199
200    @staticmethod
201    def add_params(parser: ArgumentParser):
202        """
203        Adds camera-specific parameters to the argument parser.
204
205        :param parser: The argument parser instance.
206        """
207        super(BaseDepthCamera, BaseDepthCamera).add_params(parser)
208        BaseDepthInput.add_params(parser)
209
210        try:
211            parser.add_argument("-ir", "--infrared", action="store_true", help="Use infrared as input stream.")
212        except ArgumentError as ex:
213            if ex.message.startswith("conflicting"):
214                return
215            raise ex
216
217    @property
218    def is_playback(self) -> bool:
219        """
220        Indicates whether the camera is in playback mode.
221
222        :return: False since this is a real-time camera.
223        """
224        return False

Abstract base class for depth cameras that handle both color and depth input streams.

BaseDepthCamera()
20    def __init__(self):
21        """
22        Initializes the BaseDepthCamera with default settings.
23        """
24        super().__init__()
25        self.use_infrared = False

Initializes the BaseDepthCamera with default settings.

use_infrared
def configure(self, args: argparse.Namespace):
27    def configure(self, args: Namespace):
28        """
29        Configures the camera settings based on command line arguments.
30
31        :param args: The command line arguments namespace.
32        """
33        super().configure(args)
34        self.use_infrared = args.infrared

Configures the camera settings based on command line arguments.

Parameters
  • args: The command line arguments namespace.
@abstractmethod
def pre_process_image( self, image: numpy.ndarray, stream_type: CameraStreamType = <CameraStreamType.Color: (0,)>) -> Optional[numpy.ndarray]:
 90    @abstractmethod
 91    def pre_process_image(
 92        self, image: np.ndarray, stream_type: CameraStreamType = CameraStreamType.Color
 93    ) -> Optional[np.ndarray]:
 94        """
 95        Pre-processes the input image based on the stream type.
 96
 97        :param image: The image to be pre-processed.
 98        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
 99
100        :return: The pre-processed image or None if unprocessable.
101        """
102        return image

Pre-processes the input image based on the stream type.

Parameters
  • image: The image to be pre-processed.
  • stream_type: The type of the camera stream (default is CameraStreamType.Color).
Returns

The pre-processed image or None if unprocessable.

@abstractmethod
def get_raw_image( self, stream_type: CameraStreamType = <CameraStreamType.Color: (0,)>) -> Optional[numpy.ndarray]:
104    @abstractmethod
105    def get_raw_image(self, stream_type: CameraStreamType = CameraStreamType.Color) -> Optional[np.ndarray]:
106        """
107        Retrieves the raw image from the camera based on the stream type.
108
109        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
110
111        :return: The raw image or None if unavailable.
112        """
113        pass

Retrieves the raw image from the camera based on the stream type.

Parameters
  • stream_type: The type of the camera stream (default is CameraStreamType.Color).
Returns

The raw image or None if unavailable.

def get_image( self, stream_type: CameraStreamType = <CameraStreamType.Color: (0,)>, pre_processed: bool = True, post_processed: bool = True) -> Optional[numpy.ndarray]:
115    def get_image(
116        self,
117        stream_type: CameraStreamType = CameraStreamType.Color,
118        pre_processed: bool = True,
119        post_processed: bool = True,
120    ) -> Optional[np.ndarray]:
121        """
122        Retrieves and processes the image from the camera stream.
123
124        :param stream_type: The type of the camera stream (default is CameraStreamType.Color).
125        :param pre_processed: Whether to pre-process the image (default is True).
126        :param post_processed: Whether to post-process the image (default is True).
127
128        :return: The processed image or None if unavailable.
129        """
130        frame = self.get_raw_image(stream_type)
131
132        if frame is None:
133            return None
134
135        # apply camera pre-processing
136        if pre_processed:
137            frame = self.pre_process_image(frame, stream_type)
138
139        # apply base camera post-processing
140        if post_processed:
141            _, frame = self._post_process(0, frame)
142            return frame
143
144        return frame

Retrieves and processes the image from the camera stream.

Parameters
  • stream_type: The type of the camera stream (default is CameraStreamType.Color).
  • pre_processed: Whether to pre-process the image (default is True).
  • post_processed: Whether to post-process the image (default is True).
Returns

The processed image or None if unavailable.

color_image: Optional[numpy.ndarray]
146    @property
147    def color_image(self) -> Optional[np.ndarray]:
148        """
149        Returns the processed color image.
150
151        :return: The processed color image or None if unavailable.
152        """
153        return self.get_image(CameraStreamType.Color, True, True)

Returns the processed color image.

Returns

The processed color image or None if unavailable.

depth_image: Optional[numpy.ndarray]
155    @property
156    def depth_image(self) -> Optional[np.ndarray]:
157        """
158        Returns the processed depth image.
159
160        :return: The processed depth image or None if unavailable.
161        """
162        return self.get_image(CameraStreamType.Depth, True, True)

Returns the processed depth image.

Returns

The processed depth image or None if unavailable.

infrared_image: Optional[numpy.ndarray]
164    @property
165    def infrared_image(self) -> Optional[np.ndarray]:
166        """
167        Returns the processed infrared image.
168
169        :return: The processed infrared image or None if unavailable.
170        """
171        return self.get_image(CameraStreamType.Infrared, True, True)

Returns the processed infrared image.

Returns

The processed infrared image or None if unavailable.

raw_color_image: Optional[numpy.ndarray]
173    @property
174    def raw_color_image(self) -> Optional[np.ndarray]:
175        """
176        Returns the raw color image from the camera.
177
178        :return: The raw color image or None if unavailable.
179        """
180        return self.get_raw_image(CameraStreamType.Color)

Returns the raw color image from the camera.

Returns

The raw color image or None if unavailable.

raw_depth_image: Optional[numpy.ndarray]
182    @property
183    def raw_depth_image(self) -> Optional[np.ndarray]:
184        """
185        Returns the raw depth image from the camera.
186
187        :return: The raw depth image or None if unavailable.
188        """
189        return self.get_raw_image(CameraStreamType.Depth)

Returns the raw depth image from the camera.

Returns

The raw depth image or None if unavailable.

raw_infrared_image: Optional[numpy.ndarray]
191    @property
192    def raw_infrared_image(self) -> Optional[np.ndarray]:
193        """
194        Returns the raw infrared image from the camera.
195
196        :return: The raw infrared image or None if unavailable.
197        """
198        return self.get_raw_image(CameraStreamType.Infrared)

Returns the raw infrared image from the camera.

Returns

The raw infrared image or None if unavailable.

@staticmethod
def add_params(parser: argparse.ArgumentParser):
200    @staticmethod
201    def add_params(parser: ArgumentParser):
202        """
203        Adds camera-specific parameters to the argument parser.
204
205        :param parser: The argument parser instance.
206        """
207        super(BaseDepthCamera, BaseDepthCamera).add_params(parser)
208        BaseDepthInput.add_params(parser)
209
210        try:
211            parser.add_argument("-ir", "--infrared", action="store_true", help="Use infrared as input stream.")
212        except ArgumentError as ex:
213            if ex.message.startswith("conflicting"):
214                return
215            raise ex

Adds camera-specific parameters to the argument parser.

Parameters
  • parser: The argument parser instance.
is_playback: bool
217    @property
218    def is_playback(self) -> bool:
219        """
220        Indicates whether the camera is in playback mode.
221
222        :return: False since this is a real-time camera.
223        """
224        return False

Indicates whether the camera is in playback mode.

Returns

False since this is a real-time camera.