4 import dynamic_reconfigure.server
 
    5 import geometry_msgs.msg
 
    6 import jsk_recognition_msgs.msg
 
   10 import shapely.geometry
 
   11 from jsk_recognition_utils.cfg 
import PolygonArrayToBoxArrayConfig
 
   12 from jsk_topic_tools 
import ConnectionBasedTransport
 
   13 from tf.transformations 
import quaternion_from_matrix 
as matrix2quaternion
 
   14 from tf.transformations 
import unit_vector 
as normalize_vector
 
   18     return np.array([[0, -v[2], v[1]],
 
   29 from distutils.version 
import LooseVersion
 
   30 if LooseVersion(shapely.__version__) < LooseVersion(
'1.6.0'):
 
   32     from itertools 
import islice
 
   33     from shapely.affinity 
import affine_transform
 
   36         """Returns the general minimum bounding rectangle of 
   37         the geometry. Can possibly be rotated. If the convex hull 
   38         of the object is a degenerate (line or point) this same degenerate 
   42         hull = polygon.convex_hull
 
   44             coords = hull.exterior.coords
 
   45         except AttributeError: 
 
   48         edges = ((pt2[0]-pt1[0], pt2[1]-pt1[1]) 
for pt1, pt2 
in zip(coords, islice(coords, 1, 
None)))
 
   50         def _transformed_rects():
 
   53                 length = math.sqrt(dx**2 + dy**2)
 
   54                 ux, uy = dx/length, dy/length
 
   59                 transf_rect = affine_transform(hull, (ux,uy,vx,vy,0,0)).envelope
 
   62                 yield (transf_rect, (ux,vx,uy,vy,0,0))
 
   65         transf_rect, inv_matrix = min(_transformed_rects(), key=
lambda r : r[0].area)
 
   66         return affine_transform(transf_rect, inv_matrix)
 
   67     shapely.geometry.Polygon.minimum_rotated_rectangle = minimum_rotated_rectangle
 
   70         first_axis=(1, 0, 0), second_axis=(0, 1, 0), axes=
'xy'):
 
   71     if axes 
not in [
'xy', 
'yx', 
'xz', 
'zx', 
'yz', 
'zy']:
 
   72         raise ValueError(
"Valid axes are 'xy', 'yx', 'xz', 'zx', 'yz', 'zy'.")
 
   73     e1 = normalize_vector(first_axis)
 
   74     e2 = normalize_vector(second_axis - np.dot(second_axis, e1) * e1)
 
   75     if axes 
in [
'xy', 
'zx', 
'yz']:
 
   79     e3 = normalize_vector(
 
   80         third_axis - np.dot(third_axis, e1) * e1 - np.dot(third_axis, e2) * e2)
 
   81     first_index = ord(axes[0]) - ord(
'x')
 
   82     second_index = ord(axes[1]) - ord(
'x')
 
   83     third_index = ((first_index + 1) ^ (second_index + 1)) - 1
 
   84     indices = [first_index, second_index, third_index]
 
   85     return np.vstack([e1, e2, e3])[np.argsort(indices)].T
 
   91         v1 = normalize_vector(v1)
 
   92         v2 = normalize_vector(v2)
 
   94     return np.arccos(np.clip(dot 
if directed 
else np.fabs(dot), -1.0, 1.0))
 
   99         points = points[
None, :]
 
  101     a = normalize_vector(a)
 
  102     b = normalize_vector(b)
 
  104     if np.isclose(angle, 0.0):
 
  105         k = np.array([0, 0, 0], 
'f')
 
  107         k = normalize_vector(np.cross(a, b))
 
  109     points_rot = points * np.cos(theta) \
 
  110         + np.cross(k, points) * np.sin(theta) \
 
  111         + k * np.dot(k, points.T).reshape(-1, 1) * (1 - np.cos(theta))
 
  118         super(PolygonArrayToRectBoxArray, self).
__init__()
 
  119         dynamic_reconfigure.server.Server(
 
  120             PolygonArrayToBoxArrayConfig,
 
  124             jsk_recognition_msgs.msg.PolygonArray,
 
  127             '~output/coefficients',
 
  128             jsk_recognition_msgs.msg.ModelCoefficientsArray,
 
  132             jsk_recognition_msgs.msg.BoundingBoxArray,
 
  140         queue_size = rospy.get_param(
'~queue_size', 10)
 
  143             jsk_recognition_msgs.msg.PolygonArray,
 
  146             '~input/coefficients',
 
  147             jsk_recognition_msgs.msg.ModelCoefficientsArray,
 
  149         self.
subs = [sub_polygon, sub_coefficients]
 
  150         if rospy.get_param(
'~approximate_sync', 
False):
 
  151             slop = rospy.get_param(
'~slop', 0.1)
 
  152             sync = message_filters.ApproximateTimeSynchronizer(
 
  153                 fs=self.
subs, queue_size=queue_size, slop=slop)
 
  156                 fs=self.
subs, queue_size=queue_size)
 
  157         sync.registerCallback(self.
_cb)
 
  163     def _cb(self, polygons_msg, coeffs_msg):
 
  164         new_polygons_msg = jsk_recognition_msgs.msg.PolygonArray()
 
  165         new_polygons_msg.header = polygons_msg.header
 
  166         boxes_msg = jsk_recognition_msgs.msg.BoundingBoxArray(
 
  167             header=polygons_msg.header)
 
  168         base_normal = [0, 0, 1]
 
  169         for coeff, polygon 
in zip(
 
  170                 coeffs_msg.coefficients,
 
  171                 polygons_msg.polygons):
 
  172             a, b, c, d = coeff.values
 
  174                 [[point.x, point.y, point.z]
 
  175                  for point 
in polygon.polygon.points],
 
  184             shapely_polygon = shapely.geometry.Polygon(
 
  186             rect = shapely_polygon.minimum_rotated_rectangle
 
  187             x, y = rect.exterior.xy
 
  188             rect_polygon_2d = - np.ones((5, 3), 
'f') * d
 
  189             rect_polygon_2d[:, 0] = x
 
  190             rect_polygon_2d[:, 1] = y
 
  197             polygon = geometry_msgs.msg.PolygonStamped(
 
  198                 header=polygon.header)
 
  199             for x, y, z 
in rect_polygon:
 
  200                 polygon.polygon.points.append(
 
  201                     geometry_msgs.msg.Point32(x, y, z))
 
  202             new_polygons_msg.polygons.append(polygon)
 
  204             center_x, center_y, center_z = rect_polygon[:4].mean(axis=0)
 
  206             box_msg = jsk_recognition_msgs.msg.BoundingBox(
 
  207                 header=polygon.header)
 
  208             base_matrix = np.eye(4)
 
  212                 rect_polygon[1] - rect_polygon[0], normal, 
'xz')
 
  213             base_matrix[:3, :3] = matrix
 
  214             q_x, q_y, q_z, q_w = matrix2quaternion(base_matrix)
 
  215             dim_x = np.linalg.norm(rect_polygon[1] - rect_polygon[0])
 
  216             dim_y = np.linalg.norm(rect_polygon[2] - rect_polygon[1])
 
  217             box_msg.pose.position.x = center_x
 
  218             box_msg.pose.position.y = center_y
 
  219             box_msg.pose.position.z = center_z
 
  220             box_msg.pose.orientation.w = q_w
 
  221             box_msg.pose.orientation.x = q_x
 
  222             box_msg.pose.orientation.y = q_y
 
  223             box_msg.pose.orientation.z = q_z
 
  224             box_msg.dimensions.x = dim_x
 
  225             box_msg.dimensions.y = dim_y
 
  227             boxes_msg.boxes.append(box_msg)
 
  233 if __name__ == 
'__main__':
 
  234     rospy.init_node(
'polygon_array_to_box_array')