33"""
44import carb
55from dataclasses import dataclass
6- # imports needed if you want to create viewports of the camera
7- # from omni.kit.viewport.utility import get_viewport_from_window_name
8- # from omni.kit.viewport.utility import create_viewport_window
96import omni .replicator .core as rep
107from omni .isaac .core_nodes .bindings import _omni_isaac_core_nodes
118from omni .isaac .core .prims import XFormPrim
129from pxr import Vt
1310from omni .isaac .core .utils .prims import is_prim_path_valid , get_prim_at_path
1411from omni .isaac .sensor import _sensor
12+
1513from sl .sensor .camera .pyzed_sim_streamer import ZEDSimStreamer , ZEDSimStreamerParams
1614import time
1715import copy
2119LEFT_CAMERA_PATH = "/base_link/ZED_X/CameraLeft"
2220RIGHT_CAMERA_PATH = "/base_link/ZED_X/CameraRight"
2321IMU_PRIM_PATH = "/base_link/ZED_X/Imu_Sensor"
24- IMAGE_WIDTH = 1920
25- IMAGE_HEIGHT = 1080
2622CHANNELS = 3
27-
23+
24+
2825class SlCameraStreamer :
2926 """
3027 Streams camera data to the ZED SDK
@@ -42,6 +39,7 @@ class State:
4239 pyzed_streamer = None
4340 start_time = - 1.0
4441 last_timestamp = 0.0
42+ target_fps = 30
4543 camera_prim_name = None
4644 override_simulation_time = False
4745 imu_sensor_interface = None
@@ -55,12 +53,12 @@ def internal_state() -> State:
5553 return SlCameraStreamer .State ()
5654
5755 @staticmethod
58- def get_render_product_path (camera_path :str , render_product_size = [IMAGE_WIDTH , IMAGE_HEIGHT ], force_new = True ):
56+ def get_render_product_path (camera_path :str , render_product_size = [1280 , 720 ], force_new = True ):
5957 """Helper function to get render product path
6058
6159 Args:
6260 camera_path (str): the path of the camera prim
63- render_product_size (list, optional): the resolution of the image. Defaults to [IMAGE_WIDTH, IMAGE_HEIGHT] .
61+ render_product_size (list, optional): the resolution of the image. Defaults to HD720 .
6462 force_new (bool, optional): forces the creation of a new render product. Defaults to True.
6563
6664 Returns:
@@ -71,7 +69,7 @@ def get_render_product_path(camera_path :str, render_product_size = [IMAGE_WIDTH
7169 return render_product_path
7270
7371 @staticmethod
74- def get_image_data (annotator ):
72+ def get_image_data (annotator , data_shape : tuple ):
7573 """Helper function to fetch image data.
7674
7775 Args:
@@ -88,14 +86,22 @@ def get_image_data(annotator):
8886 result = False
8987 return data , result
9088 data = data [:, :, :3 ]
91- if not data .shape == ( IMAGE_HEIGHT , IMAGE_WIDTH , CHANNELS ) :
89+ if not data .shape == data_shape :
9290 result = False
9391 except :
9492 return None , False
9593 return data , result
9694
9795 @staticmethod
9896 def check_camera (camera_prim_path : str ):
97+ """Check if the camera properties are valid. If not, set them to default values.
98+
99+ Args:
100+ camera_prim_path (str): the path of the camera prim
101+
102+ Returns:
103+ bool: True if the camera properties are valid, False otherwise
104+ """
99105 result = False
100106 default_fl , default_apt_h , default_apt_v = 2.208 , 5.76 , 3.24
101107 default_projection_type = "pinhole"
@@ -119,6 +125,33 @@ def check_camera(camera_prim_path : str):
119125 result = True
120126 return result
121127
128+ @staticmethod
129+ def get_resolution (camera_resolution : str ):
130+ """Get the resolution of the camera
131+
132+ Args:
133+ camera_resolution (str): the resolution name of the camera
134+
135+ Returns:
136+ list: the resolution of the camera
137+ """
138+ if camera_resolution == "HD1080" :
139+ result = [1920 , 1080 ]
140+ elif camera_resolution == "HD720" :
141+ result = [1280 , 720 ]
142+ elif camera_resolution == "VGA" :
143+ result = [672 , 376 ]
144+ else :
145+ result = None
146+ return result
147+
148+ @staticmethod
149+ def check_frame_rate (camera_frame_rate : int ):
150+ if camera_frame_rate not in [15 , 30 , 60 ]:
151+ carb .log_warn (f"Invalid frame rate passed: { camera_frame_rate } . Defaulting to 30." )
152+ return 30
153+ return camera_frame_rate
154+
122155
123156 @staticmethod
124157 def compute (db ) -> bool :
@@ -129,7 +162,7 @@ def compute(db) -> bool:
129162 if db .inputs .camera_prim is None :
130163 carb .log_error ("Invalid Camera prim" )
131164 return
132-
165+
133166 # Check port
134167 port = db .inputs .streaming_port
135168 if port <= 0 or port % 2 == 1 :
@@ -152,21 +185,28 @@ def compute(db) -> bool:
152185 if not res :
153186 carb .log_warn (f"[{ db .inputs .camera_prim [0 ].GetPrimPath ()} ] Invalid or non existing zed camera, try to re-import your camera prim." )
154187
188+ # Check resolution and retrieve width and height
189+ resolution = SlCameraStreamer .get_resolution (db .inputs .resolution )
190+ if resolution is None :
191+ resolution = [1280 , 720 ]
192+ carb .log_warn (f"Invalid resolution passed. Defaulting to HD720." )
193+
194+ # Check frame rate
195+ db .internal_state .target_fps = SlCameraStreamer .check_frame_rate (db .inputs .fps )
196+
155197 if (db .internal_state .annotator_left is None ):
156- render_product_path_left = SlCameraStreamer .get_render_product_path (left_cam_path )
198+ render_product_path_left = SlCameraStreamer .get_render_product_path (left_cam_path , render_product_size = resolution )
157199 db .internal_state .annotator_left = rep .AnnotatorRegistry .get_annotator ("rgb" , device = "cuda" , do_array_copy = False )
158200 db .internal_state .annotator_left .attach ([render_product_path_left ])
159201
160202 if (db .internal_state .annotator_right is None ):
161- render_product_path_right = SlCameraStreamer .get_render_product_path (right_cam_path )
203+ render_product_path_right = SlCameraStreamer .get_render_product_path (right_cam_path , render_product_size = resolution )
162204 db .internal_state .annotator_right = rep .AnnotatorRegistry .get_annotator ("rgb" , device = "cuda" , do_array_copy = False )
163205 db .internal_state .annotator_right .attach ([render_product_path_right ])
164206
165207 db .internal_state .imu_prim_path = db .inputs .camera_prim [0 ].pathString + IMU_PRIM_PATH
166208 db .internal_state .imu_prim = XFormPrim (prim_path = db .internal_state .imu_prim_path )
167209
168- carb .settings .get_settings ().set ("/omni/replicator/captureOnPlay" , False )
169-
170210 # Setup streamer parameters
171211 db .internal_state .pyzed_streamer = ZEDSimStreamer ()
172212
@@ -178,8 +218,9 @@ def compute(db) -> bool:
178218 carb .log_warn (f"Invalid serial number passed. Defaulting to: { serial_number } ." )
179219
180220 streamer_params = ZEDSimStreamerParams ()
181- streamer_params .image_width = IMAGE_WIDTH
182- streamer_params .image_height = IMAGE_HEIGHT
221+ streamer_params .image_width = resolution [0 ]
222+ streamer_params .image_height = resolution [1 ]
223+ streamer_params .fps = db .internal_state .target_fps
183224 streamer_params .alpha_channel_included = False
184225 streamer_params .rgb_encoded = True
185226 streamer_params .serial_number = serial_number
@@ -190,24 +231,38 @@ def compute(db) -> bool:
190231 # set state to initialized
191232 carb .log_info (f"Streaming camera { db .internal_state .camera_prim_name } at port { port } and using serial number { serial_number } ." )
192233 db .internal_state .invalid_images_count = 0
234+ db .internal_state .last_timestamp = 0.0
235+ db .internal_state .data_shape = (resolution [1 ], resolution [0 ], CHANNELS )
193236 db .internal_state .initialized = True
194237
195238 try :
196239 ts : int = 0
197240 if db .internal_state .initialized is True :
198241 left , right = None , None
199242 current_time = db .internal_state .core_nodes_interface .get_sim_time ()
243+
244+ # Reset last_timestamp between different play sessions
245+ if db .internal_state .last_timestamp > current_time :
246+ db .internal_state .last_timestamp = current_time
247+
248+ delta_time = current_time - db .internal_state .last_timestamp
249+
250+ # Skip data fetch if the time between frames is too short
251+ if delta_time < 1.0 / db .internal_state .target_fps :
252+ return False
200253
201254 # we fetch image data from annotators - we do it sequentially to avoid fetching both if one fails
202- left , res = SlCameraStreamer .get_image_data (db .internal_state .annotator_left )
255+ left , res = SlCameraStreamer .get_image_data (db .internal_state .annotator_left ,
256+ db .internal_state .data_shape )
203257 if res == False :
204258 db .internal_state .invalid_images_count += 1
205259 if db .internal_state .invalid_images_count >= 10 :
206260 carb .log_warn (f"{ db .internal_state .camera_prim_name } - Left camera retrieved unexpected "
207261 "data shape, skipping frame." )
208262 return False # no need to continue compute
209263
210- right , res = SlCameraStreamer .get_image_data (db .internal_state .annotator_right )
264+ right , res = SlCameraStreamer .get_image_data (db .internal_state .annotator_right ,
265+ db .internal_state .data_shape )
211266 if res == False :
212267 db .internal_state .invalid_images_count += 1
213268 if db .internal_state .invalid_images_count >= 10 :
0 commit comments