00001
00002
00003
00004
00005 import copy
00006 from jsk_topic_tools import ConnectionBasedTransport
00007 import message_filters as MF
00008 import numpy as np
00009 import rospy
00010 import tf2_ros
00011 import tf2_geometry_msgs
00012
00013 from geometry_msgs.msg import Point
00014 from geometry_msgs.msg import PoseStamped
00015 from jsk_recognition_msgs.msg import BoundingBoxArray
00016 from jsk_recognition_msgs.msg import ClassificationResult
00017 from jsk_recognition_msgs.msg import PeoplePoseArray
00018 from visualization_msgs.msg import Marker
00019 from visualization_msgs.msg import MarkerArray
00020
00021
00022 def find_pose(limb, msg):
00023 if isinstance(limb, list):
00024 for l in limb:
00025 p = find_pose(l, msg)
00026 if p is not None:
00027 return p
00028 return None
00029 try:
00030 idx = msg.limb_names.index(limb)
00031 return msg.poses[idx]
00032 except ValueError:
00033 return None
00034
00035
00036 def remove_slash(frame_id):
00037 if frame_id.startswith("/"):
00038 return frame_id[1:]
00039
00040
00041 class PointIt(ConnectionBasedTransport):
00042 """
00043 PointIt class object
00044 """
00045 def __init__(self):
00046 super(PointIt, self).__init__()
00047
00048 self.subscribers = []
00049 self.objects = []
00050
00051
00052 self.dist_threshold = rospy.get_param("~dist_threshold", 0.1)
00053 self.min_norm_threshold = rospy.get_param("~min_norm_threshold", 0.2)
00054
00055
00056 use_tf2_buffer_client = rospy.get_param("~use_tf2_buffer_client", True)
00057 if use_tf2_buffer_client:
00058 self.tfl = tf2_ros.BufferClient("/tf2_buffer_server")
00059 if not self.tfl.wait_for_server(rospy.Duration(10)):
00060 rospy.logerr("Waiting /tf2_buffer_server timed out.")
00061 use_tf2_buffer_client = False
00062 if not use_tf2_buffer_client:
00063 self.tfl = tf2_ros.Buffer()
00064
00065
00066 self.pub_bbox = self.advertise("~output", BoundingBoxArray, queue_size=1)
00067 self.pub_marker = self.advertise("~output/marker_array", MarkerArray, queue_size=1)
00068
00069 def subscribe(self):
00070 use_cls = rospy.get_param("~use_classification_result", False)
00071 if use_cls:
00072 self.subscribers = [
00073 MF.Subscriber("~input/boxes", BoundingBoxArray, queue_size=1),
00074 MF.Subscriber("~input/class", ClassificationResult, queue_size=1),
00075 ]
00076 if rospy.get_param("~approximate_sync", True):
00077 sync = MF.ApproximateTimeSynchronizer(
00078 self.subscribers,
00079 queue_size=rospy.get_param("~queue_size", 10),
00080 slop=rospy.get_param("~slop", 0.1),
00081 )
00082 else:
00083 sync = MF.TimeSynchronizer(
00084 self.subscribers,
00085 queue_size=rospy.get_param("~queue_size", 100),
00086 )
00087 sync.registerCallback(self.on_objects)
00088 else:
00089 self.subscribers = [
00090 rospy.Subscriber("~input/boxes", BoundingBoxArray,
00091 self.on_objects, queue_size=1),
00092 ]
00093
00094 self.subscribers.append(
00095 rospy.Subscriber("~input", PeoplePoseArray, self.on_people, queue_size=1))
00096
00097 def unsubscribe(self):
00098 for sub in self.subs:
00099 sub.unregister()
00100
00101 def on_objects(self, bbox_msg, cls_msg=None):
00102 """
00103 bbox_msg (jsk_recognition_msgs/BoundingBoxArray)
00104 cls_msg (jsk_recognition_msgs/ClassificationResult)
00105 """
00106 if cls_msg is not None:
00107 if len(bbox_msg.boxes) != len(cls_msg.labels):
00108 rospy.logwarn("len(boxes) != len(labels)")
00109 return
00110 for bbox, label in zip(bbox_msg.boxes, cls_msg.labels):
00111 bbox.label = label
00112 self.objects = bbox_msg.boxes
00113 rospy.loginfo("on_objects")
00114
00115 def on_people(self, ppl_msg):
00116 """
00117 ppl_msg (jsk_recognition_msgs/PeoplePoseArray)
00118
00119 refer: https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/doc/output.md
00120 """
00121 frame_id = remove_slash(ppl_msg.header.frame_id)
00122 in_objects = self.objects
00123 objects = []
00124 for bbox in in_objects:
00125 if remove_slash(bbox.header.frame_id) != frame_id:
00126 ps = PoseStamped(header=bbox.header, pose=bbox.pose)
00127 try:
00128 ps = self.tfl.transform(ps, frame_id)
00129 bbox.header, bbox.pose = ps.header, ps.pose
00130 objects.append(bbox)
00131 except tf2_ros.TransformException:
00132 continue
00133
00134 out_bboxes = []
00135 out_markers = []
00136 for i, pose in enumerate(ppl_msg.poses):
00137
00138 rwrist = find_pose("RWrist", pose)
00139 rfinger = find_pose(["RHand5", "RHand6", "RHand7", "RHand8"], pose)
00140 if rwrist is not None and rfinger is not None:
00141 rclosest, rdist = self.get_closest_bbox((rwrist, rfinger), objects)
00142 if rdist is not None and rdist < self.dist_threshold:
00143 out_bboxes.append(rclosest)
00144 rmarker = self.get_marker((rwrist, rfinger), frame_id)
00145 rmarker.id = 2 * i
00146 out_markers.append(rmarker)
00147
00148 lwrist = find_pose("LWrist", pose)
00149 lfinger = find_pose(["LHand5", "LHand6", "LHand7", "LHand8"], pose)
00150 if lwrist is not None and lfinger is not None:
00151 lclosest, ldist = self.get_closest_bbox((lwrist, lfinger), objects)
00152 if ldist is not None and ldist < self.dist_threshold:
00153 out_bboxes.append(lclosest)
00154 lmarker = self.get_marker((lwrist, lfinger), frame_id)
00155 lmarker.id = 2 * i + 1
00156 out_markers.append(lmarker)
00157
00158
00159 if out_bboxes:
00160 msg = BoundingBoxArray()
00161 msg.header.stamp = rospy.Time.now()
00162 msg.header.frame_id = frame_id
00163 msg.boxes = out_bboxes
00164 self.pub_bbox.publish(msg)
00165 if out_markers:
00166 self.pub_marker.publish(MarkerArray(markers=out_markers))
00167
00168 def get_marker(self, line_seg, frame_id, scale=0.3):
00169 p0, p1 = line_seg
00170 v = np.asarray([p1.position.x - p0.position.x,
00171 p1.position.y - p0.position.y,
00172 p1.position.z - p0.position.z])
00173 vnorm = np.linalg.norm(v)
00174 if vnorm > 0.0:
00175 v /= np.linalg.norm(v)
00176 p2 = copy.deepcopy(p0)
00177 p2.position.x += scale * v[0]
00178 p2.position.y += scale * v[1]
00179 p2.position.z += scale * v[2]
00180 m = Marker()
00181 m.header.stamp = rospy.Time.now()
00182 m.header.frame_id = frame_id
00183 m.ns = "beam"
00184 m.type = Marker.ARROW
00185 m.action = Marker.MODIFY
00186 m.lifetime = rospy.Duration(1)
00187 m.points = [p0.position, p1.position]
00188 m.scale.x = 0.02
00189 m.scale.y = 0.04
00190 m.color.r = 1.0
00191 m.color.a = 1.0
00192 return m
00193
00194 def get_closest_bbox(self, line_seg, bboxes):
00195 pose0, pose1 = line_seg
00196 p0 = np.asarray([pose0.position.x, pose0.position.y, pose0.position.z])
00197 p1 = np.asarray([pose1.position.x, pose1.position.y, pose1.position.z])
00198 min_d, closest = None, None
00199
00200 n01 = np.linalg.norm(p1 - p0)
00201 if n01 == 0.0:
00202 return closest, min_d
00203
00204 for bbox in bboxes:
00205 pos = bbox.pose.position
00206 p = np.asarray([pos.x, pos.y, pos.z])
00207
00208
00209 n = np.linalg.norm(p - p0)
00210 ip = np.inner(p1 - p0, p - p0) / (n01 * n)
00211 rospy.logdebug("ip: %s, dn: %s" % (ip, n - n01))
00212 if ip < 0.0 or n - n01 < self.min_norm_threshold:
00213 continue
00214
00215 d = np.linalg.norm(np.cross(p1 - p0, p0 - p)) / np.linalg.norm(p1 - p0)
00216 if min_d is None or min_d > d:
00217 min_d, closest = d, bbox
00218
00219 return closest, min_d
00220
00221
00222 if __name__ == '__main__':
00223 rospy.init_node("pointit")
00224 p = PointIt()
00225 rospy.spin()