polygon_array_publisher.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 import numpy as np
5 import rospy
6 from geometry_msgs.msg import Point32, PolygonStamped
7 from jsk_recognition_msgs.msg import ModelCoefficientsArray
8 from jsk_recognition_msgs.msg import PolygonArray
9 from pcl_msgs.msg import ModelCoefficients
10 
11 
12 def is_planar(points):
13  points = np.array(points)
14  # 2d points are always in a plane.
15  if len(points[0]) < 3:
16  coeffs = np.array([0, 0, 1, 0], 'f')
17  return True, coeffs
18  # Pick out three points (p0, p1, p2) from the given points.
19  # Make sure that the three points do not line up in a straight line.
20  p0 = points[0]
21  points = points[1:]
22  dists = np.linalg.norm(points - p0, axis=1, ord=2)
23  farthest_index = np.argmax(dists)
24  p1 = points[farthest_index]
25  v0 = p1 - p0
26  p2 = points[np.argmin(np.dot(points - p0, v0))]
27  v1 = p2 - p0
28  # Calculate the normal to the plane composed of p0, p1, and p2.
29  normal = np.cross(v0, v1)
30  norm = np.linalg.norm(normal, ord=2)
31  # If the input polygon is a line or a point, it is not considered a plane.
32  if np.isclose(norm, 0.0):
33  return False, np.array([0, 0, 0, 0], 'f')
34  normal = normal / norm
35  # Check the normal vector and the vector from p0 to each point are vertical
36  dists = np.abs(np.dot(points - p0, normal))
37  # Equation of plane: coeffs[0]*x + coeffs[1]*y + coeffs[2]*z + d = 0
38  # So, d = - (coeffs[0]*p[0] + coeffs[1]*p[1] + coeffs[2]*p[2])
39  d = - np.dot(normal, p0)
40  coeffs = np.array([normal[0], normal[1], normal[2], d], 'f')
41  return np.allclose(dists, 0.0), coeffs
42 
43 
44 class PolygonArrayPublisher(object):
45  def __init__(self):
46  publish_rate = rospy.get_param("~publish_rate", 1.0)
47  self.publish_coeffs = rospy.get_param("~publish_coeffs", False)
48 
49  frame_id = rospy.get_param("~frame_id")
50  param = rospy.get_param("~polygons")
52  self.msg, self.coeffs_array_msg = self.parse_params(param, frame_id)
53 
54  self.pub_polygons = rospy.Publisher("~output", PolygonArray, queue_size=1)
55  if self.publish_coeffs:
56  if self.are_polygons_in_planar is False:
57  self.publish_coeffs = False
58  rospy.logwarn(
59  '~publish_coeffs is True,'
60  ' but ModelCoefficientsArray is not published'
61  ' because each polygon is not in planar.')
62  else:
63  self.pub_coeffs = rospy.Publisher(
64  '~output/coefficients',
65  ModelCoefficientsArray, queue_size=1)
66  self.timer = rospy.Timer(rospy.Duration(1. / publish_rate), self.publish)
67 
68  def parse_params(self, param, frame_id):
69  # validate params
70  assert isinstance(param, list), "polygons must be list"
71 
72  has_label = any("label" in p for p in param)
73  has_likelihood = any("likelihood" in p for p in param)
74 
75  for polygon in param:
76  assert "points" in polygon and isinstance(polygon["points"], list),\
77  "each polygon must have at least 1 'points'"
78  for point in polygon["points"]:
79  assert len(point) == 3,\
80  "element of 'points' must be list of 3 numbers"
81  if has_label:
82  assert "label" in polygon, "missing 'label'"
83  if has_likelihood:
84  assert "likelihood" in polygon, "missing 'likelihood'"
85 
86  # parse params
87  msg = PolygonArray()
88  msg.header.frame_id = frame_id
89  coeffs_array_msg = ModelCoefficientsArray(header=msg.header)
90  for polygon in param:
91  ps = PolygonStamped()
92  ps.header.frame_id = frame_id
93  ps.polygon.points = [Point32(*v) for v in polygon["points"]]
94 
95  coeffs_msg = ModelCoefficients(header=ps.header)
96  planar, coeffs = is_planar(polygon["points"])
97  coeffs_msg.values = coeffs
98  self.are_polygons_in_planar &= planar
99  coeffs_array_msg.coefficients.append(coeffs_msg)
100  msg.polygons.append(ps)
101  if has_label:
102  msg.labels.append(polygon["label"])
103  if has_likelihood:
104  msg.likelihood.append(polygon["likelihood"])
105  return msg, coeffs_array_msg
106 
107  def publish(self, event):
108  # update timestamp
109  self.msg.header.stamp = event.current_real
110  for p in self.msg.polygons:
111  p.header.stamp = event.current_real
112 
113  self.pub_polygons.publish(self.msg)
114  if self.publish_coeffs:
115  self.coeffs_array_msg.header.stamp = event.current_real
116  for p in self.coeffs_array_msg.coefficients:
117  p.header.stamp = event.current_real
119 
120 
121 if __name__ == '__main__':
122  rospy.init_node("polygon_array_publisher")
124  rospy.spin()
polygon_array_publisher.PolygonArrayPublisher.parse_params
def parse_params(self, param, frame_id)
Definition: polygon_array_publisher.py:68
polygon_array_publisher.PolygonArrayPublisher.publish
def publish(self, event)
Definition: polygon_array_publisher.py:107
polygon_array_publisher.PolygonArrayPublisher.timer
timer
Definition: polygon_array_publisher.py:66
polygon_array_publisher.PolygonArrayPublisher.__init__
def __init__(self)
Definition: polygon_array_publisher.py:45
polygon_array_publisher.PolygonArrayPublisher
Definition: polygon_array_publisher.py:44
polygon_array_publisher.PolygonArrayPublisher.pub_coeffs
pub_coeffs
Definition: polygon_array_publisher.py:63
polygon_array_publisher.PolygonArrayPublisher.coeffs_array_msg
coeffs_array_msg
Definition: polygon_array_publisher.py:52
polygon_array_publisher.PolygonArrayPublisher.publish_coeffs
publish_coeffs
Definition: polygon_array_publisher.py:47
polygon_array_publisher.PolygonArrayPublisher.are_polygons_in_planar
are_polygons_in_planar
Definition: polygon_array_publisher.py:51
polygon_array_publisher.is_planar
def is_planar(points)
Definition: polygon_array_publisher.py:12
polygon_array_publisher.PolygonArrayPublisher.pub_polygons
pub_polygons
Definition: polygon_array_publisher.py:54


jsk_recognition_utils
Author(s):
autogenerated on Tue Jan 7 2025 04:04:52