00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00050 #include "image_processing.h"
00051 #include "visp/vpTrackingException.h"
00052 #include "visp_camera_calibration/CalibPointArray.h"
00053 #include "visp_camera_calibration/CalibPoint.h"
00054 #include "visp_camera_calibration/calibrate.h"
00055 #include "visp/vpMouseButton.h"
00056
00057 #include "names.h"
00058 #include <visp_bridge/image.h>
00059 #include "sensor_msgs/SetCameraInfo.h"
00060 #include "camera_calibration_parsers/parse.h"
00061
00062 #include "visp/vpDisplayX.h"
00063 #include "visp/vpImagePoint.h"
00064 #include "visp/vpPixelMeterConversion.h"
00065 #include "visp/vpMeterPixelConversion.h"
00066 #include "visp/vpPose.h"
00067 #include "visp/vpHomogeneousMatrix.h"
00068 #include "visp/vpDot.h"
00069 #include "visp/vpDot2.h"
00070 #include "visp/vpCalibration.h"
00071 #include <iostream>
00072
00073
00074 namespace visp_camera_calibration
00075 {
00076 ImageProcessing::ImageProcessing() :
00077 spinner_(0),
00078 queue_size_(1000),
00079 pause_image_(false),
00080 img_(480,640,128),
00081 cam_(600,600,0,0),
00082 is_initialized(false)
00083 {
00084 visp_camera_calibration::remap();
00085
00086
00087 raw_image_subscriber_callback_t raw_image_callback = boost::bind(&ImageProcessing::rawImageCallback, this, _1);
00088
00089 set_camera_info_bis_service_callback_t set_camera_info_bis_callback = boost::bind(&ImageProcessing::setCameraInfoBisCallback, this, _1,_2);
00090
00091 raw_image_subscriber_ = n_.subscribe(visp_camera_calibration::raw_image_topic, queue_size_,
00092 raw_image_callback);
00093
00094 calibrate_service_ = n_.serviceClient<visp_camera_calibration::calibrate> (visp_camera_calibration::calibrate_service);
00095
00096 point_correspondence_publisher_ = n_.advertise<visp_camera_calibration::CalibPointArray>(visp_camera_calibration::point_correspondence_topic, queue_size_);
00097 set_camera_info_bis_service_ = n_.advertiseService(visp_camera_calibration::set_camera_info_bis_service,set_camera_info_bis_callback);
00098
00099
00100 XmlRpc::XmlRpcValue model_points_x_list;
00101 XmlRpc::XmlRpcValue model_points_y_list;
00102 XmlRpc::XmlRpcValue model_points_z_list;
00103 ros::param::get(visp_camera_calibration::model_points_x_param,model_points_x_list);
00104 ros::param::get(visp_camera_calibration::model_points_y_param,model_points_y_list);
00105 ros::param::get(visp_camera_calibration::model_points_z_param,model_points_z_list);
00106
00107 ROS_ASSERT(model_points_x_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00108 ROS_ASSERT(model_points_x_list.size() == model_points_y_list.size() && model_points_x_list.size()==model_points_z_list.size());
00109 for(int i=0;i<model_points_x_list.size();i++){
00110 ROS_ASSERT(model_points_x_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00111 ROS_ASSERT(model_points_y_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00112 ROS_ASSERT(model_points_z_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00113 double X = static_cast<double>(model_points_x_list[i]);
00114 double Y = static_cast<double>(model_points_y_list[i]);
00115 double Z = static_cast<double>(model_points_z_list[i]);
00116 vpPoint p;
00117 p.setWorldCoordinates(X,Y,Z);
00118 model_points_.push_back(p);
00119 }
00120
00121
00122 XmlRpc::XmlRpcValue selected_points_x_list;
00123 XmlRpc::XmlRpcValue selected_points_y_list;
00124 XmlRpc::XmlRpcValue selected_points_z_list;
00125
00126 ros::param::get(visp_camera_calibration::selected_points_x_param,selected_points_x_list);
00127 ros::param::get(visp_camera_calibration::selected_points_y_param,selected_points_y_list);
00128 ros::param::get(visp_camera_calibration::selected_points_z_param,selected_points_z_list);
00129 ROS_ASSERT(selected_points_x_list.size() == selected_points_y_list.size() && selected_points_x_list.size()==selected_points_z_list.size());
00130
00131 for(int i=0;i<selected_points_x_list.size();i++){
00132 ROS_ASSERT(selected_points_x_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00133 ROS_ASSERT(selected_points_y_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00134 ROS_ASSERT(selected_points_z_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00135 double X = static_cast<double>(selected_points_x_list[i]);
00136 double Y = static_cast<double>(selected_points_y_list[i]);
00137 double Z = static_cast<double>(selected_points_z_list[i]);
00138 vpPoint p;
00139 p.setWorldCoordinates(X,Y,Z);
00140 selected_points_.push_back(p);
00141 }
00142 }
00143
00144 void ImageProcessing::init()
00145 {
00146 if (! is_initialized) {
00147
00148 vpDisplay* disp = new vpDisplayX();
00149 disp->init(img_);
00150 disp->setTitle("Image processing initialisation interface");
00151 vpDisplay::flush(img_);
00152 vpDisplay::display(img_);
00153 vpDisplay::displayCharString(img_,img_.getHeight()/2-10,img_.getWidth()/4,"Waiting for the camera feed.",vpColor::red);
00154 vpDisplay::displayCharString(img_,img_.getHeight()/2+10,img_.getWidth()/4,"If you are using the example camera, you should click on it's window",vpColor::red);
00155
00156 vpDisplay::flush(img_);
00157
00158
00159 double px = cam_.get_px();
00160 double py = cam_.get_px();
00161 double u0 = img_.getWidth()/2;
00162 double v0 = img_.getHeight()/2;
00163 cam_.initPersProjWithoutDistortion(px, py, u0, v0);
00164
00165 is_initialized = true;
00166 }
00167 }
00168
00169 bool ImageProcessing::setCameraInfoBisCallback(sensor_msgs::SetCameraInfo::Request &req,
00170 sensor_msgs::SetCameraInfo::Response &res){
00171 std::string calibration_path;
00172 ros::param::getCached(visp_camera_calibration::calibration_path_param,calibration_path);
00173 ROS_INFO("saving calibration file to %s",calibration_path.c_str());
00174 camera_calibration_parsers::writeCalibration(calibration_path,visp_camera_calibration::raw_image_topic,req.camera_info);
00175 return true;
00176 }
00177
00178 void ImageProcessing::rawImageCallback(const sensor_msgs::Image::ConstPtr& image){
00179 ros::Rate loop_rate(200);
00180 double gray_level_precision;
00181 double size_precision;
00182 bool pause_at_each_frame = false;
00183
00184 ros::param::getCached(visp_camera_calibration::gray_level_precision_param,gray_level_precision);
00185 ros::param::getCached(visp_camera_calibration::size_precision_param,size_precision);
00186 ros::param::getCached(visp_camera_calibration::pause_at_each_frame_param,pause_at_each_frame);
00187
00188
00189 vpPose pose;
00190 vpCalibration calib;
00191 visp_camera_calibration::CalibPointArray calib_all_points;
00192
00193 img_ = visp_bridge::toVispImage(*image);
00194
00195 init();
00196
00197 vpDisplay::display(img_);
00198 vpDisplay::flush(img_);
00199
00200 if(!pause_at_each_frame){
00201 vpImagePoint ip;
00202 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true);
00203 vpDisplay::displayCharString(img_,10,10,"Click on the window to select the current image",vpColor::red);
00204 vpDisplay::flush(img_);
00205 if(pause_image_){
00206 pause_image_= false;
00207 }
00208 else{
00209 return;
00210 }
00211 }
00212
00213 pose.clearPoint();
00214 calib.clearPoint();
00215 vpImagePoint ip;
00216
00217
00218 for(unsigned int i=0;i<selected_points_.size();i++){
00219 try{
00220 vpDot2 d;
00221 d.setGrayLevelPrecision(gray_level_precision);
00222 d.setSizePrecision(size_precision);
00223
00224 ROS_INFO("Click on point %d",i+1);
00225 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true);
00226 vpDisplay::displayCharString(img_,10,10,boost::str(boost::format("click on point %1%") % (i+1)).c_str(),vpColor::red);
00227 vpDisplay::flush(img_);
00228 while(ros::ok() && !vpDisplay::getClick(img_,ip,false));
00229
00230 d.initTracking(img_, ip);
00231
00232 ip.set_ij(d.getCog().get_i(),d.getCog().get_j());
00233 double x=0,y=0;
00234 vpPixelMeterConversion::convertPoint(cam_, ip, x, y);
00235 selected_points_[i].set_x(x);
00236 selected_points_[i].set_y(y);
00237 pose.addPoint(selected_points_[i]);
00238 calib.addPoint(selected_points_[i].get_oX(),selected_points_[i].get_oY(),selected_points_[i].get_oZ(), ip);
00239
00240 vpDisplay::displayCross(img_, d.getCog(), 10, vpColor::red);
00241 vpDisplay::flush(img_);
00242 }catch(vpTrackingException e){
00243 ROS_ERROR("Failed to init point");
00244 }
00245 }
00246
00247
00248 vpHomogeneousMatrix cMo;
00249 pose.computePose(vpPose::LAGRANGE, cMo) ;
00250 pose.computePose(vpPose::VIRTUAL_VS, cMo) ;
00251 vpHomogeneousMatrix cMoTmp = cMo;
00252
00253 vpCameraParameters camTmp = cam_;
00254
00255 try{
00256 calib.computeCalibration(vpCalibration::CALIB_VIRTUAL_VS,cMoTmp,camTmp,false);
00257 ROS_DEBUG_STREAM("cMo="<<std::endl <<cMoTmp<<std::endl);
00258 ROS_DEBUG_STREAM("cam="<<std::endl <<camTmp<<std::endl);
00259
00260
00261 for (std::vector<vpPoint>::iterator model_point_iter= model_points_.begin();
00262 model_point_iter!= model_points_.end() ;
00263 model_point_iter++){
00264
00265 vpColVector _cP, _p ;
00266
00267 model_point_iter->changeFrame(cMoTmp,_cP) ;
00268 model_point_iter->projection(_cP,_p) ;
00269 vpMeterPixelConversion::convertPoint(camTmp,_p[0],_p[1], ip);
00270 if (10 < ip.get_u() && ip.get_u() < img_.getWidth()-10 &&
00271 10 < ip.get_v() && ip.get_v() < img_.getHeight()-10) {
00272 try {
00273
00274 vpDot2 md;
00275 md.setGrayLevelPrecision(gray_level_precision);
00276 md.setSizePrecision(size_precision);
00277
00278 md.initTracking(img_, ip);
00279 if(!ros::ok())
00280 return;
00281
00282 vpRect bbox = md.getBBox();
00283 vpImagePoint cog = md.getCog();
00284 if(bbox.getLeft()<5 || bbox.getRight()>(double)img_.getWidth()-5 ||
00285 bbox.getTop()<5 || bbox.getBottom()>(double)img_.getHeight()-5||
00286 vpMath::abs(ip.get_u() - cog.get_u()) > 10 ||
00287 vpMath::abs(ip.get_v() - cog.get_v()) > 10){
00288 ROS_DEBUG("tracking failed[suspicious point location].");
00289 }else{
00290
00291 double x=0, y=0;
00292 vpPixelMeterConversion::convertPoint(camTmp, cog, x, y) ;
00293 model_point_iter->set_x(x) ;
00294 model_point_iter->set_y(y) ;
00295
00296 md.display(img_,vpColor::yellow, 2);
00297 visp_camera_calibration::CalibPoint cp;
00298 cp.i = cog.get_i();
00299 cp.j = cog.get_j();
00300 cp.X = model_point_iter->get_oX();
00301 cp.Y = model_point_iter->get_oY();
00302 cp.Z = model_point_iter->get_oZ();
00303
00304 calib_all_points.points.push_back(cp);
00305
00306 model_point_iter->display(img_,cMoTmp,camTmp) ;
00307 loop_rate.sleep();
00308 vpDisplay::flush(img_);
00309 }
00310 } catch(...){
00311 ROS_DEBUG("tracking failed.");
00312 }
00313 } else {
00314 ROS_DEBUG("bad projection.");
00315 }
00316 }
00317
00318 ROS_INFO("Left click on the interface window to continue, right click to restart");
00319 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true);
00320 vpDisplay::displayCharString(img_,10,10,"Left click on the interface window to continue, right click to restart",vpColor::red);
00321 vpDisplay::flush(img_);
00322
00323 vpMouseButton::vpMouseButtonType btn;
00324 while(ros::ok() && !vpDisplay::getClick(img_,ip,btn, false));
00325
00326 if(btn==vpMouseButton::button1)
00327 point_correspondence_publisher_.publish(calib_all_points);
00328 else{
00329 rawImageCallback(image);
00330 return;
00331 }
00332 }catch(...){
00333 ROS_ERROR("calibration failed.");
00334 }
00335 }
00336
00337 void ImageProcessing::interface()
00338 {
00339 vpImagePoint ip;
00340 while(ros::ok()){
00341 ros::spinOnce();
00342 if(vpDisplay::getClick(img_,ip,false))
00343 pause_image_ = true;
00344 }
00345 ros::waitForShutdown();
00346 }
00347
00348 ImageProcessing::~ImageProcessing()
00349 {
00350
00351 }
00352 }