$search
00001 #!/usr/bin/env python 00002 ################################################################# 00003 ##\file 00004 # 00005 # \note 00006 # Copyright (c) 2011-2012 \n 00007 # Fraunhofer Institute for Manufacturing Engineering 00008 # and Automation (IPA) \n\n 00009 # 00010 ################################################################# 00011 # 00012 # \note 00013 # Project name: care-o-bot 00014 # \note 00015 # ROS stack name: cob_calibration 00016 # \note 00017 # ROS package name: cob_camera_calibration 00018 # 00019 # \author 00020 # Author: Sebastian Haug, email:sebhaug@gmail.com 00021 # \author 00022 # Supervised by: Florian Weisshardt, email:florian.weisshardt@ipa.fhg.de 00023 # 00024 # \date Date of creation: November 2011 00025 # 00026 ################################################################# 00027 # 00028 # Redistribution and use in source and binary forms, with or without 00029 # modification, are permitted provided that the following conditions are met: 00030 # 00031 # - Redistributions of source code must retain the above copyright 00032 # notice, this list of conditions and the following disclaimer. \n 00033 # - Redistributions in binary form must reproduce the above copyright 00034 # notice, this list of conditions and the following disclaimer in the 00035 # documentation and/or other materials provided with the distribution. \n 00036 # - Neither the name of the Fraunhofer Institute for Manufacturing 00037 # Engineering and Automation (IPA) nor the names of its 00038 # contributors may be used to endorse or promote products derived from 00039 # this software without specific prior written permission. \n 00040 # 00041 # This program is free software: you can redistribute it and/or modify 00042 # it under the terms of the GNU Lesser General Public License LGPL as 00043 # published by the Free Software Foundation, either version 3 of the 00044 # License, or (at your option) any later version. 00045 # 00046 # This program is distributed in the hope that it will be useful, 00047 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00048 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00049 # GNU Lesser General Public License LGPL for more details. 00050 # 00051 # You should have received a copy of the GNU Lesser General Public 00052 # License LGPL along with this program. 00053 # If not, see <http://www.gnu.org/licenses/>. 00054 # 00055 ################################################################# 00056 PKG = 'cob_camera_calibration' 00057 NODE = 'stereo_calibration_node' 00058 import roslib; roslib.load_manifest(PKG) 00059 import rospy 00060 00061 import numpy as np 00062 import tf 00063 from cob_camera_calibration import Checkerboard, CheckerboardDetector, StereoCalibrator, CalibrationData, CalibrationUrdfUpdater 00064 00065 class StereoCalibrationNode(): 00066 ''' 00067 Stereo Calibration ROS Node 00068 00069 Runs stereo calibration on a set of images. All settings are configurable via 00070 the ROS parameter server. 00071 ''' 00072 00073 def __init__(self): 00074 ''' 00075 Configures the calibration node 00076 00077 Reads configuration from parameter server or uses default values 00078 ''' 00079 rospy.init_node(NODE) 00080 print "==> started " + NODE 00081 00082 # get parameter from parameter server or set defaults 00083 self.folder = rospy.get_param('~folder', ".") 00084 self.pattern_size = rospy.get_param('~pattern_size', "9x6") 00085 self.square_size = rospy.get_param('~square_size', 0.03) 00086 00087 self.image_prefix_l = rospy.get_param('~image_prefix_l', "left") 00088 self.camera_name_l = rospy.get_param('~camera_name_l', "left") 00089 self.frame_id_l = rospy.get_param('~frame_id_l', "/left") 00090 self.output_file_l = rospy.get_param('~output_file_l', self.camera_name_l+".yaml") 00091 00092 self.image_prefix_r = rospy.get_param('~image_prefix_r', "right") 00093 self.camera_name_r = rospy.get_param('~camera_name_r', "right") 00094 self.frame_id_r = rospy.get_param('~frame_id_r', "/right") 00095 self.output_file_r = rospy.get_param('~output_file_r', self.camera_name_r+".yaml") 00096 00097 self.calibration_urdf_in = rospy.get_param('~calibration_urdf_in', "") 00098 self.calibration_urdf_out = rospy.get_param('~calibration_urdf_out', "") 00099 self.baseline_prop_prefix = rospy.get_param('~baseline_prop_prefix', "cam_r_") 00100 00101 self.alpha = rospy.get_param('~alpha', 0.0) 00102 self.verbose = rospy.get_param('~verbose', False) 00103 00104 # split pattern_size string into tuple, e.g '9x6' -> tuple(9,6) 00105 self.pattern_size = tuple((int(self.pattern_size.split("x")[0]), int(self.pattern_size.split("x")[1]))) 00106 00107 def run_stereo_calibration(self): 00108 ''' 00109 Runs the calibration 00110 ''' 00111 # set up Checkerboard, CheckerboardDetector and MonoCalibrator 00112 board = Checkerboard(self.pattern_size, self.square_size) 00113 detector = CheckerboardDetector(board) 00114 calibrator = StereoCalibrator(board, detector, self.folder, self.image_prefix_l, self.image_prefix_r) 00115 00116 # run calibration 00117 ((rms_l, rms_r, rms_stereo), camera_matrix_l, dist_coeffs_l, rectification_matrix_l, projection_matrix_l, 00118 camera_matrix_r, dist_coeffs_r, rectification_matrix_r, projection_matrix_r, 00119 (h, w), R, T) = calibrator.calibrate_stereo_camera(self.alpha) 00120 print "==> successfully calibrated, stereo reprojection RMS (in pixels):", rms_stereo 00121 00122 # create CalibrationData object with results 00123 camera_info_l = CalibrationData(self.camera_name_l, self.frame_id_l, w, h) 00124 camera_info_l.camera_matrix = camera_matrix_l 00125 camera_info_l.rectification_matrix = rectification_matrix_l 00126 camera_info_l.projection_matrix = projection_matrix_l 00127 camera_info_l.distortion_coefficients = dist_coeffs_l 00128 00129 camera_info_r = CalibrationData(self.camera_name_r, self.frame_id_r, w, h) 00130 camera_info_r.camera_matrix = camera_matrix_r 00131 camera_info_r.rectification_matrix = rectification_matrix_r 00132 camera_info_r.projection_matrix = projection_matrix_r 00133 camera_info_r.distortion_coefficients = dist_coeffs_r 00134 00135 # save results 00136 camera_info_l.save_camera_yaml_file(self.output_file_l) 00137 print "==> saved left results to:", self.output_file_l 00138 00139 camera_info_r.save_camera_yaml_file(self.output_file_r) 00140 print "==> saved right results to:", self.output_file_r 00141 00142 # convert baseline (invert transfrom as T and R bring right frame into left 00143 # and we need transform from left to right for urdf!) 00144 M = np.matrix(np.vstack((np.hstack((R, T)), [0.0, 0.0, 0.0, 1.0]))) # 4x4 homogeneous matrix 00145 M_inv = M.I 00146 T_inv = np.array(M_inv[:3,3]).flatten().tolist() # T as list (x, y, z) 00147 R_inv = list(tf.transformations.euler_from_matrix(M_inv[:3,:3])) # convert R to (roll, pitch, yaw) 00148 00149 # save baseline 00150 if (self.calibration_urdf_in != "" and self.calibration_urdf_out != ""): 00151 attributes2update = {self.baseline_prop_prefix+'x': T_inv[0], 00152 self.baseline_prop_prefix+'y': T_inv[1], 00153 self.baseline_prop_prefix+'z': T_inv[2], 00154 self.baseline_prop_prefix+'roll': R_inv[0], 00155 self.baseline_prop_prefix+'pitch': R_inv[1], 00156 self.baseline_prop_prefix+'yaw': R_inv[2]} 00157 urdf_updater = CalibrationUrdfUpdater(self.calibration_urdf_in, self.calibration_urdf_out, self.verbose) 00158 urdf_updater.update(attributes2update) 00159 print "==> updated baseline in:", self.calibration_urdf_out 00160 else: 00161 print "==> NOT saving baseline to urdf file! Parameters 'calibration_urdf_in' and/or 'calibration_urdf_out' are empty..." 00162 00163 # verbose mode 00164 if self.verbose: 00165 print "--> results:" 00166 np.set_printoptions(suppress=1) 00167 print "left\n----" 00168 print "rms left monocular calibration:", rms_l 00169 print "camera matrix:\n", camera_matrix_l 00170 print "distortion coefficients:\n", dist_coeffs_l 00171 print "rectification matrix:\n", rectification_matrix_l 00172 print "projection matrix:\n", projection_matrix_l 00173 print 00174 print "right\n-----" 00175 print "rms right monocular calibration:", rms_r 00176 print "camera matrix:\n", camera_matrix_r 00177 print "distortion coefficients:\n", dist_coeffs_r 00178 print "rectification matrix:\n", rectification_matrix_r 00179 print "projection matrix:\n", projection_matrix_r 00180 print 00181 print "baseline (transform from left to right camera)\n--------" 00182 print "R (in rpy):\n", R_inv 00183 print "T (in xyz):\n", T_inv 00184 00185 if __name__ == '__main__': 00186 node = StereoCalibrationNode() 00187 node.run_stereo_calibration() 00188 print "==> done! exiting..."