-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ROI and binning handling #16
Changes from 4 commits
e92590c
3adef6d
0529ed9
fc3f738
19641f7
395511f
0a0e77a
9029eb0
b8bd1f9
4c0f666
0975852
44d6d5a
4a658cb
167c9f8
abbbaa5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,12 @@ | |
|
||
from rclpy.node import Node | ||
from rclpy.time import Time | ||
from rclpy.qos import qos_profile_sensor_data | ||
|
||
from sensor_msgs.msg import CameraInfo, CompressedImage, Image | ||
|
||
from cv_bridge import CvBridge | ||
from image_geometry.cameramodels import PinholeCameraModel | ||
|
||
from message_filters import ApproximateTimeSynchronizer, Subscriber | ||
|
||
|
@@ -58,11 +60,23 @@ def __init__( | |
topic_postfix = "/image_raw" | ||
|
||
self._image = None | ||
self._camera_info = None | ||
self._cvb = CvBridge() | ||
self._cam_model = PinholeCameraModel() | ||
|
||
sync_topics = [ | ||
Subscriber(self._node, img_msg_type, self._camera_name + topic_postfix), | ||
Subscriber(self._node, CameraInfo, self._camera_name + "/camera_info"), | ||
Subscriber( | ||
self._node, | ||
img_msg_type, | ||
self._camera_name + topic_postfix, | ||
qos_profile=qos_profile_sensor_data, | ||
), | ||
Subscriber( | ||
self._node, | ||
CameraInfo, | ||
self._camera_name + "/camera_info", | ||
qos_profile=qos_profile_sensor_data, | ||
), | ||
] | ||
|
||
# Create time approximate time synchronization | ||
|
@@ -74,43 +88,24 @@ def __init__( | |
# Register callback depending on the configuration | ||
self._image_approx_time_sync.registerCallback(self._on_image_data_cb) | ||
|
||
def image_guarded(func: Callable[..., RetType]) -> Callable[..., RetType]: | ||
"""Decorator, checks if image was already received. | ||
def data_recieved_guarded(func: Callable[..., RetType]) -> Callable[..., RetType]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "data_received_guarded" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually lots of "recieved" in the code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
"""Decorator, checks if data was already received. | ||
|
||
:param func: Function to wrap. | ||
:type func: Callable[..., RetType] | ||
:raises RuntimeError: No images were received yet. | ||
:return: Wrapped function. | ||
:rtype: Callable[..., RetType] | ||
""" | ||
|
||
def _image_guarded_inner(self, *args, **kwargs) -> RetType: | ||
if self._image is None: | ||
raise RuntimeError( | ||
f"No images received yet from camera '{self._camera_name}'!" | ||
) | ||
return func(self, *args, **kwargs) | ||
|
||
return _image_guarded_inner | ||
|
||
def k_matrix_guarded(func: Callable[..., RetType]) -> Callable[..., RetType]: | ||
"""Decorator, checks if an intrinsic matrix was already received. | ||
|
||
:param func: Function to wrap. | ||
:type func: Callable[..., RetType] | ||
:raises RuntimeError: No images were received yet. | ||
:raises RuntimeError: No data was received yet. | ||
:return: Wrapped function. | ||
:rtype: Callable[..., RetType] | ||
""" | ||
|
||
def _k_matrix_guarded_inner(self, *args, **kwargs) -> RetType: | ||
if self._camera_k is None: | ||
def _data_recieved_guarded_inner(self, *args, **kwargs) -> RetType: | ||
if self._image is None and self._camera_info is None: | ||
raise RuntimeError( | ||
f"Camera info was not received yet from camera '{self._camera_name}'!" | ||
f"No data received yet from the camera '{self._camera_name}'!" | ||
) | ||
return func(self, *args, **kwargs) | ||
|
||
return _k_matrix_guarded_inner | ||
return _data_recieved_guarded_inner | ||
|
||
def _validate_k_matrix(self, k_arr: npt.NDArray[np.float64]) -> bool: | ||
"""Performs basic check of the structure of intrinsic matrix. | ||
|
@@ -139,30 +134,26 @@ def _on_image_data_cb( | |
""" | ||
|
||
if self._validate_k_matrix(info.k): | ||
self._camera_k = info.k | ||
self._camera_info = info | ||
else: | ||
self._node.get_logger().warn( | ||
f"K matrix from topic '{self._info_sub.topic_name()}' is incorrect!" | ||
f" Fix it or set 'cameras.{self._camera_name}.k_matrix'" | ||
f" param for the camera '{self._camera_name}'.", | ||
f"K matrix from topic '{self._info_sub.topic_name()}' is incorrect!", | ||
throttle_duration_sec=5.0, | ||
) | ||
return | ||
|
||
self._image = image | ||
# Fire the callback only if camera info is available | ||
if self._camera_k is not None: | ||
self._image_sync_hook() | ||
self._image_sync_hook() | ||
|
||
def ready(self) -> bool: | ||
"""Checks if the camera has all the data needed to use. | ||
|
||
:return: Camera image and intrinsic matrix are available | ||
:rtype: bool | ||
""" | ||
return self._image is not None and self._camera_k is not None | ||
return self._image is not None | ||
|
||
@image_guarded | ||
@data_recieved_guarded | ||
def get_last_image_frame_id(self) -> str: | ||
"""Returns frame id associated with the last received image. | ||
|
||
|
@@ -172,7 +163,7 @@ def get_last_image_frame_id(self) -> str: | |
""" | ||
return self._image.header.frame_id | ||
|
||
@image_guarded | ||
@data_recieved_guarded | ||
def get_last_image_stamp(self) -> Time: | ||
"""Returns time stamp associated with last received image. | ||
|
||
|
@@ -182,7 +173,7 @@ def get_last_image_stamp(self) -> Time: | |
""" | ||
return Time.from_msg(self._image.header.stamp) | ||
|
||
@image_guarded | ||
@data_recieved_guarded | ||
def get_last_rgb_image(self) -> npt.NDArray[np.uint8]: | ||
"""Returns last received color image. | ||
|
||
|
@@ -203,12 +194,13 @@ def get_last_rgb_image(self) -> npt.NDArray[np.uint8]: | |
) | ||
return encoder(self._image, desired_encoding) | ||
|
||
@k_matrix_guarded | ||
@data_recieved_guarded | ||
def get_last_k_matrix(self) -> npt.NDArray[np.float64]: | ||
"""Returns intrinsic matrix associated with last received camera info message. | ||
|
||
:raises RuntimeError: No camera info messages were received yet. | ||
:return: 3x3 Numpy array with intrinsic matrix. | ||
:rtype: numpy.typing.NDArray[numpy.float64] | ||
""" | ||
return self._camera_k.reshape((3, 3)) | ||
self._cam_model.fromCameraInfo(self._camera_info) | ||
return np.array(self._cam_model.intrinsicMatrix()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment or link explaining what qos_profile_sensor_data is meant to be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was addressed in #17. This change was followed with some other networking changes in that PR