$search
00001 /**************************************************************************** 00002 * 00003 * $Id: file.cpp 3496 2011-11-22 15:14:32Z fnovotny $ 00004 * 00005 * This file is part of the ViSP software. 00006 * Copyright (C) 2005 - 2012 by INRIA. All rights reserved. 00007 * 00008 * This software is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * ("GPL") version 2 as published by the Free Software Foundation. 00011 * See the file LICENSE.txt at the root directory of this source 00012 * distribution for additional information about the GNU GPL. 00013 * 00014 * For using ViSP with software that can not be combined with the GNU 00015 * GPL, please contact INRIA about acquiring a ViSP Professional 00016 * Edition License. 00017 * 00018 * See http://www.irisa.fr/lagadic/visp/visp.html for more information. 00019 * 00020 * This software was developed at: 00021 * INRIA Rennes - Bretagne Atlantique 00022 * Campus Universitaire de Beaulieu 00023 * 35042 Rennes Cedex 00024 * France 00025 * http://www.irisa.fr/lagadic 00026 * 00027 * If you have questions regarding the use of this file, please contact 00028 * INRIA at visp@inria.fr 00029 * 00030 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00031 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00032 * 00033 * Contact visp@irisa.fr if any conditions of this licensing are 00034 * not clear to you. 00035 * 00036 * Description: 00037 * 00038 * 00039 * Authors: 00040 * Filip Novotny 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 "conversions/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 { 00083 visp_camera_calibration::remap(); 00084 //Setup ROS environment 00085 //prepare function objects,define publishers & subscribers 00086 raw_image_subscriber_callback_t raw_image_callback = boost::bind(&ImageProcessing::rawImageCallback, this, _1); 00087 00088 set_camera_info_bis_service_callback_t set_camera_info_bis_callback = boost::bind(&ImageProcessing::setCameraInfoBisCallback, this, _1,_2); 00089 00090 raw_image_subscriber_ = n_.subscribe(visp_camera_calibration::raw_image_topic, queue_size_, 00091 raw_image_callback); 00092 00093 calibrate_service_ = n_.serviceClient<visp_camera_calibration::calibrate> (visp_camera_calibration::calibrate_service); 00094 00095 point_correspondence_publisher_ = n_.advertise<visp_camera_calibration::CalibPointArray>(visp_camera_calibration::point_correspondence_topic, queue_size_); 00096 set_camera_info_bis_service_ = n_.advertiseService(visp_camera_calibration::set_camera_info_bis_service,set_camera_info_bis_callback); 00097 00098 //init graphical interface 00099 vpDisplay* disp = new vpDisplayX(); 00100 disp->init(img_); 00101 disp->setTitle("Image processing initialisation interface"); 00102 vpDisplay::flush(img_); 00103 vpDisplay::display(img_); 00104 vpDisplay::displayCharString(img_,img_.getHeight()/2-10,img_.getWidth()/4,"Waiting for the camera feed.",vpColor::red); 00105 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); 00106 00107 vpDisplay::flush(img_); 00108 00109 // read 3D model from parameters 00110 XmlRpc::XmlRpcValue model_points_x_list; 00111 XmlRpc::XmlRpcValue model_points_y_list; 00112 XmlRpc::XmlRpcValue model_points_z_list; 00113 ros::param::get(visp_camera_calibration::model_points_x_param,model_points_x_list); 00114 ros::param::get(visp_camera_calibration::model_points_y_param,model_points_y_list); 00115 ros::param::get(visp_camera_calibration::model_points_z_param,model_points_z_list); 00116 00117 ROS_ASSERT(model_points_x_list.getType() == XmlRpc::XmlRpcValue::TypeArray); 00118 ROS_ASSERT(model_points_x_list.size() == model_points_y_list.size() && model_points_x_list.size()==model_points_z_list.size()); 00119 for(int i=0;i<model_points_x_list.size();i++){ 00120 ROS_ASSERT(model_points_x_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00121 ROS_ASSERT(model_points_y_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00122 ROS_ASSERT(model_points_z_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00123 double X = static_cast<double>(model_points_x_list[i]); 00124 double Y = static_cast<double>(model_points_y_list[i]); 00125 double Z = static_cast<double>(model_points_z_list[i]); 00126 vpPoint p; 00127 p.setWorldCoordinates(X,Y,Z); 00128 model_points_.push_back(p); 00129 } 00130 00131 //define selected model points 00132 XmlRpc::XmlRpcValue selected_points_x_list; 00133 XmlRpc::XmlRpcValue selected_points_y_list; 00134 XmlRpc::XmlRpcValue selected_points_z_list; 00135 00136 ros::param::get(visp_camera_calibration::selected_points_x_param,selected_points_x_list); 00137 ros::param::get(visp_camera_calibration::selected_points_y_param,selected_points_y_list); 00138 ros::param::get(visp_camera_calibration::selected_points_z_param,selected_points_z_list); 00139 ROS_ASSERT(selected_points_x_list.size() == selected_points_y_list.size() && selected_points_x_list.size()==selected_points_z_list.size()); 00140 00141 for(int i=0;i<selected_points_x_list.size();i++){ 00142 ROS_ASSERT(selected_points_x_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00143 ROS_ASSERT(selected_points_y_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00144 ROS_ASSERT(selected_points_z_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble); 00145 double X = static_cast<double>(selected_points_x_list[i]); 00146 double Y = static_cast<double>(selected_points_y_list[i]); 00147 double Z = static_cast<double>(selected_points_z_list[i]); 00148 vpPoint p; 00149 p.setWorldCoordinates(X,Y,Z); 00150 selected_points_.push_back(p); 00151 } 00152 00153 //init camera 00154 double px = cam_.get_px(); 00155 double py = cam_.get_px(); 00156 double u0 = img_.getWidth()/2; 00157 double v0 = img_.getHeight()/2; 00158 cam_.initPersProjWithoutDistortion(px, py, u0, v0); 00159 00160 } 00161 00162 bool ImageProcessing::setCameraInfoBisCallback(sensor_msgs::SetCameraInfo::Request &req, 00163 sensor_msgs::SetCameraInfo::Response &res){ 00164 std::string calibration_path; 00165 ros::param::getCached(visp_camera_calibration::calibration_path_param,calibration_path); 00166 ROS_INFO("saving calibration file to %s",calibration_path.c_str()); 00167 camera_calibration_parsers::writeCalibration(calibration_path,visp_camera_calibration::raw_image_topic,req.camera_info); 00168 return true; 00169 } 00170 void ImageProcessing::rawImageCallback(const sensor_msgs::Image::ConstPtr& image){ 00171 ros::Rate loop_rate(200); 00172 double gray_level_precision; 00173 double size_precision; 00174 bool pause_at_each_frame = false; //Wait for user input each time a new frame is recieved. 00175 00176 ros::param::getCached(visp_camera_calibration::gray_level_precision_param,gray_level_precision); 00177 ros::param::getCached(visp_camera_calibration::size_precision_param,size_precision); 00178 ros::param::getCached(visp_camera_calibration::pause_at_each_frame_param,pause_at_each_frame); 00179 00180 00181 vpPose pose; 00182 vpCalibration calib; 00183 visp_camera_calibration::CalibPointArray calib_all_points; 00184 00185 img_ = visp_bridge::toVispImage(*image); 00186 00187 vpDisplay::display(img_); 00188 vpDisplay::flush(img_); 00189 00190 if(!pause_at_each_frame){ 00191 vpImagePoint ip; 00192 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true); 00193 vpDisplay::displayCharString(img_,10,10,"Click on the window to select the current image",vpColor::red); 00194 vpDisplay::flush(img_); 00195 if(pause_image_){ 00196 pause_image_= false; 00197 } 00198 else{ 00199 return; 00200 } 00201 } 00202 00203 pose.clearPoint(); 00204 calib.clearPoint(); 00205 vpImagePoint ip; 00206 00207 //lets the user select keypoints 00208 for(unsigned int i=0;i<selected_points_.size();i++){ 00209 try{ 00210 vpDot2 d; 00211 d.setGrayLevelPrecision(gray_level_precision); 00212 d.setSizePrecision(size_precision); 00213 00214 ROS_INFO("Click on point %d",i+1); 00215 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true); 00216 vpDisplay::displayCharString(img_,10,10,boost::str(boost::format("click on point %1%") % (i+1)).c_str(),vpColor::red); 00217 vpDisplay::flush(img_); 00218 while(ros::ok() && !vpDisplay::getClick(img_,ip,false)); 00219 00220 d.initTracking(img_, ip); 00221 00222 ip.set_ij(d.getCog().get_i(),d.getCog().get_j()); 00223 double x=0,y=0; 00224 vpPixelMeterConversion::convertPoint(cam_, ip, x, y); 00225 selected_points_[i].set_x(x); 00226 selected_points_[i].set_y(y); 00227 pose.addPoint(selected_points_[i]); 00228 calib.addPoint(selected_points_[i].get_oX(),selected_points_[i].get_oY(),selected_points_[i].get_oZ(), ip); 00229 00230 vpDisplay::displayCross(img_, d.getCog(), 10, vpColor::red); 00231 vpDisplay::flush(img_); 00232 }catch(vpTrackingException e){ 00233 ROS_ERROR("Failed to init point"); 00234 } 00235 } 00236 00237 00238 vpHomogeneousMatrix cMo; 00239 pose.computePose(vpPose::LAGRANGE, cMo) ; 00240 pose.computePose(vpPose::VIRTUAL_VS, cMo) ; 00241 vpHomogeneousMatrix cMoTmp = cMo; 00242 00243 vpCameraParameters camTmp = cam_; 00244 //compute local calibration to match the calibration grid with the image 00245 try{ 00246 calib.computeCalibration(vpCalibration::CALIB_VIRTUAL_VS,cMoTmp,camTmp,false); 00247 ROS_DEBUG_STREAM("cMo="<<std::endl <<cMoTmp<<std::endl); 00248 ROS_DEBUG_STREAM("cam="<<std::endl <<camTmp<<std::endl); 00249 00250 //project all points and track their corresponding image location 00251 for (std::vector<vpPoint>::iterator model_point_iter= model_points_.begin(); 00252 model_point_iter!= model_points_.end() ; 00253 model_point_iter++){ 00254 //project each model point into image according to current calibration 00255 vpColVector _cP, _p ; 00256 00257 model_point_iter->changeFrame(cMoTmp,_cP) ; 00258 model_point_iter->projection(_cP,_p) ; 00259 vpMeterPixelConversion::convertPoint(camTmp,_p[0],_p[1], ip); 00260 if (10 < ip.get_u() && ip.get_u() < img_.getWidth()-10 && 00261 10 < ip.get_v() && ip.get_v() < img_.getHeight()-10) { 00262 try { 00263 //track the projected point, look for match 00264 vpDot2 md; 00265 md.setGrayLevelPrecision(gray_level_precision); 00266 md.setSizePrecision(size_precision); 00267 00268 md.initTracking(img_, ip); 00269 if(!ros::ok()) 00270 return; 00271 00272 vpRect bbox = md.getBBox(); 00273 vpImagePoint cog = md.getCog(); 00274 if(bbox.getLeft()<5 || bbox.getRight()>(double)img_.getWidth()-5 || 00275 bbox.getTop()<5 || bbox.getBottom()>(double)img_.getHeight()-5|| 00276 vpMath::abs(ip.get_u() - cog.get_u()) > 10 || 00277 vpMath::abs(ip.get_v() - cog.get_v()) > 10){ 00278 ROS_DEBUG("tracking failed[suspicious point location]."); 00279 }else{ 00280 //point matches 00281 double x=0, y=0; 00282 vpPixelMeterConversion::convertPoint(camTmp, cog, x, y) ; 00283 model_point_iter->set_x(x) ; 00284 model_point_iter->set_y(y) ; 00285 00286 md.display(img_,vpColor::yellow, 2); 00287 visp_camera_calibration::CalibPoint cp; 00288 cp.i = cog.get_i(); 00289 cp.j = cog.get_j(); 00290 cp.X = model_point_iter->get_oX(); 00291 cp.Y = model_point_iter->get_oY(); 00292 cp.Z = model_point_iter->get_oZ(); 00293 00294 calib_all_points.points.push_back(cp); 00295 00296 model_point_iter->display(img_,cMoTmp,camTmp) ; 00297 loop_rate.sleep(); //To avoid refresh problems 00298 vpDisplay::flush(img_); 00299 } 00300 } catch(...){ 00301 ROS_DEBUG("tracking failed."); 00302 } 00303 } else { 00304 ROS_DEBUG("bad projection."); 00305 } 00306 } 00307 00308 ROS_INFO("Left click on the interface window to continue, right click to restart"); 00309 vpDisplay::displayRectangle(img_,0,0,img_.getWidth(),15,vpColor::black,true); 00310 vpDisplay::displayCharString(img_,10,10,"Left click on the interface window to continue, right click to restart",vpColor::red); 00311 vpDisplay::flush(img_); 00312 00313 vpMouseButton::vpMouseButtonType btn; 00314 while(ros::ok() && !vpDisplay::getClick(img_,ip,btn, false)); 00315 00316 if(btn==vpMouseButton::button1) 00317 point_correspondence_publisher_.publish(calib_all_points); 00318 else{ 00319 rawImageCallback(image); 00320 return; 00321 } 00322 }catch(...){ 00323 ROS_ERROR("calibration failed."); 00324 } 00325 } 00326 00327 void ImageProcessing::interface() 00328 { 00329 vpImagePoint ip; 00330 while(ros::ok()){ 00331 ros::spinOnce(); 00332 if(vpDisplay::getClick(img_,ip,false)) 00333 pause_image_ = true; 00334 } 00335 ros::waitForShutdown(); 00336 } 00337 00338 ImageProcessing::~ImageProcessing() 00339 { 00340 // TODO Auto-generated destructor stub 00341 } 00342 }