7 from image_geometry.cameramodels
import PinholeCameraModel
8 from jsk_recognition_msgs.msg
import BoundingBox
9 from jsk_recognition_msgs.msg
import BoundingBoxArray
10 from jsk_topic_tools
import ConnectionBasedTransport
11 import message_filters
14 import sensor_msgs.msg
16 from tf.transformations
import quaternion_from_matrix
17 from tf.transformations
import unit_vector
as normalize_vector
21 return np.array([[0, -v[2], v[1]],
31 first_axis=(1, 0, 0), second_axis=(0, 1, 0), axes=
'xy'):
32 if axes
not in [
'xy',
'yx',
'xz',
'zx',
'yz',
'zy']:
33 raise ValueError(
"Valid axes are 'xy', 'yx', 'xz', 'zx', 'yz', 'zy'.")
34 e1 = normalize_vector(first_axis)
35 e2 = normalize_vector(second_axis - np.dot(second_axis, e1) * e1)
36 if axes
in [
'xy',
'zx',
'yz']:
40 e3 = normalize_vector(
41 third_axis - np.dot(third_axis, e1) * e1 - np.dot(third_axis, e2) * e2)
42 first_index = ord(axes[0]) - ord(
'x')
43 second_index = ord(axes[1]) - ord(
'x')
44 third_index = ((first_index + 1) ^ (second_index + 1)) - 1
45 indices = [first_index, second_index, third_index]
46 return np.vstack([e1, e2, e3])[np.argsort(indices)].T
54 for i
in range(len(poly)):
56 if i
is len(poly) - 1:
60 prod = np.cross(vi1, vi2)
64 result = np.dot(total,
unit_normal(poly[0], poly[1], poly[2]))
65 return abs(result / 2)
69 x = np.linalg.det([[1, a[1], a[2]],
72 y = np.linalg.det([[a[0], 1, a[2]],
75 z = np.linalg.det([[a[0], a[1], 1],
78 magnitude = (x**2 + y**2 + z**2)**.5
79 return (x / magnitude, y / magnitude, z / magnitude)
83 pt0 = np.array(pt0, dtype=np.float32)
84 pt1 = np.array(pt1, dtype=np.float32)
85 pt2 = np.array(pt2, dtype=np.float32)
86 dx1 = pt1[0][0] - pt0[0][0]
87 dy1 = pt1[0][1] - pt0[0][1]
88 dx2 = pt2[0][0] - pt0[0][0]
89 dy2 = pt2[0][1] - pt0[0][1]
90 return (dx1 * dx2 + dy1 * dy2) / np.sqrt(
91 (dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10)
98 distance_threshold=1.41421356,
101 canny_aperture_size=3,
103 self.
lsd = cv2.ximgproc.createFastLineDetector(
112 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
113 line_segments = self.
lsd.detect(gray)
115 if line_segments
is None:
117 edge_img = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
118 for line
in line_segments:
119 x1, y1, x2, y2 = map(int, line[0][:4])
120 cv2.line(edge_img, (x1, y1), (x2, y2), (255, 255, 255), 10)
122 _, contours, _ = cv2.findContours(
125 cv2.CHAIN_APPROX_SIMPLE)
129 for contour
in contours:
130 arclen = cv2.arcLength(contour,
True)
131 approx = cv2.approxPolyDP(contour,
136 if (len(approx) == 4
and
137 abs(cv2.contourArea(approx)) > 1000
138 and cv2.isContourConvex(approx)):
140 for j
in range(2, 5):
143 angle(approx[j % 4], approx[j - 2], approx[j - 1]))
144 maxCosine = max(maxCosine, cosine)
150 squares.append(approx)
151 approx = np.array(approx).reshape(-1, 2)
157 cv2.line(img, tuple(approx[0]), tuple(approx[2]),
159 cv2.line(img, tuple(approx[1]), tuple(approx[3]),
165 for i
in range(len(squares)):
167 p = np.array(p).reshape(-1, 2)
168 image = cv2.polylines(image, [p],
True, (0, 255, 0), thickness=3)
177 '~angle_tolerance', np.rad2deg(5.0))
180 '~area_tolerance', 0.1)
187 '~length_tolerance', 0.04)
189 sensor_msgs.msg.Image,
192 geometry_msgs.msg.PoseArray,
195 '~output/boxes', BoundingBoxArray, queue_size=1)
197 '~output/length', std_msgs.msg.Float32MultiArray, queue_size=1)
203 queue_size = rospy.get_param(
'~queue_size', 10)
204 if rospy.get_param(
'~with_depth',
True):
207 sensor_msgs.msg.Image,
212 sensor_msgs.msg.Image,
215 self.
subs = [sub_img, sub_depth]
217 '~input/camera_info',
220 if rospy.get_param(
'~approximate_sync',
True):
221 slop = rospy.get_param(
'~slop', 0.1)
222 sync = message_filters.ApproximateTimeSynchronizer(
223 fs=self.
subs, queue_size=queue_size, slop=slop)
226 fs=self.
subs, queue_size=queue_size)
229 sub = rospy.Subscriber(
231 sensor_msgs.msg.Image,
233 queue_size=queue_size)
246 rospy.loginfo(
"Received camera info")
251 cv_image = bridge.imgmsg_to_cv2(
253 except cv_bridge.CvBridgeError
as e:
254 rospy.logerr(
'{}'.format(e))
260 vis_msg = bridge.cv2_to_imgmsg(cv_image, encoding=
'bgr8')
261 vis_msg.header.stamp = msg.header.stamp
266 rospy.loginfo(
"Waiting camera info ...")
270 cv_image = bridge.imgmsg_to_cv2(img_msg,
'bgr8')
271 depth_img = bridge.imgmsg_to_cv2(depth_msg,
'passthrough')
273 if depth_msg.encoding ==
'16UC1':
274 depth_img = np.asarray(depth_img, dtype=np.float32)
276 elif depth_msg.encoding !=
'32FC1':
277 rospy.logerr(
'Unsupported depth encoding: %s' %
279 except cv_bridge.CvBridgeError
as e:
280 rospy.logerr(
'{}'.format(e))
284 np_squares = np.array(squares, dtype=np.int32).reshape(-1, 2)
286 height, width, _ = cv_image.shape
289 x = (np_squares[:, 0] - cameramodel.cx()) / cameramodel.fx()
290 y = (np_squares[:, 1] - cameramodel.cy()) / cameramodel.fy()
291 z = depth_img.reshape(-1)[np_squares[:, 1] * width + np_squares[:, 0]]
295 x = x.reshape(-1, 4, 1, 1)
296 y = y.reshape(-1, 4, 1, 1)
297 z = z.reshape(-1, 4, 1, 1)
298 xyzs = np.concatenate([x, y, z], axis=3)
300 valid_xyz_corners = []
301 length_array_for_publish = std_msgs.msg.Float32MultiArray()
302 for si, xyz
in enumerate(xyzs):
303 xyz_org = xyz.reshape(4, 3)
304 xyz = np.concatenate([xyz, xyz], axis=0)
307 vec_a = xyz[i] - xyz[i + 1]
308 vec_b = xyz[i + 2] - xyz[i + 1]
309 zzz = np.inner(vec_a, vec_b)
310 nnn = np.linalg.norm(vec_a) * np.linalg.norm(vec_b)
315 calc_axis = np.arccos(np.clip(ccc, -1.0, 1.0))
321 _a = (np.sqrt(np.sum((xyz_org[0] - xyz_org[1]) ** 2)))
322 _b = (np.sqrt(np.sum((xyz_org[1] - xyz_org[2]) ** 2)))
323 _c = (np.sqrt(np.sum((xyz_org[2] - xyz_org[3]) ** 2)))
324 _d = (np.sqrt(np.sum((xyz_org[3] - xyz_org[0]) ** 2)))
325 tmp = sorted([_a, _b, _c, _d])
327 length_array.append(_a)
328 length_array.append(_b)
329 length_array.append(_c)
330 length_array.append(_d)
331 length_array_for_publish = std_msgs.msg.Float32MultiArray(
338 area_value =
area(xyz_org)
340 new_squares.append(squares[si])
341 valid_xyz_corners.append(xyz_org)
344 pose_array_msg = geometry_msgs.msg.PoseArray(header=img_msg.header)
345 bounding_box_array_msg = BoundingBoxArray(header=img_msg.header)
346 for xyz
in valid_xyz_corners:
347 center = np.mean(xyz, axis=0)
349 vec_a = xyz[2] - xyz[1]
350 vec_b = xyz[0] - xyz[1]
351 if np.linalg.norm(vec_a) > np.linalg.norm(vec_b):
352 vec_a, vec_b = vec_b, vec_a
353 normal = np.cross(vec_a, vec_b)
356 normal = normal / np.linalg.norm(normal)
360 q_xyzw = quaternion_from_matrix(M)
361 _a = (np.sqrt(np.sum((xyz[0] - xyz[1]) ** 2)))
362 _b = (np.sqrt(np.sum((xyz[1] - xyz[2]) ** 2)))
363 _c = (np.sqrt(np.sum((xyz[2] - xyz[3]) ** 2)))
364 _d = (np.sqrt(np.sum((xyz[3] - xyz[0]) ** 2)))
365 lengths = np.array([_a, _b, _c, _d])
366 indices = np.argsort(lengths)
368 pose = geometry_msgs.msg.Pose()
369 pose.position.x = center[0]
370 pose.position.y = center[1]
371 pose.position.z = center[2]
372 pose.orientation.x = q_xyzw[0]
373 pose.orientation.y = q_xyzw[1]
374 pose.orientation.z = q_xyzw[2]
375 pose.orientation.w = q_xyzw[3]
376 pose_array_msg.poses.append(pose)
377 bounding_box_array = BoundingBox(header=img_msg.header)
378 bounding_box_array.pose.position.x = center[0]
379 bounding_box_array.pose.position.y = center[1]
380 bounding_box_array.pose.position.z = center[2]
381 bounding_box_array.pose.orientation.x = q_xyzw[0]
382 bounding_box_array.pose.orientation.y = q_xyzw[1]
383 bounding_box_array.pose.orientation.z = q_xyzw[2]
384 bounding_box_array.pose.orientation.w = q_xyzw[3]
385 bounding_box_array.dimensions.x = 0.01
386 bounding_box_array.dimensions.y = (
387 lengths[indices[0]] + lengths[indices[1]]) / 2.0
388 bounding_box_array.dimensions.z = (
389 lengths[indices[2]] + lengths[indices[3]]) / 2.0
390 bounding_box_array_msg.boxes.append(bounding_box_array)
396 vis_msg = bridge.cv2_to_imgmsg(cv_image, encoding=
'bgr8')
397 vis_msg.header.stamp = img_msg.header.stamp
402 return self.
image_pub.get_num_connections() > 0
405 if __name__ ==
'__main__':
406 rospy.init_node(
'paper_finder')