pointit.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 # Author: Yuki Furuta <furushchev@jsk.imi.i.u-tokyo.ac.jp>
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         # variables
00048         self.subscribers = []
00049         self.objects = []
00050 
00051         # parameters
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         # tf listener
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         # advertise
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             # for each person
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         # publish
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             # check if the order is p0 -> p1 -> p
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()


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Tue Jul 2 2019 19:41:07