Skip to content

Commit 57ee33f

Browse files
committed
Updated the yaml file settings
Now you can define args in cone_detection.yaml
1 parent 3f3c5a5 commit 57ee33f

3 files changed

Lines changed: 135 additions & 69 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cameras:
2+
front:
3+
K:
4+
- [684.83331299, 0.0, 573.37109375]
5+
- [0.0, 684.60968018, 363.70092773]
6+
- [0.0, 0.0, 1.0]
7+
D: [0.0, 0.0, 0.0, 0.0, 0.0]
8+
T_l2c:
9+
- [ 0.0289748006, -0.999580136, 0.0000368439, -0.0307300513]
10+
- [-0.0094993062, -0.0003122155, -0.999954834, -0.386689354 ]
11+
- [ 0.999534999, 0.0289731321, -0.0095043721, -0.671425124 ]
12+
- [ 0.0, 0.0, 0.0, 1.0 ]
13+
14+
front_right:
15+
K:
16+
- [1176.25545, 0.0, 966.432645]
17+
- [0.0, 1175.14569, 608.580326]
18+
- [0.0, 0.0, 1.0 ]
19+
D: [-0.270136325, 0.164393255, -0.00160720782, -0.0000741246708, -0.0619939758]
20+
T_l2c:
21+
- [-0.71836368, -0.69527204, -0.02346088, 0.05718003]
22+
- [-0.09720448, 0.13371206, -0.98624154, -0.15983010]
23+
- [ 0.68884317, -0.70619960, -0.16363744, -1.04767285]
24+
- [ 0.0, 0.0, 0.0, 1.0 ]
25+
26+
# add other cameras (back_left, front_right, back_right) similarly...

GEMstack/onboard/perception/cone_detection.py

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import math
1919
import ros_numpy
2020
import os
21+
import yaml
2122

2223

2324
# ----- Helper Functions -----
@@ -269,30 +270,79 @@ class ConeDetector3D(Component):
269270
270271
Tracking is optional: set `enable_tracking=False` to disable persistent tracking
271272
and return only detections from the current frame.
273+
274+
Supports multiple cameras; each camera’s intrinsics and extrinsics are
275+
loaded from a single YAML calibration file via plain PyYAML.
272276
"""
273277

274-
def __init__(self, vehicle_interface: GEMInterface):
275-
self.vehicle_interface = vehicle_interface
276-
self.enable_tracking = False
277-
self.current_agents = {}
278-
self.tracked_agents = {}
279-
self.cone_counter = 0
280-
self.latest_image = None
281-
self.latest_lidar = None
282-
self.bridge = CvBridge()
283-
self.start_pose_abs = None
284-
self.camera_front = False
285-
self.visualize_2d = False
286-
self.use_cyl_roi = False
287-
self.start_time = None
288-
self.use_start_frame = False
289-
self.save_data = False
290-
self.orientation = False
278+
def __init__(
279+
self,
280+
vehicle_interface: GEMInterface,
281+
camera_name: str,
282+
camera_calib_file: str,
283+
enable_tracking: bool = True,
284+
visualize_2d: bool = False,
285+
use_cyl_roi: bool = False,
286+
T_l2v: list = None,
287+
save_data: bool = True,
288+
orientation: bool = True,
289+
use_start_frame: bool = True,
290+
**kwargs
291+
):
292+
# Core interfaces and state
293+
self.vehicle_interface = vehicle_interface
294+
self.current_agents = {}
295+
self.tracked_agents = {}
296+
self.cone_counter = 0
297+
self.latest_image = None
298+
self.latest_lidar = None
299+
self.bridge = CvBridge()
300+
self.start_pose_abs = None
301+
self.start_time = None
302+
303+
# Config flags
304+
self.camera_name = camera_name
305+
self.enable_tracking = enable_tracking
306+
self.visualize_2d = visualize_2d
307+
self.use_cyl_roi = use_cyl_roi
308+
self.save_data = save_data
309+
self.orientation = orientation
310+
self.use_start_frame = use_start_frame
311+
312+
# 1) Load lidar→vehicle transform
313+
if T_l2v is not None:
314+
self.T_l2v = np.array(T_l2v)
315+
else:
316+
self.T_l2v = np.array([
317+
[0.99939639, 0.02547917, 0.023615, 1.1],
318+
[-0.02530848, 0.99965156, -0.00749882, 0.03773583],
319+
[-0.02379784, 0.00689664, 0.999693, 1.95320223],
320+
[0.0, 0.0, 0.0, 1.0]
321+
])
322+
323+
# 2) Load camera intrinsics/extrinsics from the supplied YAML
324+
with open(camera_calib_file, 'r') as f:
325+
calib = yaml.safe_load(f)
326+
327+
# Expect structure:
328+
# cameras:
329+
# front:
330+
# K: [[...], [...], [...]]
331+
# D: [...]
332+
# T_l2c: [[...], ..., [...]]
333+
cam_cfg = calib['cameras'][camera_name]
334+
self.K = np.array(cam_cfg['K'])
335+
self.D = np.array(cam_cfg['D'])
336+
self.T_l2c = np.array(cam_cfg['T_l2c'])
337+
338+
# Derived transforms
339+
291340
self.undistort_map1 = None
292341
self.undistort_map2 = None
342+
self.camera_front = (camera_name=='front')
293343

294344
def rate(self) -> float:
295-
return 10.0
345+
return 8
296346

297347
def state_inputs(self) -> list:
298348
return ['vehicle']
@@ -301,48 +351,30 @@ def state_outputs(self) -> list:
301351
return ['agents']
302352

303353
def initialize(self):
304-
self.rgb_sub = Subscriber('/camera_fr/arena_camera_node/image_raw', Image)
354+
# --- Determine the correct RGB topic for this camera ---
355+
rgb_topic_map = {
356+
'front': '/oak/rgb/image_raw',
357+
'front_right': '/camera_fr/arena_camera_node/image_raw',
358+
# add additional camera mappings here if needed
359+
}
360+
rgb_topic = rgb_topic_map.get(
361+
self.camera_name,
362+
f'/{self.camera_name}/rgb/image_raw'
363+
)
364+
365+
# Subscribe to the RGB and LiDAR streams
366+
self.rgb_sub = Subscriber(rgb_topic, Image)
305367
self.lidar_sub = Subscriber('/ouster/points', PointCloud2)
306-
self.sync = ApproximateTimeSynchronizer([self.rgb_sub, self.lidar_sub],
307-
queue_size=200, slop=0.1)
368+
self.sync = ApproximateTimeSynchronizer([
369+
self.rgb_sub, self.lidar_sub
370+
], queue_size=200, slop=0.1)
308371
self.sync.registerCallback(self.synchronized_callback)
372+
373+
# Initialize the YOLO detector
309374
self.detector = YOLO('GEMstack/knowledge/detection/cone.pt')
310375
self.detector.to('cuda')
311-
312-
if self.camera_front:
313-
self.K = np.array([[684.83331299, 0., 573.37109375],
314-
[0., 684.60968018, 363.70092773],
315-
[0., 0., 1.]])
316-
else:
317-
self.K = np.array([[1.17625545e+03, 0.00000000e+00, 9.66432645e+02],
318-
[0.00000000e+00, 1.17514569e+03, 6.08580326e+02],
319-
[0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
320-
321-
if self.camera_front:
322-
self.D = np.array([0.0, 0.0, 0.0, 0.0, 0.0])
323-
else:
324-
self.D = np.array([-2.70136325e-01, 1.64393255e-01, -1.60720782e-03, -7.41246708e-05,
325-
-6.19939758e-02])
326-
327-
self.T_l2v = np.array([[0.99939639, 0.02547917, 0.023615, 1.1],
328-
[-0.02530848, 0.99965156, -0.00749882, 0.03773583],
329-
[-0.02379784, 0.00689664, 0.999693, 1.95320223],
330-
[0., 0., 0., 1.]])
331-
if self.camera_front:
332-
self.T_l2c = np.array([
333-
[2.89748006e-02, -9.99580136e-01, 3.68439439e-05, -3.07300513e-02],
334-
[-9.49930618e-03, -3.12215512e-04, -9.99954834e-01, -3.86689354e-01],
335-
[9.99534999e-01, 2.89731321e-02, -9.50437214e-03, -6.71425124e-01],
336-
[0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]
337-
])
338-
else:
339-
self.T_l2c = np.array([[-0.71836368, -0.69527204, -0.02346088, 0.05718003],
340-
[-0.09720448, 0.13371206, -0.98624154, -0.1598301],
341-
[0.68884317, -0.7061996, -0.16363744, -1.04767285],
342-
[0., 0., 0., 1.]]
343-
)
344-
self.T_c2l = np.linalg.inv(self.T_l2c)
345-
self.R_c2l = self.T_c2l[:3, :3]
376+
self.T_c2l = np.linalg.inv(self.T_l2c)
377+
self.R_c2l = self.T_c2l[:3, :3]
346378
self.camera_origin_in_lidar = self.T_c2l[:3, 3]
347379

348380
def synchronized_callback(self, image_msg, lidar_msg):
@@ -439,15 +471,18 @@ def update(self, vehicle: VehicleState) -> Dict[str, AgentState]:
439471
img_normal = undistorted_img
440472
else:
441473
img_normal = lastest_image.copy()
442-
results_normal = self.detector(img_normal, conf=0.3, classes=[0])
474+
undistorted_img = lastest_image.copy()
475+
orig_H, orig_W = lastest_image.shape[:2]
476+
self.current_K = self.K
477+
results_normal = self.detector(img_normal, conf=0.25, classes=[0])
443478
combined_boxes = []
444479
if not self.enable_tracking:
445480
self.cone_counter = 0
446481
if self.orientation:
447482
img_left = cv2.rotate(undistorted_img.copy(), cv2.ROTATE_90_COUNTERCLOCKWISE)
448483
img_right = cv2.rotate(undistorted_img.copy(), cv2.ROTATE_90_CLOCKWISE)
449-
results_left = self.detector(img_left, conf=0.75, classes=[0])
450-
results_right = self.detector(img_right, conf=0.75, classes=[0])
484+
results_left = self.detector(img_left, conf=0.05, classes=[0])
485+
results_right = self.detector(img_right, conf=0.05, classes=[0])
451486
boxes_left = np.array(results_left[0].boxes.xywh.cpu()) if len(results_left) > 0 else []
452487
boxes_right = np.array(results_right[0].boxes.xywh.cpu()) if len(results_right) > 0 else []
453488
for box in boxes_left:
@@ -489,7 +524,6 @@ def update(self, vehicle: VehicleState) -> Dict[str, AgentState]:
489524
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
490525
cv2.imshow("Detection - Cone 2D", undistorted_img)
491526

492-
493527
start = time.time()
494528
pts_cam = transform_points_l2c(lidar_down, self.T_l2c)
495529
projected_pts = project_points(pts_cam, self.current_K, lidar_down)

launch/cone_detection.yaml

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,24 @@ recovery:
99
trajectory_tracking : recovery.StopTrajectoryTracker
1010

1111
# Driving behavior for the GEM vehicle. Runs real pedestrian perception, yield planner, but does not send commands to real vehicle.
12-
drive:
12+
drive:
1313
perception:
1414
state_estimation : GNSSStateEstimator
15-
agent_detection : cone_detection.ConeDetector3D
15+
agent_detection :
16+
type: cone_detection.ConeDetector3D
17+
args:
18+
camera_name: front_right #[front, front_right]
19+
camera_calib_file: knowledge/calib/cameras.yaml
20+
21+
# optional overrides
22+
enable_tracking: False
23+
visualize_2d: False
24+
use_cyl_roi: False
25+
save_data: False
26+
orientation: False
27+
use_start_frame: False
28+
1629
perception_normalization : StandardPerceptionNormalizer
17-
enable_tracking : False
18-
camera_front : False
19-
visualize_2d : False
20-
use_cyl_roi : False
21-
use_start_frame : False
22-
save_data : False
23-
orientation : False
2430
planning:
2531
relations_estimation:
2632
type: pedestrian_yield_logic.PedestrianYielder

0 commit comments

Comments
 (0)