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')