Skip to content

Commit f71fb87

Browse files
tsampazkcharsymestefaniapedrazzi
authored
ROS1 updates and fixes for several nodes (opendr-eu#281)
* Updated, cleaned up and added argparse to ROS1 pose estimation node * Added additional information for pose estimation node documentation * Improved wording in pose estimation ros docs * Minor comment improvement * Fix typo * Updated, cleaned up and added argparse to ROS1 fall detection node * Added box id type conversion that caused error in object det2d centernet * Updated, cleaned up and added argparse to ROS1 object detection 2d centernet node * Updated, cleaned up and added argparse to ROS1 object detection 2d ssd node * Updated, cleaned up and added argparse to ROS1 object detection 2d yolov3 node * Minor typo fix * Updated, cleaned up and added argparse to ROS1 object detection 2d DETR node * Updated, cleaned up and added argparse to ROS1 face detection retinaface node * Updated, cleaned up and added argparse to ROS1 semantic segmentation bisenet node * Increased buffer size for fall detection and pose estimation to minimize delay * Updated, cleaned up and added argparse to ROS1 face recognition node * Fixed minor type conversion typo in bridge * Sem seg bisenet now outputs class ids heatmap and separate visualization heatmap with improved colors and legend * Added custom opendr pose and keypoint messages on ros_bridge * Modified opendr_bridge from/to ros pose to use new messages and doc update * ROS1 pose node now uses new custom pose ros message * Enhanced pose __str__ method to return pose id and confidence * Update human_model_generation_client.py * Added missing space to pose out_string Co-authored-by: Stefania Pedrazzi <[email protected]> * Fixed indentation on CMakeLists.txt Co-authored-by: Stefania Pedrazzi <[email protected]> Co-authored-by: charsyme <[email protected]> Co-authored-by: Stefania Pedrazzi <[email protected]>
1 parent 3dcab24 commit f71fb87

18 files changed

+970
-602
lines changed

docs/reference/rosbridge.md

+10-7
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,28 @@ ROSBridge.from_ros_pose(self,
5959
ros_pose)
6060
```
6161

62-
Converts a ROS pose into an OpenDR pose.
62+
Converts an OpenDRPose2D message into an OpenDR Pose.
6363

6464
Parameters:
6565

66-
- **message**: *ros_bridge.msg.Pose*\
67-
ROS pose to be converted into an OpenDR pose.
66+
- **ros_pose**: *ros_bridge.msg.OpenDRPose2D*\
67+
ROS pose to be converted into an OpenDR Pose.
6868

6969
#### `ROSBridge.to_ros_pose`
7070

7171
```python
7272
ROSBridge.to_ros_pose(self,
73-
ros_pose)
73+
pose)
7474
```
75-
Converts an OpenDR pose into a ROS pose.
75+
Converts an OpenDR Pose into a OpenDRPose2D msg that can carry the same information, i.e. a list of keypoints,
76+
the pose detection confidence and the pose id.
77+
Each keypoint is represented as an OpenDRPose2DKeypoint with x, y pixel position on input image with (0, 0)
78+
being the top-left corner.
7679

7780
Parameters:
7881

79-
- **message**: *engine.target.Pose*\
80-
OpenDR pose to be converted to ROS pose.
82+
- **pose**: *engine.target.Pose*\
83+
OpenDR Pose to be converted to ROS OpenDRPose2D.
8184

8285

8386
#### `ROSBridge.to_ros_category`

projects/opendr_ws/src/perception/README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,25 @@ Assuming that you have already [activated the OpenDR environment](../../../../do
3131
rosrun usb_cam usb_cam_node
3232
```
3333

34-
2. You are then ready to start the pose detection node
34+
2. You are then ready to start the pose detection node (use `-h` to print out help for various arguments)
3535

3636
```shell
3737
rosrun perception pose_estimation.py
3838
```
3939

4040
3. You can examine the annotated image stream using `rqt_image_view` (select the topic `/opendr/image_pose_annotated`) or
41-
`rostopic echo /opendr/poses`
41+
`rostopic echo /opendr/poses`.
42+
43+
Note that to use the pose messages properly, you need to create an appropriate subscriber that will convert the ROS pose messages back to OpenDR poses which you can access as described in the [documentation](https://github.com/opendr-eu/opendr/blob/master/docs/reference/engine-target.md#posekeypoints-confidence):
44+
```python
45+
...
46+
rospy.Subscriber("opendr/poses", Detection2DArray, self.callback)
47+
...
48+
def callback(self, data):
49+
opendr_pose = self.bridge.from_ros_pose(data)
50+
print(opendr_pose)
51+
print(opendr_pose['r_eye'])
52+
```
4253

4354
## Fall Detection ROS Node
4455
Assuming that you have already [activated the OpenDR environment](../../../../docs/reference/installation.md), [built your workspace](../../README.md) and started roscore (i.e., just run `roscore`), then you can

projects/opendr_ws/src/perception/scripts/face_detection_retinaface.py

+83-68
Original file line numberDiff line numberDiff line change
@@ -13,115 +13,130 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
import rospy
16+
import argparse
1717
import mxnet as mx
18+
19+
import rospy
1820
from vision_msgs.msg import Detection2DArray
1921
from sensor_msgs.msg import Image as ROS_Image
2022
from opendr_bridge import ROSBridge
23+
24+
from opendr.engine.data import Image
2125
from opendr.perception.object_detection_2d import RetinaFaceLearner
2226
from opendr.perception.object_detection_2d import draw_bounding_boxes
23-
from opendr.engine.data import Image
2427

2528

2629
class FaceDetectionNode:
27-
def __init__(self, input_image_topic="/usb_cam/image_raw", output_image_topic="/opendr/image_boxes_annotated",
28-
face_detections_topic="/opendr/faces", device="cuda", backbone="resnet"):
30+
31+
def __init__(self, input_rgb_image_topic="/usb_cam/image_raw",
32+
output_rgb_image_topic="/opendr/image_faces_annotated", detections_topic="/opendr/faces",
33+
device="cuda", backbone="resnet"):
2934
"""
30-
Creates a ROS Node for face detection
31-
:param input_image_topic: Topic from which we are reading the input image
32-
:type input_image_topic: str
33-
:param output_image_topic: Topic to which we are publishing the annotated image (if None, we are not publishing
34-
annotated image)
35-
:type output_image_topic: str
36-
:param face_detections_topic: Topic to which we are publishing the annotations (if None, we are not publishing
37-
annotated pose annotations)
38-
:type face_detections_topic: str
35+
Creates a ROS Node for face detection with Retinaface.
36+
:param input_rgb_image_topic: Topic from which we are reading the input image
37+
:type input_rgb_image_topic: str
38+
:param output_rgb_image_topic: Topic to which we are publishing the annotated image (if None, no annotated
39+
image is published)
40+
:type output_rgb_image_topic: str
41+
:param detections_topic: Topic to which we are publishing the annotations (if None, no face detection message
42+
is published)
43+
:type detections_topic: str
3944
:param device: device on which we are running inference ('cpu' or 'cuda')
4045
:type device: str
41-
:param backbone: retinaface backbone, options are ('mnet' and 'resnet'), where 'mnet' detects masked faces as well
46+
:param backbone: retinaface backbone, options are either 'mnet' or 'resnet',
47+
where 'mnet' detects masked faces as well
4248
:type backbone: str
4349
"""
50+
self.input_rgb_image_topic = input_rgb_image_topic
4451

45-
# Initialize the face detector
46-
self.face_detector = RetinaFaceLearner(backbone=backbone, device=device)
47-
self.face_detector.download(path=".", verbose=True)
48-
self.face_detector.load("retinaface_{}".format(backbone))
49-
self.class_names = ["face", "masked_face"]
50-
51-
# Initialize OpenDR ROSBridge object
52-
self.bridge = ROSBridge()
53-
54-
# setup communications
55-
if output_image_topic is not None:
56-
self.image_publisher = rospy.Publisher(output_image_topic, ROS_Image, queue_size=10)
52+
if output_rgb_image_topic is not None:
53+
self.image_publisher = rospy.Publisher(output_rgb_image_topic, ROS_Image, queue_size=1)
5754
else:
5855
self.image_publisher = None
5956

60-
if face_detections_topic is not None:
61-
self.face_publisher = rospy.Publisher(face_detections_topic, Detection2DArray, queue_size=10)
57+
if detections_topic is not None:
58+
self.face_publisher = rospy.Publisher(detections_topic, Detection2DArray, queue_size=1)
6259
else:
6360
self.face_publisher = None
6461

65-
rospy.Subscriber(input_image_topic, ROS_Image, self.callback)
62+
self.bridge = ROSBridge()
63+
64+
# Initialize the face detector
65+
self.face_detector = RetinaFaceLearner(backbone=backbone, device=device)
66+
self.face_detector.download(path=".", verbose=True)
67+
self.face_detector.load("retinaface_{}".format(backbone))
68+
self.class_names = ["face", "masked_face"]
69+
70+
def listen(self):
71+
"""
72+
Start the node and begin processing input data.
73+
"""
74+
rospy.init_node('face_detection_node', anonymous=True)
75+
rospy.Subscriber(self.input_rgb_image_topic, ROS_Image, self.callback, queue_size=1, buff_size=10000000)
76+
rospy.loginfo("Face detection RetinaFace node started.")
77+
rospy.spin()
6678

6779
def callback(self, data):
6880
"""
69-
Callback that process the input data and publishes to the corresponding topics
70-
:param data: input message
81+
Callback that processes the input data and publishes to the corresponding topics.
82+
:param data: Input image message
7183
:type data: sensor_msgs.msg.Image
7284
"""
73-
7485
# Convert sensor_msgs.msg.Image into OpenDR Image
7586
image = self.bridge.from_ros_image(data, encoding='bgr8')
7687

77-
# Run pose estimation
88+
# Run face detection
7889
boxes = self.face_detector.infer(image)
7990

8091
# Get an OpenCV image back
8192
image = image.opencv()
82-
83-
# Convert detected boxes to ROS type and publish
84-
ros_boxes = self.bridge.to_ros_boxes(boxes)
93+
# Publish detections in ROS message
94+
ros_boxes = self.bridge.to_ros_boxes(boxes) # Convert to ROS boxes
8595
if self.face_publisher is not None:
8696
self.face_publisher.publish(ros_boxes)
87-
rospy.loginfo("Published face boxes")
8897

89-
# Annotate image and publish result
90-
# NOTE: converting back to OpenDR BoundingBoxList is unnecessary here,
91-
# only used to test the corresponding bridge methods
92-
odr_boxes = self.bridge.from_ros_boxes(ros_boxes)
93-
image = draw_bounding_boxes(image, odr_boxes, class_names=self.class_names)
9498
if self.image_publisher is not None:
95-
message = self.bridge.to_ros_image(Image(image), encoding='bgr8')
96-
self.image_publisher.publish(message)
97-
rospy.loginfo("Published annotated image")
99+
# Annotate image with face detection boxes
100+
image = draw_bounding_boxes(image, boxes, class_names=self.class_names)
101+
# Convert the annotated OpenDR image to ROS2 image message using bridge and publish it
102+
self.image_publisher.publish(self.bridge.to_ros_image(Image(image), encoding='bgr8'))
103+
104+
105+
def main():
106+
parser = argparse.ArgumentParser()
107+
parser.add_argument("-i", "--input_rgb_image_topic", help="Topic name for input rgb image",
108+
type=str, default="/usb_cam/image_raw")
109+
parser.add_argument("-o", "--output_rgb_image_topic", help="Topic name for output annotated rgb image",
110+
type=str, default="/opendr/image_faces_annotated")
111+
parser.add_argument("-d", "--detections_topic", help="Topic name for detection messages",
112+
type=str, default="/opendr/faces")
113+
parser.add_argument("--device", help="Device to use, either \"cpu\" or \"cuda\", defaults to \"cuda\"",
114+
type=str, default="cuda", choices=["cuda", "cpu"])
115+
parser.add_argument("--backbone",
116+
help="Retinaface backbone, options are either 'mnet' or 'resnet', where 'mnet' detects "
117+
"masked faces as well",
118+
type=str, default="resnet", choices=["resnet", "mnet"])
119+
args = parser.parse_args()
98120

99-
100-
if __name__ == '__main__':
101-
# Automatically run on GPU/CPU
102121
try:
103-
if mx.context.num_gpus() > 0:
104-
print("GPU found.")
105-
device = 'cuda'
106-
else:
122+
if args.device == "cuda" and mx.context.num_gpus() > 0:
123+
device = "cuda"
124+
elif args.device == "cuda":
107125
print("GPU not found. Using CPU instead.")
108-
device = 'cpu'
126+
device = "cpu"
127+
else:
128+
print("Using CPU.")
129+
device = "cpu"
109130
except:
110-
device = 'cpu'
131+
print("Using CPU.")
132+
device = "cpu"
111133

112-
# initialize ROS node
113-
rospy.init_node('opendr_face_detection', anonymous=True)
114-
rospy.loginfo("Face detection node started!")
134+
face_detection_node = FaceDetectionNode(device=device, backbone=args.backbone,
135+
input_rgb_image_topic=args.input_rgb_image_topic,
136+
output_rgb_image_topic=args.output_rgb_image_topic,
137+
detections_topic=args.detections_topic)
138+
face_detection_node.listen()
115139

116-
# get network backbone ("mnet" detects masked faces as well)
117-
backbone = rospy.get_param("~backbone", "resnet")
118-
input_image_topic = rospy.get_param("~input_image_topic", "/videofile/image_raw")
119140

120-
rospy.loginfo("Using backbone: {}".format(backbone))
121-
assert backbone in ["resnet", "mnet"], "backbone should be one of ['resnet', 'mnet']"
122-
123-
# created node object
124-
face_detection_node = FaceDetectionNode(device=device, backbone=backbone,
125-
input_image_topic=input_image_topic)
126-
# begin ROS communications
127-
rospy.spin()
141+
if __name__ == '__main__':
142+
main()

0 commit comments

Comments
 (0)