$search
00001 #! /usr/bin/python 00002 #*********************************************************** 00003 #* Software License Agreement (BSD License) 00004 #* 00005 #* Copyright (c) 2009, Willow Garage, Inc. 00006 #* All rights reserved. 00007 #* 00008 #* Redistribution and use in source and binary forms, with or without 00009 #* modification, are permitted provided that the following conditions 00010 #* are met: 00011 #* 00012 #* * Redistributions of source code must retain the above copyright 00013 #* notice, this list of conditions and the following disclaimer. 00014 #* * Redistributions in binary form must reproduce the above 00015 #* copyright notice, this list of conditions and the following 00016 #* disclaimer in the documentation and/or other materials provided 00017 #* with the distribution. 00018 #* * Neither the name of Willow Garage, Inc. nor the names of its 00019 #* contributors may be used to endorse or promote products derived 00020 #* from this software without specific prior written permission. 00021 #* 00022 #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00025 #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00026 #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00028 #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00029 #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00030 #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00032 #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00033 #* POSSIBILITY OF SUCH DAMAGE. 00034 #* 00035 #* Author: Eitan Marder-Eppstein 00036 #*********************************************************** 00037 PKG = 'kinect_depth_calibration' 00038 NAME = 'depth_calibrator' 00039 00040 import roslib; roslib.load_manifest(PKG) 00041 00042 import rospy 00043 import tf 00044 import numpy 00045 import math 00046 from geometry_msgs.msg import PoseStamped 00047 from kinect_depth_calibration.srv import GetCheckerboardPose, GetCheckerboardPoseResponse, GetCheckerboardPoseRequest 00048 from kinect_depth_calibration.srv import GetCheckerboardCenter, GetCheckerboardCenterResponse, GetCheckerboardCenterRequest 00049 00050 from geometry_msgs.msg import Quaternion, Pose 00051 00052 from sensor_msgs.msg import CameraInfo 00053 00054 def msg_to_quaternion(msg): 00055 return [msg.x, msg.y, msg.z, msg.w] 00056 00057 def quaternion_to_msg(q): 00058 msg = Quaternion() 00059 msg.x = q[0] 00060 msg.y = q[1] 00061 msg.z = q[2] 00062 msg.w = q[3] 00063 return msg 00064 00065 def msg_to_pose(msg): 00066 trans = tf.transformations.quaternion_matrix(msg_to_quaternion(msg.orientation)) 00067 trans[0, 3] = msg.position.x 00068 trans[1, 3] = msg.position.y 00069 trans[2, 3] = msg.position.z 00070 trans[3, 3] = 1.0 00071 return trans 00072 00073 def pose_to_msg(pose): 00074 msg = Pose() 00075 msg.position.x = pose[0, 3] 00076 msg.position.y = pose[1, 3] 00077 msg.position.z = pose[2, 3] 00078 q = tf.transformations.quaternion_from_matrix(pose) 00079 msg.orientation.x = q[0] 00080 msg.orientation.y = q[1] 00081 msg.orientation.z = q[2] 00082 msg.orientation.w = q[3] 00083 return msg 00084 00085 def find_board_min(board_pose, corners_x, corners_y, spacing): 00086 trans = msg_to_pose(board_pose.pose) 00087 origin = tf.transformations.translation_matrix([-spacing, -spacing, 0.0]) 00088 pose_mat = numpy.dot(trans, origin) 00089 return pose_to_msg(pose_mat) 00090 00091 def find_board_max(board_pose, corners_x, corners_y, spacing): 00092 trans = msg_to_pose(board_pose.pose) 00093 origin = tf.transformations.translation_matrix([((corners_x) * spacing), ((corners_y) * spacing), 0.0]) 00094 pose_mat = numpy.dot(trans, origin) 00095 return pose_to_msg(pose_mat) 00096 00097 def find_board_center(board_pose, corners_x, corners_y, spacing): 00098 trans = msg_to_pose(board_pose.pose) 00099 origin = tf.transformations.translation_matrix([((corners_x - 1) * spacing) / 2.0, ((corners_y - 1) * spacing) / 2.0, 0.0]) 00100 pose_mat = numpy.dot(trans, origin) 00101 return pose_to_msg(pose_mat) 00102 00103 def project_pose(proj, pose): 00104 position = pose.pose.position 00105 point = numpy.array([[position.x], [position.y], [position.z]]) 00106 mult = numpy.dot(proj, point) 00107 return mult / mult[2] 00108 00109 def depth_calibrator_main(argv=None): 00110 rospy.init_node(NAME, anonymous=False) 00111 pose_pub = rospy.Publisher("new_pose", PoseStamped, latch=True) 00112 00113 corners_x = rospy.get_param('~corners_x', 5) 00114 corners_y = rospy.get_param('~corners_y', 4) 00115 spacing = rospy.get_param('~spacing', 0.0245) 00116 00117 listener = tf.TransformListener() 00118 00119 print "Waiting to receive camera info for the depth camera..." 00120 depth_info = rospy.wait_for_message('depth_camera_info', CameraInfo) 00121 depth_proj = numpy.reshape(numpy.array(depth_info.P), (3,4))[:3, :3] 00122 depth_frame_id = depth_info.header.frame_id 00123 print "Got camera info, the depth camera operates in frame %s" % depth_frame_id 00124 00125 run = True 00126 while run: 00127 00128 while(raw_input("Is a checkerboard visible for your image producing camera? (y/n): ") != 'y'): 00129 print "For the Kinect, you may need to cover the IR projector for the CB to be detected." 00130 00131 print "OK, thanks! Checking for the 'get_checkerboard_pose' service." 00132 00133 rospy.wait_for_service('get_checkerboard_pose') 00134 00135 print "Found the checkerboard service." 00136 00137 print "Looking for a %d x %d checkerboard, with %.4f spacing...." % (corners_x, corners_y, spacing) 00138 00139 cb_detector = rospy.ServiceProxy('get_checkerboard_pose', GetCheckerboardPose) 00140 cb = cb_detector.call(GetCheckerboardPoseRequest(corners_x, corners_y, spacing, spacing)) 00141 img_center = find_board_center(cb.board_pose, corners_x, corners_y, spacing) 00142 img_msg = PoseStamped() 00143 img_msg.header = cb.board_pose.header 00144 img_msg.pose = img_center 00145 pose_pub.publish(img_msg) 00146 00147 depth_center = None 00148 #now we want to transform the pose into the depth frame if the image frame is different 00149 if depth_frame_id is not None and img_msg.header.frame_id != depth_frame_id: 00150 img_min = PoseStamped(cb.board_pose.header, find_board_min(cb.board_pose, corners_x, corners_y, spacing)) 00151 img_max = PoseStamped(cb.board_pose.header, find_board_max(cb.board_pose, corners_x, corners_y, spacing)) 00152 00153 print "Waiting for the transform between %s and %s" % (img_msg.header.frame_id, depth_frame_id) 00154 listener.waitForTransform(depth_frame_id, img_msg.header.frame_id, img_msg.header.stamp, rospy.Duration(2.0)) 00155 depth_pose = listener.transformPose(depth_frame_id, img_msg) 00156 depth_min = listener.transformPose(depth_frame_id, img_min) 00157 depth_max = listener.transformPose(depth_frame_id, img_max) 00158 00159 depth_min_pt = project_pose(depth_proj, depth_min) 00160 depth_max_pt = project_pose(depth_proj, depth_max) 00161 00162 cb.min_x = depth_min_pt[0] 00163 cb.min_y = depth_min_pt[1] 00164 cb.max_x = depth_max_pt[0] 00165 cb.max_y = depth_max_pt[1] 00166 00167 depth_center = depth_pose.pose 00168 else: 00169 depth_center = img_center 00170 00171 print "Successfully found a checkerboard, with depth %.4f, noise_vel: %f, noise_rot: %f in frame %s" % (depth_center.position.z, 00172 cb.noise_vel, cb.noise_rot, 00173 depth_frame_id) 00174 00175 00176 print "Now we want to look for the center of the checkerboard in the depth image." 00177 while(raw_input("Have you uncovered the IR projector and turned off any other IR light source? (y/n): ") != 'y'): 00178 print "Don't be difficult, just do it." 00179 00180 print "OK, thanks! Waiting for the 'get_checkerboard_center' service." 00181 00182 rospy.wait_for_service('get_checkerboard_center') 00183 00184 print "Found the service, looking for the center of the checkerboard bounded by the rectangle (%.2f, %.2f), (%.2f, %.2f)." % ( 00185 cb.min_x, cb.min_y, cb.max_x, cb.max_y) 00186 00187 center_detector = rospy.ServiceProxy('get_checkerboard_center', GetCheckerboardCenter) 00188 center_depth = center_detector.call(GetCheckerboardCenterRequest(cb.min_x, cb.max_x, cb.min_y, cb.max_y, depth_center.position.z)) 00189 00190 print "Found the center of the board at depth %.4f in the pointcloud" % (center_depth.depth) 00191 00192 print "The offset between the img and the point cloud is: %.4f" % (depth_center.position.z - center_depth.depth) 00193 00194 run = raw_input("Would you like to run again? (y/n): ") == 'y' 00195 00196 if __name__ == '__main__': 00197 depth_calibrator_main()