From ddb8d96755134acb6f6b9460e2b51442296e9a83 Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Mon, 20 Mar 2023 15:49:42 +0100 Subject: [PATCH 01/15] feat(#62): Implemented TLDNode without testing yet --- code/perception/launch/perception.launch | 5 + .../traffic_light_detection/tld_ckpt.pt | Bin 0 -> 10282 bytes code/perception/src/TLDNode.py | 127 ++++++++++++++++++ .../traffic_light_inference.py | 1 + 4 files changed, 133 insertions(+) create mode 100644 code/perception/models/traffic_light_detection/tld_ckpt.pt create mode 100755 code/perception/src/TLDNode.py diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 9c7c2828..4237ec71 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -18,6 +18,11 @@ + + + + + diff --git a/code/perception/models/traffic_light_detection/tld_ckpt.pt b/code/perception/models/traffic_light_detection/tld_ckpt.pt new file mode 100644 index 0000000000000000000000000000000000000000..c66789a21b88853039718bda3a38d3b58468084a GIT binary patch literal 10282 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 literal 0 HcmV?d00001 diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py new file mode 100755 index 00000000..55fc0ec1 --- /dev/null +++ b/code/perception/src/TLDNode.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +import pathlib +import numpy as np +import ros_compatibility as roscomp +from rospy.numpy_msg import numpy_msg +from ros_compatibility.node import CompatibleNode +from sensor_msgs.msg import Image + +from traffic_light_detection.traffic_light_inference import \ + TrafficLightInference +from panoptic_segmentation.preparation.labels import name2label +from panoptic_segmentation.datasets.panoptic_dataset import rgb2id + +MODEL_PATH = pathlib.Path( + __file__).parent.parent / \ + "models/traffic_light_detection/tld_ckpt.pt" + + +class TLDNode(CompatibleNode): + """ + This node runs the traffic light detection model on + the semantic images and publishes the classified traffic lights. + """ + + def __init__(self, name, **kwargs): + super().__init__(name, **kwargs) + + self.image = None + self.publisher = None + self.loginfo("Initializing traffic light detection node...") + + self.role_name = self.get_param("role_name", "hero") + self.side = self.get_param("side", "Center") + + self.model = self.load_model() + + self.setup_subscriptions() + self.setup_publishers() + self.traffic_light_id = name2label("traffic light").id + + def setup_subscriptions(self): + self.new_subscription( + msg_type=numpy_msg(Image), + callback=self.handle_segmented_image, + topic=f"/carla/{self.role_name}/{self.side}/segmented_image", + qos_profile=1 + ) + self.new_subscription( + msg_type=numpy_msg(Image), + callback=self.handle_image, + topic=f"/carla/{self.role_name}/{self.side}/image", + qos_profile=1 + ) + + def setup_publishers(self): + self.publisher = self.new_publisher( + msg_type=str, + topic=f"/paf/{self.role_name}/{self.side}/segmented_image", + qos_profile=1 + ) + + @staticmethod + def load_model(): + model = TrafficLightInference(model_path=MODEL_PATH) + return model + + def predict(self, image: np.ndarray): + self.loginfo(f"predicting image shape: {image.shape}") + result = self.model(image) + result = result.cpu().numpy() + return result + + def handle_image(self, image): + image_array = np.frombuffer(image.data, dtype=np.uint8) + image_array = image_array.reshape((image.height, image.width, -1)) + # remove alpha channel + image_array = image_array[:, :, :3] + self.image = image_array + + def handle_segmented_image(self, image): + self.loginfo(f"got segmented image from EfficientPS {self.side}") + image = rgb2id(image) + mask = self.traffic_light_id * 1000 <= image < \ + (self.traffic_light_id + 1) * 1000 + if not mask.any(): + return + + tl_image = np.zeros(image.shape) + tl_image[mask] = image[mask] + + indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, + tl_image.shape[1] // 3: + 2 * (tl_image.shape[1] // 3)]) + upper_left = [min(indices[:, 0]), min(indices[: 1])] + lower_right = [max(indices[:, 0]), max(indices[: 1])] + + traffic_light = self.image[upper_left[0]:lower_right[0], + upper_left[1]:lower_right[1]] + classification = self.predict(traffic_light) + + # construct the message + msg = Image() + msg.header.stamp = roscomp.ros_timestamp( + self.get_time(), from_sec=True) + msg.header.frame_id = "map" + msg.data = str(classification) + self.publisher.publish(msg) + + def run(self): + self.spin() + pass + # while True: + # self.spin() + + +if __name__ == "__main__": + roscomp.init("TLDNode") + # try: + + node = TLDNode("TLDNode") + node.run() + # except KeyboardInterrupt: + # pass + # finally: +# roscomp.shutdown() +# diff --git a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py index 40dd4c24..798141e6 100644 --- a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py +++ b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py @@ -43,6 +43,7 @@ def __init__(self, model_path): ]) self.model = ClassificationModel.load_model(self.cfg) + self.model.eval() self.model = self.model.to(self.cfg.DEVICE) self.class_dict = {0: 'Backside', 1: 'Green', From ad7ee94e31afcd694c1daa708d4826d8f97c5cd0 Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Mon, 20 Mar 2023 15:49:42 +0100 Subject: [PATCH 02/15] feat(#218): Implemented TLDNode without testing yet --- code/perception/launch/perception.launch | 5 + .../traffic_light_detection/tld_ckpt.pt | Bin 0 -> 10282 bytes code/perception/src/TLDNode.py | 127 ++++++++++++++++++ .../traffic_light_inference.py | 1 + 4 files changed, 133 insertions(+) create mode 100644 code/perception/models/traffic_light_detection/tld_ckpt.pt create mode 100755 code/perception/src/TLDNode.py diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 9c7c2828..4237ec71 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -18,6 +18,11 @@ + + + + + diff --git a/code/perception/models/traffic_light_detection/tld_ckpt.pt b/code/perception/models/traffic_light_detection/tld_ckpt.pt new file mode 100644 index 0000000000000000000000000000000000000000..c66789a21b88853039718bda3a38d3b58468084a GIT binary patch literal 10282 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 literal 0 HcmV?d00001 diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py new file mode 100755 index 00000000..55fc0ec1 --- /dev/null +++ b/code/perception/src/TLDNode.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +import pathlib +import numpy as np +import ros_compatibility as roscomp +from rospy.numpy_msg import numpy_msg +from ros_compatibility.node import CompatibleNode +from sensor_msgs.msg import Image + +from traffic_light_detection.traffic_light_inference import \ + TrafficLightInference +from panoptic_segmentation.preparation.labels import name2label +from panoptic_segmentation.datasets.panoptic_dataset import rgb2id + +MODEL_PATH = pathlib.Path( + __file__).parent.parent / \ + "models/traffic_light_detection/tld_ckpt.pt" + + +class TLDNode(CompatibleNode): + """ + This node runs the traffic light detection model on + the semantic images and publishes the classified traffic lights. + """ + + def __init__(self, name, **kwargs): + super().__init__(name, **kwargs) + + self.image = None + self.publisher = None + self.loginfo("Initializing traffic light detection node...") + + self.role_name = self.get_param("role_name", "hero") + self.side = self.get_param("side", "Center") + + self.model = self.load_model() + + self.setup_subscriptions() + self.setup_publishers() + self.traffic_light_id = name2label("traffic light").id + + def setup_subscriptions(self): + self.new_subscription( + msg_type=numpy_msg(Image), + callback=self.handle_segmented_image, + topic=f"/carla/{self.role_name}/{self.side}/segmented_image", + qos_profile=1 + ) + self.new_subscription( + msg_type=numpy_msg(Image), + callback=self.handle_image, + topic=f"/carla/{self.role_name}/{self.side}/image", + qos_profile=1 + ) + + def setup_publishers(self): + self.publisher = self.new_publisher( + msg_type=str, + topic=f"/paf/{self.role_name}/{self.side}/segmented_image", + qos_profile=1 + ) + + @staticmethod + def load_model(): + model = TrafficLightInference(model_path=MODEL_PATH) + return model + + def predict(self, image: np.ndarray): + self.loginfo(f"predicting image shape: {image.shape}") + result = self.model(image) + result = result.cpu().numpy() + return result + + def handle_image(self, image): + image_array = np.frombuffer(image.data, dtype=np.uint8) + image_array = image_array.reshape((image.height, image.width, -1)) + # remove alpha channel + image_array = image_array[:, :, :3] + self.image = image_array + + def handle_segmented_image(self, image): + self.loginfo(f"got segmented image from EfficientPS {self.side}") + image = rgb2id(image) + mask = self.traffic_light_id * 1000 <= image < \ + (self.traffic_light_id + 1) * 1000 + if not mask.any(): + return + + tl_image = np.zeros(image.shape) + tl_image[mask] = image[mask] + + indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, + tl_image.shape[1] // 3: + 2 * (tl_image.shape[1] // 3)]) + upper_left = [min(indices[:, 0]), min(indices[: 1])] + lower_right = [max(indices[:, 0]), max(indices[: 1])] + + traffic_light = self.image[upper_left[0]:lower_right[0], + upper_left[1]:lower_right[1]] + classification = self.predict(traffic_light) + + # construct the message + msg = Image() + msg.header.stamp = roscomp.ros_timestamp( + self.get_time(), from_sec=True) + msg.header.frame_id = "map" + msg.data = str(classification) + self.publisher.publish(msg) + + def run(self): + self.spin() + pass + # while True: + # self.spin() + + +if __name__ == "__main__": + roscomp.init("TLDNode") + # try: + + node = TLDNode("TLDNode") + node.run() + # except KeyboardInterrupt: + # pass + # finally: +# roscomp.shutdown() +# diff --git a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py index 40dd4c24..798141e6 100644 --- a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py +++ b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py @@ -43,6 +43,7 @@ def __init__(self, model_path): ]) self.model = ClassificationModel.load_model(self.cfg) + self.model.eval() self.model = self.model.to(self.cfg.DEVICE) self.class_dict = {0: 'Backside', 1: 'Green', From 1dcf91b82aac4721a52890595ef9886488003c7e Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 21 Mar 2023 14:14:07 +0100 Subject: [PATCH 03/15] feat(#218): TLDNode not starting --- code/perception/src/TLDNode.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 55fc0ec1..74e8d18b 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -26,6 +26,8 @@ class TLDNode(CompatibleNode): def __init__(self, name, **kwargs): super().__init__(name, **kwargs) + self.effps_sub = None + self.camera_sub = None self.image = None self.publisher = None self.loginfo("Initializing traffic light detection node...") @@ -40,13 +42,13 @@ def __init__(self, name, **kwargs): self.traffic_light_id = name2label("traffic light").id def setup_subscriptions(self): - self.new_subscription( + self.effps_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_segmented_image, topic=f"/carla/{self.role_name}/{self.side}/segmented_image", qos_profile=1 ) - self.new_subscription( + self.camera_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_image, topic=f"/carla/{self.role_name}/{self.side}/image", From 37a9043ae7f7e157d0786b2046f58cbb1c60b87f Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 21 Mar 2023 15:43:49 +0100 Subject: [PATCH 04/15] feat(#218): Fixes, but Node still does not start --- code/perception/launch/perception.launch | 2 -- code/perception/src/TLDNode.py | 9 +++++---- code/perception/src/traffic_light_detection/__init__.py | 1 + .../src/data_generation/__init__.py | 1 + .../src/traffic_light_detection/__init__.py | 1 + .../traffic_light_detection/traffic_light_inference.py | 9 +++++---- 6 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 code/perception/src/traffic_light_detection/__init__.py create mode 100644 code/perception/src/traffic_light_detection/src/data_generation/__init__.py create mode 100644 code/perception/src/traffic_light_detection/src/traffic_light_detection/__init__.py diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 4237ec71..5b3a908e 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -36,6 +36,4 @@ - - diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 74e8d18b..b829390b 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -6,9 +6,10 @@ from rospy.numpy_msg import numpy_msg from ros_compatibility.node import CompatibleNode from sensor_msgs.msg import Image +from std_msgs.msg import String -from traffic_light_detection.traffic_light_inference import \ - TrafficLightInference +from traffic_light_detection.src.traffic_light_detection.\ + traffic_light_inference import TrafficLightInference from panoptic_segmentation.preparation.labels import name2label from panoptic_segmentation.datasets.panoptic_dataset import rgb2id @@ -39,7 +40,7 @@ def __init__(self, name, **kwargs): self.setup_subscriptions() self.setup_publishers() - self.traffic_light_id = name2label("traffic light").id + self.traffic_light_id = (name2label["traffic light"]).id def setup_subscriptions(self): self.effps_sub = self.new_subscription( @@ -57,7 +58,7 @@ def setup_subscriptions(self): def setup_publishers(self): self.publisher = self.new_publisher( - msg_type=str, + msg_type=String, topic=f"/paf/{self.role_name}/{self.side}/segmented_image", qos_profile=1 ) diff --git a/code/perception/src/traffic_light_detection/__init__.py b/code/perception/src/traffic_light_detection/__init__.py new file mode 100644 index 00000000..7c93e6f1 --- /dev/null +++ b/code/perception/src/traffic_light_detection/__init__.py @@ -0,0 +1 @@ +__author__ = 'Marco' diff --git a/code/perception/src/traffic_light_detection/src/data_generation/__init__.py b/code/perception/src/traffic_light_detection/src/data_generation/__init__.py new file mode 100644 index 00000000..7c93e6f1 --- /dev/null +++ b/code/perception/src/traffic_light_detection/src/data_generation/__init__.py @@ -0,0 +1 @@ +__author__ = 'Marco' diff --git a/code/perception/src/traffic_light_detection/src/traffic_light_detection/__init__.py b/code/perception/src/traffic_light_detection/src/traffic_light_detection/__init__.py new file mode 100644 index 00000000..7c93e6f1 --- /dev/null +++ b/code/perception/src/traffic_light_detection/src/traffic_light_detection/__init__.py @@ -0,0 +1 @@ +__author__ = 'Marco' diff --git a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py index 798141e6..6bbd1d8d 100644 --- a/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py +++ b/code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py @@ -3,11 +3,12 @@ import torch.cuda import torchvision.transforms as t -from data_generation.transforms import Normalize, ResizeAndPadToSquare, \ - load_image -from traffic_light_detection.classification_model import ClassificationModel +from traffic_light_detection.src.data_generation.transforms \ + import Normalize, ResizeAndPadToSquare, load_image +from traffic_light_detection.src.traffic_light_detection.classification_model \ + import ClassificationModel from torchvision.transforms import ToTensor -from traffic_light_config import TrafficLightConfig +from traffic_light_detection.src.traffic_light_config import TrafficLightConfig def parse_args(): From 11552b7dacaa23615a656560cbc818bc7129470a Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 21 Mar 2023 16:08:16 +0100 Subject: [PATCH 05/15] feat(#218): Model loading fixed --- .../src/traffic_light_detection/classification_model.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/perception/src/traffic_light_detection/src/traffic_light_detection/classification_model.py b/code/perception/src/traffic_light_detection/src/traffic_light_detection/classification_model.py index 9c5fb339..377e020f 100644 --- a/code/perception/src/traffic_light_detection/src/traffic_light_detection/classification_model.py +++ b/code/perception/src/traffic_light_detection/src/traffic_light_detection/classification_model.py @@ -1,3 +1,5 @@ +import pathlib + import torch import torch.nn as nn import torch.nn.functional as F @@ -58,8 +60,12 @@ def load_model(cfg): path = cfg.MODEL_PATH if path is not None: try: + parent = pathlib.Path(__file__).parent.parent.parent\ + .parent.parent.parent + path = parent.joinpath(path) state_dict = torch.load(path) - model.load_state_dict(state_dict).eval() + model.load_state_dict(state_dict) + model.eval() print(f"Pretrained model loaded from {path}") return model except (Exception, ): From 769ab784131a1d7f4fdbd75dc3bd2f509ecceb09 Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 21 Mar 2023 17:40:31 +0100 Subject: [PATCH 06/15] feat(#218): Traffic light node is working --- code/perception/src/TLDNode.py | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index b829390b..9fa55fb1 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -7,7 +7,7 @@ from ros_compatibility.node import CompatibleNode from sensor_msgs.msg import Image from std_msgs.msg import String - +import cv2 from traffic_light_detection.src.traffic_light_detection.\ traffic_light_inference import TrafficLightInference from panoptic_segmentation.preparation.labels import name2label @@ -26,12 +26,11 @@ class TLDNode(CompatibleNode): def __init__(self, name, **kwargs): super().__init__(name, **kwargs) - + self.loginfo("Initializing traffic light detection node...") self.effps_sub = None self.camera_sub = None self.image = None self.publisher = None - self.loginfo("Initializing traffic light detection node...") self.role_name = self.get_param("role_name", "hero") self.side = self.get_param("side", "Center") @@ -41,12 +40,13 @@ def __init__(self, name, **kwargs): self.setup_subscriptions() self.setup_publishers() self.traffic_light_id = (name2label["traffic light"]).id + self.loginfo("Traffic light detection node initialized.") def setup_subscriptions(self): self.effps_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_segmented_image, - topic=f"/carla/{self.role_name}/{self.side}/segmented_image", + topic=f"/paf/{self.role_name}/{self.side}/segmented_image", qos_profile=1 ) self.camera_sub = self.new_subscription( @@ -59,7 +59,7 @@ def setup_subscriptions(self): def setup_publishers(self): self.publisher = self.new_publisher( msg_type=String, - topic=f"/paf/{self.role_name}/{self.side}/segmented_image", + topic=f"/paf/{self.role_name}/{self.side}/traffic_light", qos_profile=1 ) @@ -69,46 +69,48 @@ def load_model(): return model def predict(self, image: np.ndarray): - self.loginfo(f"predicting image shape: {image.shape}") + self.loginfo(f"TLDNode predicting image shape: {image.shape}") result = self.model(image) - result = result.cpu().numpy() return result def handle_image(self, image): + self.loginfo(f"TLDNode got image from camera {self.side}") image_array = np.frombuffer(image.data, dtype=np.uint8) image_array = image_array.reshape((image.height, image.width, -1)) # remove alpha channel image_array = image_array[:, :, :3] + image_array = cv2.resize(image_array, (1280, 720), + interpolation=cv2.INTER_NEAREST) self.image = image_array def handle_segmented_image(self, image): - self.loginfo(f"got segmented image from EfficientPS {self.side}") - image = rgb2id(image) - mask = self.traffic_light_id * 1000 <= image < \ - (self.traffic_light_id + 1) * 1000 + self.loginfo(f"TLDNode got segmented image from EfficientPS " + f"{self.side}") + image_array = np.frombuffer(image.data, dtype=np.uint8) + image_array = image_array.reshape((image.height, image.width, -1)) + image = rgb2id(image_array) + mask = np.ma.masked_outside(image, self.traffic_light_id * 1000, + (self.traffic_light_id + 1) * 1000) + mask = mask.mask if not mask.any(): return tl_image = np.zeros(image.shape) tl_image[mask] = image[mask] - indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, tl_image.shape[1] // 3: 2 * (tl_image.shape[1] // 3)]) - upper_left = [min(indices[:, 0]), min(indices[: 1])] - lower_right = [max(indices[:, 0]), max(indices[: 1])] + upper_left = [min(indices[0]), min(indices[1])] + lower_right = [max(indices[0]), max(indices[1])] traffic_light = self.image[upper_left[0]:lower_right[0], upper_left[1]:lower_right[1]] classification = self.predict(traffic_light) # construct the message - msg = Image() - msg.header.stamp = roscomp.ros_timestamp( - self.get_time(), from_sec=True) - msg.header.frame_id = "map" - msg.data = str(classification) - self.publisher.publish(msg) + self.publisher.publish(str(classification)) + self.loginfo(f"TLDNode classified traffic light " + f"{self.side}") def run(self): self.spin() From 772b9cf8a17369e6afd9dfba6ace6c351baa9b6d Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 21 Mar 2023 19:15:50 +0100 Subject: [PATCH 07/15] feat(#218): Small fix for mask creation --- code/perception/src/TLDNode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 9fa55fb1..6c345090 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -90,7 +90,7 @@ def handle_segmented_image(self, image): image_array = image_array.reshape((image.height, image.width, -1)) image = rgb2id(image_array) mask = np.ma.masked_outside(image, self.traffic_light_id * 1000, - (self.traffic_light_id + 1) * 1000) + (self.traffic_light_id + 1) * 1000 - 1) mask = mask.mask if not mask.any(): return From 9ab81187e7f6a12e9b3cbb05aee3bc0512ffcbcb Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Wed, 22 Mar 2023 19:11:47 +0100 Subject: [PATCH 08/15] feat(#218): Added publisher for snipped image --- code/perception/src/TLDNode.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 6c345090..2fb40f6b 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -26,11 +26,12 @@ class TLDNode(CompatibleNode): def __init__(self, name, **kwargs): super().__init__(name, **kwargs) + self.snip_publisher = None + self.class_publisher = None self.loginfo("Initializing traffic light detection node...") self.effps_sub = None self.camera_sub = None self.image = None - self.publisher = None self.role_name = self.get_param("role_name", "hero") self.side = self.get_param("side", "Center") @@ -57,11 +58,16 @@ def setup_subscriptions(self): ) def setup_publishers(self): - self.publisher = self.new_publisher( + self.class_publisher = self.new_publisher( msg_type=String, topic=f"/paf/{self.role_name}/{self.side}/traffic_light", qos_profile=1 ) + self.snip_publisher = self.new_publisher( + msg_type=numpy_msg(Image), + topic=f"/paf/{self.role_name}/{self.side}/snipped_traffic_light", + qos_profile=1 + ) @staticmethod def load_model(): @@ -92,11 +98,25 @@ def handle_segmented_image(self, image): mask = np.ma.masked_outside(image, self.traffic_light_id * 1000, (self.traffic_light_id + 1) * 1000 - 1) mask = mask.mask - if not mask.any(): - return tl_image = np.zeros(image.shape) tl_image[mask] = image[mask] + msg = Image() + msg.header.stamp = roscomp.ros_timestamp( + self.get_time(), from_sec=True) + msg.header.frame_id = "map" + msg.height = 720 + msg.width = 1280 + msg.encoding = "rgb8" + msg.is_bigendian = 0 + msg.step = 1280 * 3 + msg.data = tl_image + + self.snip_publisher.publish(msg) + + if not mask.any(): + return + indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, tl_image.shape[1] // 3: 2 * (tl_image.shape[1] // 3)]) @@ -108,7 +128,7 @@ def handle_segmented_image(self, image): classification = self.predict(traffic_light) # construct the message - self.publisher.publish(str(classification)) + self.class_publisher.publish(str(classification)) self.loginfo(f"TLDNode classified traffic light " f"{self.side}") From b0937e473524b509a1e6ac1538ab1107f51472cb Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Thu, 23 Mar 2023 13:53:29 +0100 Subject: [PATCH 09/15] feat(#218): Fixed mask creation --- code/perception/src/TLDNode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 2fb40f6b..4d66e2d2 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -12,6 +12,7 @@ traffic_light_inference import TrafficLightInference from panoptic_segmentation.preparation.labels import name2label from panoptic_segmentation.datasets.panoptic_dataset import rgb2id +from panopticapi.utils import id2rgb MODEL_PATH = pathlib.Path( __file__).parent.parent / \ @@ -95,8 +96,8 @@ def handle_segmented_image(self, image): image_array = np.frombuffer(image.data, dtype=np.uint8) image_array = image_array.reshape((image.height, image.width, -1)) image = rgb2id(image_array) - mask = np.ma.masked_outside(image, self.traffic_light_id * 1000, - (self.traffic_light_id + 1) * 1000 - 1) + mask = np.ma.masked_inside(image, self.traffic_light_id * 1000, + (self.traffic_light_id + 1) * 1000 - 1) mask = mask.mask tl_image = np.zeros(image.shape) @@ -110,8 +111,7 @@ def handle_segmented_image(self, image): msg.encoding = "rgb8" msg.is_bigendian = 0 msg.step = 1280 * 3 - msg.data = tl_image - + msg.data = id2rgb(tl_image).tobytes() self.snip_publisher.publish(msg) if not mask.any(): From 774107eca277cf60230ef7fb2e11bebe547cf974 Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Thu, 23 Mar 2023 14:58:12 +0100 Subject: [PATCH 10/15] feat(#218): Added segmentation camera and changed to carla 9.14 --- build/docker-compose.yml | 8 +-- build/docker/agent/Dockerfile | 2 +- code/agent/config/dev_objects.json | 25 +++++++++ code/agent/src/agent/agent.py | 4 ++ code/perception/src/TLDNode.py | 81 ++++++++++++++++++++++++++++-- 5 files changed, 111 insertions(+), 9 deletions(-) diff --git a/build/docker-compose.yml b/build/docker-compose.yml index 4580d9ea..d61960e9 100644 --- a/build/docker-compose.yml +++ b/build/docker-compose.yml @@ -20,8 +20,8 @@ services: carla-simulator: command: /bin/bash CarlaUE4.sh -quality-level=Epic -world-port=2000 -resx=800 -resy=600 # Use this image version to enable instance segmentation cameras: (it does not match the leaderboard version) - # image: carlasim/carla:0.9.14 - image: ghcr.io/nylser/carla:leaderboard + image: carlasim/carla:0.9.14 +# image: ghcr.io/nylser/carla:leaderboard init: true expose: - 2000 @@ -54,8 +54,8 @@ services: tty: true shm_size: 2gb #command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/opt/leaderboard/leaderboard/autoagents/npc_agent.py --host=carla-simulator --track=SENSORS" - #command: bash -c "sleep 10 && roslaunch agent/launch/dev.launch" - command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/workspace/code/agent/src/agent/agent.py --host=carla-simulator --track=MAP" + command: bash -c "sleep 10 && roslaunch agent/launch/dev.launch" + #command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/workspace/code/agent/src/agent/agent.py --host=carla-simulator --track=MAP" logging: driver: "local" environment: diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 4cab6ea2..70cdd94d 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -5,7 +5,7 @@ # Then, uncomment this line and the COPY --from=carla line to build the image. # FROM ghcr.io/nylser/carla:leaderboard as carla # Use this image to enable instance segmentation cameras -# FROM carlasim/carla:0.9.14 as carla +ROM carlasim/carla:0.9.14 as carla # supply the base image with an environment supporting ROS UI via x11 FROM osrf/ros:noetic-desktop-full-focal diff --git a/code/agent/config/dev_objects.json b/code/agent/config/dev_objects.json index 09995008..cd08df49 100644 --- a/code/agent/config/dev_objects.json +++ b/code/agent/config/dev_objects.json @@ -43,6 +43,31 @@ } ] }, + { + "type": "sensor.camera.instance_segmentation", + "id": "Instance_Center", + "spawn_point": { + "x": 0.0, + "y": 0.0, + "z": 1.70, + "roll": 0.0, + "pitch": 0.0, + "yaw": 0.0, + "lens_circle_multiplier": 3.0, + "lens_circle_falloff": 3.0, + "chromatic_aberration_intensity": 0.5, + "chromatic_aberration_offset": 0.0 + }, + "image_size_x": 1280, + "image_size_y": 720, + "fov": 100, + "attached_objects": [ + { + "type": "actor.pseudo.control", + "id": "control" + } + ] + }, { "type": "sensor.camera.rgb", "id": "Left", diff --git a/code/agent/src/agent/agent.py b/code/agent/src/agent/agent.py index 46d06855..0463935a 100755 --- a/code/agent/src/agent/agent.py +++ b/code/agent/src/agent/agent.py @@ -25,6 +25,10 @@ def sensors(self): {'type': 'sensor.camera.rgb', 'id': 'Center', 'x': 0.7, 'y': 0.0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0, 'width': 300, 'height': 200, 'fov': 100}, + {'type': 'sensor.camera.instance_segmentation', + 'id': 'Instance_Center', + 'x': 0.7, 'y': 0.0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, + 'yaw': 0.0, 'width': 300, 'height': 200, 'fov': 100}, {'type': 'sensor.lidar.ray_cast', 'id': 'LIDAR', 'x': 0.7, 'y': -0.4, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': -45.0}, diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 4d66e2d2..728b15d3 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -10,7 +10,7 @@ import cv2 from traffic_light_detection.src.traffic_light_detection.\ traffic_light_inference import TrafficLightInference -from panoptic_segmentation.preparation.labels import name2label +from panoptic_segmentation.preparation.labels import name2label, id2label from panoptic_segmentation.datasets.panoptic_dataset import rgb2id from panopticapi.utils import id2rgb @@ -54,6 +54,12 @@ def setup_subscriptions(self): self.camera_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_image, + topic=f"/carla/{self.role_name}/Instance_{self.side}/image", + qos_profile=1 + ) + self.instance_sub = self.new_subscription( + msg_type=numpy_msg(Image), + callback=self.handle_instance_image, topic=f"/carla/{self.role_name}/{self.side}/image", qos_profile=1 ) @@ -90,7 +96,74 @@ def handle_image(self, image): interpolation=cv2.INTER_NEAREST) self.image = image_array + def handle_instance_image(self, image): + self.loginfo(f"TLDNode got segmented image from Camera" + f"{self.side}") + image_array = np.frombuffer(image.data, dtype=np.uint8) + image_array = image_array.reshape((image.height, image.width, -1)) + image_array = image_array[:, :, 3] + + panoptic = np.zeros(image_array.shape, dtype=np.uint8) + formatted = image_array.reshape(-1, image_array.shape[2]) + segmentIds = np.unique(formatted, axis=0) + instance_ids = np.zeros((max(segmentIds[:, 0]) + 1), dtype=np.uint8) + for segmentId in segmentIds: + semanticId = segmentId[0] + labelInfo = id2label[semanticId] + if labelInfo.hasInstances: + instance_id = 1000 * segmentId[0] \ + + instance_ids[segmentId[0]] + instance_ids[segmentId[0]] += 1 + else: + instance_id = segmentId[0] + + if labelInfo.ignoreInEval: + continue + mask = image_array == segmentId + mask = mask.all(axis=2) + color = [instance_id % 256, instance_id // 256, + instance_id // 256 // 256] + panoptic[mask] = color + image = rgb2id(panoptic) + + mask = np.ma.masked_inside(image, self.traffic_light_id * 1000, + (self.traffic_light_id + 1) * 1000 - 1) + mask = mask.mask + + tl_image = np.zeros(image.shape) + tl_image[mask] = image[mask] + msg = Image() + msg.header.stamp = roscomp.ros_timestamp( + self.get_time(), from_sec=True) + msg.header.frame_id = "map" + msg.height = 720 + msg.width = 1280 + msg.encoding = "rgb8" + msg.is_bigendian = 0 + msg.step = 1280 * 3 + msg.data = id2rgb(tl_image).tobytes() + self.snip_publisher.publish(msg) + + indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, + tl_image.shape[1] // 3: + 2 * (tl_image.shape[1] // 3)]) + + if len(indices) == 0: + return + upper_left = [min(indices[0]), min(indices[1])] + lower_right = [max(indices[0]), max(indices[1])] + + traffic_light = self.image[upper_left[0]:lower_right[0], + upper_left[1]:lower_right[1]] + classification = self.predict(traffic_light) + + # construct the message + self.class_publisher.publish(str(classification)) + self.loginfo(f"TLDNode classified traffic light " + f"{self.side}") + def handle_segmented_image(self, image): + return self.loginfo(f"TLDNode got segmented image from EfficientPS " f"{self.side}") image_array = np.frombuffer(image.data, dtype=np.uint8) @@ -114,12 +187,12 @@ def handle_segmented_image(self, image): msg.data = id2rgb(tl_image).tobytes() self.snip_publisher.publish(msg) - if not mask.any(): - return - indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, tl_image.shape[1] // 3: 2 * (tl_image.shape[1] // 3)]) + + if len(indices) == 0: + return upper_left = [min(indices[0]), min(indices[1])] lower_right = [max(indices[0]), max(indices[1])] From 452109323b542e3c4cb0b27df2904fe1f9e85e35 Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Thu, 23 Mar 2023 15:11:42 +0100 Subject: [PATCH 11/15] feat(#218): Fixed typo --- build/docker/agent/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 70cdd94d..1d8d8e85 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -5,7 +5,7 @@ # Then, uncomment this line and the COPY --from=carla line to build the image. # FROM ghcr.io/nylser/carla:leaderboard as carla # Use this image to enable instance segmentation cameras -ROM carlasim/carla:0.9.14 as carla +FROM carlasim/carla:0.9.14 as carla # supply the base image with an environment supporting ROS UI via x11 FROM osrf/ros:noetic-desktop-full-focal From ed31b20b99cb9a15732a4b6e450037cef07232aa Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Sat, 25 Mar 2023 15:07:53 +0100 Subject: [PATCH 12/15] feat(#218): Fixed wrong method call and improved code --- code/perception/src/TLDNode.py | 120 ++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 53 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 728b15d3..8f059be9 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -1,18 +1,20 @@ #!/usr/bin/env python3 import pathlib + +import cv2 import numpy as np import ros_compatibility as roscomp -from rospy.numpy_msg import numpy_msg +from panopticapi.utils import id2rgb from ros_compatibility.node import CompatibleNode +from rospy.numpy_msg import numpy_msg from sensor_msgs.msg import Image from std_msgs.msg import String -import cv2 -from traffic_light_detection.src.traffic_light_detection.\ - traffic_light_inference import TrafficLightInference -from panoptic_segmentation.preparation.labels import name2label, id2label + from panoptic_segmentation.datasets.panoptic_dataset import rgb2id -from panopticapi.utils import id2rgb +from panoptic_segmentation.preparation.labels import name2label, id2label +from traffic_light_detection.src.traffic_light_detection. \ + traffic_light_inference import TrafficLightInference MODEL_PATH = pathlib.Path( __file__).parent.parent / \ @@ -27,6 +29,7 @@ class TLDNode(CompatibleNode): def __init__(self, name, **kwargs): super().__init__(name, **kwargs) + self.instance_sub = None self.snip_publisher = None self.class_publisher = None self.loginfo("Initializing traffic light detection node...") @@ -54,13 +57,13 @@ def setup_subscriptions(self): self.camera_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_image, - topic=f"/carla/{self.role_name}/Instance_{self.side}/image", + topic=f"/carla/{self.role_name}/{self.side}/image", qos_profile=1 ) self.instance_sub = self.new_subscription( msg_type=numpy_msg(Image), callback=self.handle_instance_image, - topic=f"/carla/{self.role_name}/{self.side}/image", + topic=f"/carla/{self.role_name}/Instance_{self.side}/image", qos_profile=1 ) @@ -101,7 +104,7 @@ def handle_instance_image(self, image): f"{self.side}") image_array = np.frombuffer(image.data, dtype=np.uint8) image_array = image_array.reshape((image.height, image.width, -1)) - image_array = image_array[:, :, 3] + image_array = image_array[:, :, :3] panoptic = np.zeros(image_array.shape, dtype=np.uint8) formatted = image_array.reshape(-1, image_array.shape[2]) @@ -126,12 +129,11 @@ def handle_instance_image(self, image): panoptic[mask] = color image = rgb2id(panoptic) - mask = np.ma.masked_inside(image, self.traffic_light_id * 1000, - (self.traffic_light_id + 1) * 1000 - 1) - mask = mask.mask + tld_id = self.traffic_light_id + tl_image = np.ma.masked_inside(image, tld_id * 1000, + (tld_id + 1) * 1000 - 1) \ + .filled(0) - tl_image = np.zeros(image.shape) - tl_image[mask] = image[mask] msg = Image() msg.header.stamp = roscomp.ros_timestamp( self.get_time(), from_sec=True) @@ -144,23 +146,30 @@ def handle_instance_image(self, image): msg.data = id2rgb(tl_image).tobytes() self.snip_publisher.publish(msg) - indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, - tl_image.shape[1] // 3: - 2 * (tl_image.shape[1] // 3)]) - - if len(indices) == 0: - return - upper_left = [min(indices[0]), min(indices[1])] - lower_right = [max(indices[0]), max(indices[1])] - - traffic_light = self.image[upper_left[0]:lower_right[0], - upper_left[1]:lower_right[1]] - classification = self.predict(traffic_light) - - # construct the message - self.class_publisher.publish(str(classification)) - self.loginfo(f"TLDNode classified traffic light " - f"{self.side}") + areas = {} + for instance in np.unique(tl_image): + inst = np.ma.masked_not_equal(tl_image, instance).filled(0) + indices = np.nonzero(inst[0:inst.shape[0] // 2, + inst.shape[1] // 4: + 3 * (inst.shape[1] // 4)]) + upper_left = [min(indices[0]), min(indices[1])] + lower_right = [max(indices[0]), max(indices[1])] + areas[str(instance)] = [(lower_right[0] - upper_left[0]) * + (lower_right[1] - upper_left[1]), + upper_left, + lower_right] + if len(areas) > 0: + maximum = max(areas, key=areas.get) + upper_left = areas[maximum][1] + lower_right = areas[maximum][2] + traffic_light = self.image[upper_left[0]:lower_right[0], + upper_left[1]:lower_right[1]] + classification = self.predict(traffic_light) + + # construct the message + self.class_publisher.publish(str(classification)) + self.loginfo(f"TLDNode classified traffic light " + f"{self.side}") def handle_segmented_image(self, image): return @@ -169,12 +178,10 @@ def handle_segmented_image(self, image): image_array = np.frombuffer(image.data, dtype=np.uint8) image_array = image_array.reshape((image.height, image.width, -1)) image = rgb2id(image_array) - mask = np.ma.masked_inside(image, self.traffic_light_id * 1000, - (self.traffic_light_id + 1) * 1000 - 1) - mask = mask.mask + tl_image = np.ma.masked_inside(image, self.traffic_light_id * 1000, + (self.traffic_light_id + 1) * 1000 - 1)\ + .filled(0) - tl_image = np.zeros(image.shape) - tl_image[mask] = image[mask] msg = Image() msg.header.stamp = roscomp.ros_timestamp( self.get_time(), from_sec=True) @@ -187,23 +194,30 @@ def handle_segmented_image(self, image): msg.data = id2rgb(tl_image).tobytes() self.snip_publisher.publish(msg) - indices = np.nonzero(tl_image[0:tl_image.shape[0] // 2, - tl_image.shape[1] // 3: - 2 * (tl_image.shape[1] // 3)]) - - if len(indices) == 0: - return - upper_left = [min(indices[0]), min(indices[1])] - lower_right = [max(indices[0]), max(indices[1])] - - traffic_light = self.image[upper_left[0]:lower_right[0], - upper_left[1]:lower_right[1]] - classification = self.predict(traffic_light) - - # construct the message - self.class_publisher.publish(str(classification)) - self.loginfo(f"TLDNode classified traffic light " - f"{self.side}") + areas = {} + for instance in np.unique(tl_image): + inst = np.ma.masked_not_equal(tl_image, instance).filled(0) + indices = np.nonzero(inst[0:inst.shape[0] // 2, + inst.shape[1] // 4: + 3 * (inst.shape[1] // 4)]) + upper_left = [min(indices[0]), min(indices[1])] + lower_right = [max(indices[0]), max(indices[1])] + areas[str(instance)] = [(lower_right[0] - upper_left[0]) * + (lower_right[1] - upper_left[1]), + upper_left, + lower_right] + if len(areas) > 0: + maximum = max(areas, key=areas.get) + upper_left = areas[maximum][1] + lower_right = areas[maximum][2] + traffic_light = self.image[upper_left[0]:lower_right[0], + upper_left[1]:lower_right[1]] + classification = self.predict(traffic_light) + + # construct the message + self.class_publisher.publish(str(classification)) + self.loginfo(f"TLDNode classified traffic light " + f"{self.side}") def run(self): self.spin() From d73c7b3b6ddbd49b00945d0cd0ceff2a533cc3ac Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 28 Mar 2023 15:08:39 +0200 Subject: [PATCH 13/15] feat(#218): Removed segment camera and returned to 9.13 and leaderboard --- build/docker-compose.yml | 8 ++++---- build/docker/agent/Dockerfile | 4 ++-- code/agent/config/dev_objects.json | 25 ------------------------- code/agent/src/agent/agent.py | 4 ---- 4 files changed, 6 insertions(+), 35 deletions(-) diff --git a/build/docker-compose.yml b/build/docker-compose.yml index d61960e9..04183b2c 100644 --- a/build/docker-compose.yml +++ b/build/docker-compose.yml @@ -20,8 +20,8 @@ services: carla-simulator: command: /bin/bash CarlaUE4.sh -quality-level=Epic -world-port=2000 -resx=800 -resy=600 # Use this image version to enable instance segmentation cameras: (it does not match the leaderboard version) - image: carlasim/carla:0.9.14 -# image: ghcr.io/nylser/carla:leaderboard +# image: carlasim/carla:0.9.14 + image: ghcr.io/nylser/carla:leaderboard init: true expose: - 2000 @@ -54,8 +54,8 @@ services: tty: true shm_size: 2gb #command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/opt/leaderboard/leaderboard/autoagents/npc_agent.py --host=carla-simulator --track=SENSORS" - command: bash -c "sleep 10 && roslaunch agent/launch/dev.launch" - #command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/workspace/code/agent/src/agent/agent.py --host=carla-simulator --track=MAP" + #command: bash -c "sleep 10 && roslaunch agent/launch/dev.launch" + command: bash -c "sleep 10 && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=/opt/leaderboard/data/routes_devtest.xml --agent=/workspace/code/agent/src/agent/agent.py --host=carla-simulator --track=MAP" logging: driver: "local" environment: diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 1d8d8e85..bc8931aa 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -3,9 +3,9 @@ # This is commented out because of the large image download necessary to build this image otherwise. # If the PythonAPI/carla version changes, one can comment out the Download Carla PythonAPI line below. # Then, uncomment this line and the COPY --from=carla line to build the image. -# FROM ghcr.io/nylser/carla:leaderboard as carla +FROM ghcr.io/nylser/carla:leaderboard as carla # Use this image to enable instance segmentation cameras -FROM carlasim/carla:0.9.14 as carla +# FROM carlasim/carla:0.9.14 as carla # supply the base image with an environment supporting ROS UI via x11 FROM osrf/ros:noetic-desktop-full-focal diff --git a/code/agent/config/dev_objects.json b/code/agent/config/dev_objects.json index cd08df49..09995008 100644 --- a/code/agent/config/dev_objects.json +++ b/code/agent/config/dev_objects.json @@ -43,31 +43,6 @@ } ] }, - { - "type": "sensor.camera.instance_segmentation", - "id": "Instance_Center", - "spawn_point": { - "x": 0.0, - "y": 0.0, - "z": 1.70, - "roll": 0.0, - "pitch": 0.0, - "yaw": 0.0, - "lens_circle_multiplier": 3.0, - "lens_circle_falloff": 3.0, - "chromatic_aberration_intensity": 0.5, - "chromatic_aberration_offset": 0.0 - }, - "image_size_x": 1280, - "image_size_y": 720, - "fov": 100, - "attached_objects": [ - { - "type": "actor.pseudo.control", - "id": "control" - } - ] - }, { "type": "sensor.camera.rgb", "id": "Left", diff --git a/code/agent/src/agent/agent.py b/code/agent/src/agent/agent.py index 0463935a..46d06855 100755 --- a/code/agent/src/agent/agent.py +++ b/code/agent/src/agent/agent.py @@ -25,10 +25,6 @@ def sensors(self): {'type': 'sensor.camera.rgb', 'id': 'Center', 'x': 0.7, 'y': 0.0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0, 'width': 300, 'height': 200, 'fov': 100}, - {'type': 'sensor.camera.instance_segmentation', - 'id': 'Instance_Center', - 'x': 0.7, 'y': 0.0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, - 'yaw': 0.0, 'width': 300, 'height': 200, 'fov': 100}, {'type': 'sensor.lidar.ray_cast', 'id': 'LIDAR', 'x': 0.7, 'y': -0.4, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': -45.0}, From 8a4d7277a7a8028a1074932e887f065e5a38c09d Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 28 Mar 2023 15:20:59 +0200 Subject: [PATCH 14/15] feat(#218): commented code for instance camera images in TLDNode.py --- code/perception/src/TLDNode.py | 158 +++++++++++++++++---------------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/code/perception/src/TLDNode.py b/code/perception/src/TLDNode.py index 8f059be9..483eac59 100755 --- a/code/perception/src/TLDNode.py +++ b/code/perception/src/TLDNode.py @@ -12,7 +12,7 @@ from std_msgs.msg import String from panoptic_segmentation.datasets.panoptic_dataset import rgb2id -from panoptic_segmentation.preparation.labels import name2label, id2label +from panoptic_segmentation.preparation.labels import name2label from traffic_light_detection.src.traffic_light_detection. \ traffic_light_inference import TrafficLightInference @@ -60,12 +60,13 @@ def setup_subscriptions(self): topic=f"/carla/{self.role_name}/{self.side}/image", qos_profile=1 ) - self.instance_sub = self.new_subscription( - msg_type=numpy_msg(Image), - callback=self.handle_instance_image, - topic=f"/carla/{self.role_name}/Instance_{self.side}/image", - qos_profile=1 - ) + """Include this code to compute the output of a segmentation camera""" + # self.instance_sub = self.new_subscription( + # msg_type=numpy_msg(Image), + # callback=self.handle_instance_image, + # topic=f"/carla/{self.role_name}/Instance_{self.side}/image", + # qos_profile=1 + # ) def setup_publishers(self): self.class_publisher = self.new_publisher( @@ -100,79 +101,80 @@ def handle_image(self, image): self.image = image_array def handle_instance_image(self, image): - self.loginfo(f"TLDNode got segmented image from Camera" - f"{self.side}") - image_array = np.frombuffer(image.data, dtype=np.uint8) - image_array = image_array.reshape((image.height, image.width, -1)) - image_array = image_array[:, :, :3] - - panoptic = np.zeros(image_array.shape, dtype=np.uint8) - formatted = image_array.reshape(-1, image_array.shape[2]) - segmentIds = np.unique(formatted, axis=0) - instance_ids = np.zeros((max(segmentIds[:, 0]) + 1), dtype=np.uint8) - for segmentId in segmentIds: - semanticId = segmentId[0] - labelInfo = id2label[semanticId] - if labelInfo.hasInstances: - instance_id = 1000 * segmentId[0] \ - + instance_ids[segmentId[0]] - instance_ids[segmentId[0]] += 1 - else: - instance_id = segmentId[0] - - if labelInfo.ignoreInEval: - continue - mask = image_array == segmentId - mask = mask.all(axis=2) - color = [instance_id % 256, instance_id // 256, - instance_id // 256 // 256] - panoptic[mask] = color - image = rgb2id(panoptic) - - tld_id = self.traffic_light_id - tl_image = np.ma.masked_inside(image, tld_id * 1000, - (tld_id + 1) * 1000 - 1) \ - .filled(0) - - msg = Image() - msg.header.stamp = roscomp.ros_timestamp( - self.get_time(), from_sec=True) - msg.header.frame_id = "map" - msg.height = 720 - msg.width = 1280 - msg.encoding = "rgb8" - msg.is_bigendian = 0 - msg.step = 1280 * 3 - msg.data = id2rgb(tl_image).tobytes() - self.snip_publisher.publish(msg) - - areas = {} - for instance in np.unique(tl_image): - inst = np.ma.masked_not_equal(tl_image, instance).filled(0) - indices = np.nonzero(inst[0:inst.shape[0] // 2, - inst.shape[1] // 4: - 3 * (inst.shape[1] // 4)]) - upper_left = [min(indices[0]), min(indices[1])] - lower_right = [max(indices[0]), max(indices[1])] - areas[str(instance)] = [(lower_right[0] - upper_left[0]) * - (lower_right[1] - upper_left[1]), - upper_left, - lower_right] - if len(areas) > 0: - maximum = max(areas, key=areas.get) - upper_left = areas[maximum][1] - lower_right = areas[maximum][2] - traffic_light = self.image[upper_left[0]:lower_right[0], - upper_left[1]:lower_right[1]] - classification = self.predict(traffic_light) - - # construct the message - self.class_publisher.publish(str(classification)) - self.loginfo(f"TLDNode classified traffic light " - f"{self.side}") + pass + """Include this code to compute the output of a segmentation camera""" + # self.loginfo(f"TLDNode got segmented image from Camera" + # f"{self.side}") + # image_array = np.frombuffer(image.data, dtype=np.uint8) + # image_array = image_array.reshape((image.height, image.width, -1)) + # image_array = image_array[:, :, :3] + # + # panoptic = np.zeros(image_array.shape, dtype=np.uint8) + # formatted = image_array.reshape(-1, image_array.shape[2]) + # segmentIds = np.unique(formatted, axis=0) + # instance_ids = np.zeros((max(segmentIds[:, 0]) + 1), dtype=np.uint8) + # for segmentId in segmentIds: + # semanticId = segmentId[0] + # labelInfo = id2label[semanticId] + # if labelInfo.hasInstances: + # instance_id = 1000 * segmentId[0] \ + # + instance_ids[segmentId[0]] + # instance_ids[segmentId[0]] += 1 + # else: + # instance_id = segmentId[0] + # + # if labelInfo.ignoreInEval: + # continue + # mask = image_array == segmentId + # mask = mask.all(axis=2) + # color = [instance_id % 256, instance_id // 256, + # instance_id // 256 // 256] + # panoptic[mask] = color + # image = rgb2id(panoptic) + # + # tld_id = self.traffic_light_id + # tl_image = np.ma.masked_inside(image, tld_id * 1000, + # (tld_id + 1) * 1000 - 1) \ + # .filled(0) + # + # msg = Image() + # msg.header.stamp = roscomp.ros_timestamp( + # self.get_time(), from_sec=True) + # msg.header.frame_id = "map" + # msg.height = 720 + # msg.width = 1280 + # msg.encoding = "rgb8" + # msg.is_bigendian = 0 + # msg.step = 1280 * 3 + # msg.data = id2rgb(tl_image).tobytes() + # self.snip_publisher.publish(msg) + # + # areas = {} + # for instance in np.unique(tl_image): + # inst = np.ma.masked_not_equal(tl_image, instance).filled(0) + # indices = np.nonzero(inst[0:inst.shape[0] // 2, + # inst.shape[1] // 4: + # 3 * (inst.shape[1] // 4)]) + # upper_left = [min(indices[0]), min(indices[1])] + # lower_right = [max(indices[0]), max(indices[1])] + # areas[str(instance)] = [(lower_right[0] - upper_left[0]) * + # (lower_right[1] - upper_left[1]), + # upper_left, + # lower_right] + # if len(areas) > 0: + # maximum = max(areas, key=areas.get) + # upper_left = areas[maximum][1] + # lower_right = areas[maximum][2] + # traffic_light = self.image[upper_left[0]:lower_right[0], + # upper_left[1]:lower_right[1]] + # classification = self.predict(traffic_light) + # + # # construct the message + # self.class_publisher.publish(str(classification)) + # self.loginfo(f"TLDNode classified traffic light " + # f"{self.side}") def handle_segmented_image(self, image): - return self.loginfo(f"TLDNode got segmented image from EfficientPS " f"{self.side}") image_array = np.frombuffer(image.data, dtype=np.uint8) From c1c0e1dca673902f9e4fe2cc5932192ed078111b Mon Sep 17 00:00:00 2001 From: MarcoRiedenauer Date: Tue, 28 Mar 2023 15:38:38 +0200 Subject: [PATCH 15/15] feat(#218): Added doc for TLDNode --- doc/00_assets/TLDNode.png | Bin 0 -> 121219 bytes .../05_traffic_light_detection.md | 34 ++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 doc/00_assets/TLDNode.png create mode 100644 doc/06_perception/05_traffic_light_detection.md diff --git a/doc/00_assets/TLDNode.png b/doc/00_assets/TLDNode.png new file mode 100644 index 0000000000000000000000000000000000000000..2ed63fb9b9ccf7494634b18f435132a83b9410f4 GIT binary patch literal 121219 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

UidL+)w$>e>OG?7FPN#5%id( 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 literal 0 HcmV?d00001 diff --git a/doc/06_perception/05_traffic_light_detection.md b/doc/06_perception/05_traffic_light_detection.md new file mode 100644 index 00000000..4a545611 --- /dev/null +++ b/doc/06_perception/05_traffic_light_detection.md @@ -0,0 +1,34 @@ +# Traffic Light Detection + +**Summary:** This document gives a short overview about the traffic light detection module. + +--- + +## Author + +Marco Riedenauer + +## Date + +28.03.2023 + + +* [Dataset structure](#dataset-structure) + * [Author](#author) + * [Date](#date) + * [TLDNode](#tldnode) + + +## TLDNode + +The TLDNode is responsible for receiving segmented images from EfficientPS or an instance segmentation camera, snipping +the detected traffic lights out of the image and classify them. + +![TLDNode](../00_assets/TLDNode.png) + +The first step is to mask out all pixels from the segmented image, which aren't classified as traffic light. In the +upper half and the segments 2/4 to 3/4 from left to right of the image, the biggest traffic light is searched and +snipped out of the image. +The same area is snipped out of the RGB image to receive the traffic light as RGB image. This traffic light is fed in +our [model](../../code/perception/src/traffic_light_detection/src/traffic_light_detection/traffic_light_inference.py) +for traffic light classification.