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 #include <algorithm>
00028
00029 #include <cstdio>
00030 #include <vector>
00031 #include <sstream>
00032 #include <algorithm>
00033 #include <ros/ros.h>
00034
00035 #include <boost/thread/mutex.hpp>
00036
00037 #include "opencv2/opencv.hpp"
00038 #include "cv_bridge/cv_bridge.h"
00039 #include "sensor_msgs/image_encodings.h"
00040 #include "sensor_msgs/CameraInfo.h"
00041 #include "sensor_msgs/Image.h"
00042 #include "image_geometry/pinhole_camera_model.h"
00043 #include "posedetection_msgs/ObjectDetection.h"
00044 #include "posedetection_msgs/Detect.h"
00045 #include "geometry_msgs/PointStamped.h"
00046 #include "geometry_msgs/PoseStamped.h"
00047 #include "math.h"
00048 #include "geometry_msgs/PolygonStamped.h"
00049 #include "jsk_recognition_msgs/PolygonArray.h"
00050 #include "eigen_conversions/eigen_msg.h"
00051 #include <sys/timeb.h>
00052 #include <sys/time.h>
00053
00054 using namespace std;
00055 using namespace ros;
00056
00057 class CheckerboardDetector
00058 {
00059 template <typename T>
00060 static vector<T> tokenizevector(const string& s)
00061 {
00062 stringstream ss(s);
00063 return vector<T>((istream_iterator<T>(ss)), istream_iterator<T>());
00064 }
00065
00066 public:
00067 struct CHECKERBOARD
00068 {
00069 CvSize griddims;
00070 vector<cv::Point3f> grid3d;
00071
00072
00073 vector<cv::Point2f> corners;
00074 TransformMatrix tlocaltrans;
00075 std::string board_type;
00076 };
00077
00078 posedetection_msgs::ObjectDetection _objdetmsg;
00079 sensor_msgs::CameraInfo _camInfoMsg;
00080
00081 ros::Subscriber camInfoSubscriber,camInfoSubscriber2;
00082 ros::Subscriber imageSubscriber,imageSubscriber2;
00083 ros::Publisher _pubDetection;
00084 ros::Publisher _pubPoseStamped;
00085 ros::Publisher _pubCornerPoint;
00086 ros::Publisher _pubPolygonArray;
00087 ros::ServiceServer _srvDetect;
00088 int message_throttle_;
00089 int message_throttle_counter_;
00090 string frame_id;
00091 bool invert_color;
00092 int display, verbose, maxboard;
00093 vector<CHECKERBOARD> vcheckers;
00094 vector< string > vstrtypes;
00095 map<string,int> maptypes;
00096 ros::Time lasttime;
00097 boost::mutex mutexcalib;
00098 ros::NodeHandle _node;
00099 int dimx, dimy;
00100 bool use_P;
00101 double fRectSize[2];
00102
00104
00105 CheckerboardDetector()
00106 {
00107 _node.param("display", display, 0);
00108 _node.param("verbose", verbose, 1);
00109 _node.param("maxboard", maxboard, -1);
00110 _node.param("invert_color", invert_color, false);
00111 _node.param("use_P", use_P, false);
00112 _node.param("message_throttle", message_throttle_, 1);
00113 char str[32];
00114 int index = 0;
00115
00116 while(1) {
00117 string type;
00118
00119 sprintf(str,"grid%d_size_x",index);
00120 if( !_node.getParam(str,dimx) )
00121 break;
00122 if (dimx < 3) {
00123 ROS_ERROR("Param: %s must be greater than 2",str);
00124 return;
00125 }
00126
00127 sprintf(str,"grid%d_size_y",index);
00128 if( !_node.getParam(str,dimy) )
00129 break;
00130 if (dimy < 3) {
00131 ROS_ERROR("Param: %s must be greater than 2",str);
00132 return;
00133 }
00134
00135 sprintf(str,"rect%d_size_x",index);
00136 if( !_node.getParam(str,fRectSize[0]) )
00137 break;
00138
00139 sprintf(str,"rect%d_size_y",index);
00140 if( !_node.getParam(str,fRectSize[1]) )
00141 break;
00142
00143 sprintf(str,"type%d",index);
00144 if( !_node.getParam(str,type) ) {
00145 sprintf(str,"checker%dx%d", dimx, dimy);
00146 type = str;
00147 }
00148
00149 std::string board_type;
00150 _node.param("board_type", board_type, std::string("chess"));
00151
00152
00153 string strtranslation,strrotation;
00154 sprintf(str,"translation%d",index);
00155 _node.param(str,strtranslation,string());
00156
00157 vector<float> vtranslation = tokenizevector<float>(strtranslation);
00158 sprintf(str,"rotation%d",index);
00159 _node.param(str,strrotation,string());
00160
00161 vector<float> vrotation = tokenizevector<float>(strrotation);
00162
00163 CHECKERBOARD cb;
00164 cb.griddims = cvSize(dimx,dimy);
00165 cb.board_type = board_type;
00166 cb.grid3d.resize(dimx*dimy);
00167 int j=0;
00168 if (board_type == "chess" || board_type == "circle") {
00169 for(int y=0; y<dimy; ++y)
00170 for(int x=0; x<dimx; ++x)
00171 cb.grid3d[j++] = cv::Point3f(x*fRectSize[0], y*fRectSize[1], 0);
00172 }
00173 else if (board_type == "acircle") {
00174 for(int ii=0; ii<dimy; ii++) {
00175 for(int jj=0; jj<dimx; jj++) {
00176 cb.grid3d[j++] = cv::Point3f((2*jj + ii % 2)*fRectSize[0],
00177 ii*fRectSize[1],
00178 0);
00179 }
00180 }
00181 }
00182
00183 if( vtranslation.size() == 3 )
00184 cb.tlocaltrans.trans =
00185 Vector(vtranslation[0],vtranslation[1],vtranslation[2]);
00186
00187 if( vrotation.size() == 9 ) {
00188 for(int k = 0; k < 3; ++k) {
00189 cb.tlocaltrans.m[4*k+0] = vrotation[3*k+0];
00190 cb.tlocaltrans.m[4*k+1] = vrotation[3*k+1];
00191 cb.tlocaltrans.m[4*k+2] = vrotation[3*k+2];
00192 }
00193 }
00194
00195 vcheckers.push_back(cb);
00196 vstrtypes.push_back(type);
00197 maptypes[vstrtypes.back()] = index;
00198 index++;
00199 }
00200
00201 _node.param("frame_id", frame_id,string(""));
00202
00203 if( maptypes.size() == 0 ) {
00204 ROS_ERROR("no checkerboards to detect");
00205 return;
00206 }
00207
00208 if( display ) {
00209 cv::namedWindow("Checkerboard Detector",
00210 (display == 1? CV_WINDOW_AUTOSIZE : display));
00211 }
00212
00213 lasttime = ros::Time::now();
00214 if (!display) {
00215 ros::SubscriberStatusCallback connect_cb = boost::bind( &CheckerboardDetector::connectCb, this);
00216 _pubDetection =
00217 _node.advertise<posedetection_msgs::ObjectDetection> ("ObjectDetection", 1,
00218 connect_cb, connect_cb);
00219 _pubPoseStamped =
00220 _node.advertise<geometry_msgs::PoseStamped> ("objectdetection_pose", 1,
00221 connect_cb, connect_cb);
00222 _pubCornerPoint = _node.advertise<geometry_msgs::PointStamped>("corner_point", 1, connect_cb, connect_cb);
00223 _pubPolygonArray = _node.advertise<jsk_recognition_msgs::PolygonArray>("polygons", 1, connect_cb, connect_cb);
00224 }
00225 else {
00226 _pubDetection =
00227 _node.advertise<posedetection_msgs::ObjectDetection> ("ObjectDetection", 1);
00228 _pubPoseStamped =
00229 _node.advertise<geometry_msgs::PoseStamped> ("objectdetection_pose", 1);
00230 _pubCornerPoint = _node.advertise<geometry_msgs::PointStamped>("corner_point", 1);
00231 _pubPolygonArray = _node.advertise<jsk_recognition_msgs::PolygonArray>("polygons", 1);
00232 subscribe();
00233 }
00234
00235
00236
00237
00238 _srvDetect = _node.advertiseService("Detect",&CheckerboardDetector::detect_cb,this);
00239 }
00240
00242
00243 virtual ~CheckerboardDetector()
00244 {
00245 }
00246
00248
00249 void caminfo_cb(const sensor_msgs::CameraInfoConstPtr &msg)
00250 {
00251 boost::mutex::scoped_lock lock(this->mutexcalib);
00252
00253 this->_camInfoMsg = *msg;
00254
00255
00256
00257
00258 }
00259 void caminfo_cb2(const sensor_msgs::CameraInfoConstPtr &msg)
00260 {
00261 ROS_WARN("The topic CameraInfo has been deprecated. Please change your launch file to use camera_info instead.");
00262 caminfo_cb(msg);
00263 }
00264
00265 void publishPolygonArray(const posedetection_msgs::ObjectDetection& obj)
00266 {
00267 jsk_recognition_msgs::PolygonArray polygon_array;
00268 polygon_array.header = obj.header;
00269 for (size_t i = 0; i < obj.objects.size(); i++) {
00270 geometry_msgs::Pose pose = obj.objects[i].pose;
00271 Eigen::Affine3d affine;
00272 tf::poseMsgToEigen(pose, affine);
00273 Eigen::Vector3d A_local(0, 0, 0);
00274 Eigen::Vector3d B_local((dimx - 1) * fRectSize[0], 0, 0);
00275 Eigen::Vector3d C_local((dimx - 1) * fRectSize[0], (dimy - 1) * fRectSize[1], 0);
00276 Eigen::Vector3d D_local(0, (dimy - 1) * fRectSize[1], 0);
00277 Eigen::Vector3d A_global = affine * A_local;
00278 Eigen::Vector3d B_global = affine * B_local;
00279 Eigen::Vector3d C_global = affine * C_local;
00280 Eigen::Vector3d D_global = affine * D_local;
00281 geometry_msgs::Point32 a, b, c, d;
00282 a.x = A_global[0]; a.y = A_global[1]; a.z = A_global[2];
00283 b.x = B_global[0]; b.y = B_global[1]; b.z = B_global[2];
00284 c.x = C_global[0]; c.y = C_global[1]; c.z = C_global[2];
00285 d.x = D_global[0]; d.y = D_global[1]; d.z = D_global[2];
00286 geometry_msgs::PolygonStamped polygon;
00287 polygon.header = obj.header;
00288 polygon.polygon.points.push_back(a);
00289 polygon.polygon.points.push_back(b);
00290 polygon.polygon.points.push_back(c);
00291 polygon.polygon.points.push_back(d);
00292 polygon_array.polygons.push_back(polygon);
00293 }
00294 _pubPolygonArray.publish(polygon_array);
00295 }
00296
00297 void image_cb2(const sensor_msgs::ImageConstPtr &msg)
00298 {
00299 ROS_WARN("The topic Image has been deprecated. Please change your launch file to use image instead.");
00300 boost::mutex::scoped_lock lock(this->mutexcalib);
00301 ++message_throttle_counter_;
00302 if (message_throttle_counter_ % message_throttle_ == 0) {
00303 message_throttle_counter_ = 0;
00304 if( Detect(_objdetmsg,*msg,this->_camInfoMsg) ) {
00305 if (_objdetmsg.objects.size() > 0) {
00306 geometry_msgs::PoseStamped pose;
00307 pose.header = _objdetmsg.header;
00308 pose.pose = _objdetmsg.objects[0].pose;
00309 _pubPoseStamped.publish(pose);
00310 }
00311 _pubDetection.publish(_objdetmsg);
00312 publishPolygonArray(_objdetmsg);
00313 }
00314 }
00315 }
00316
00318
00319 void image_cb(const sensor_msgs::ImageConstPtr &msg)
00320 {
00321 boost::mutex::scoped_lock lock(this->mutexcalib);
00322 ++message_throttle_counter_;
00323 if (message_throttle_counter_ % message_throttle_ == 0) {
00324 message_throttle_counter_ = 0;
00325 if( Detect(_objdetmsg,*msg,this->_camInfoMsg) ) {
00326 if (_objdetmsg.objects.size() > 0) {
00327 geometry_msgs::PoseStamped pose;
00328 pose.header = _objdetmsg.header;
00329 pose.pose = _objdetmsg.objects[0].pose;
00330 _pubPoseStamped.publish(pose);
00331 }
00332 _pubDetection.publish(_objdetmsg);
00333 publishPolygonArray(_objdetmsg);
00334 }
00335 }
00336 }
00337
00338 bool detect_cb(posedetection_msgs::Detect::Request& req, posedetection_msgs::Detect::Response& res)
00339 {
00340 bool result = Detect(res.object_detection,req.image,req.camera_info);
00341 return result;
00342 }
00343
00344
00345 void subscribe( )
00346 {
00347 if ( camInfoSubscriber == NULL )
00348 camInfoSubscriber = _node.subscribe("camera_info", 1, &CheckerboardDetector::caminfo_cb, this);
00349 if ( imageSubscriber == NULL )
00350 imageSubscriber = _node.subscribe("image", 1, &CheckerboardDetector::image_cb, this);
00351 if ( camInfoSubscriber2 == NULL )
00352 camInfoSubscriber2 = _node.subscribe("CameraInfo", 1, &CheckerboardDetector::caminfo_cb2, this);
00353 if ( imageSubscriber2 == NULL )
00354 imageSubscriber2 = _node.subscribe("Image",1, &CheckerboardDetector::image_cb2, this);
00355
00356 }
00357
00358 void unsubscribe( )
00359 {
00360 camInfoSubscriber.shutdown();
00361 camInfoSubscriber2.shutdown();
00362 imageSubscriber.shutdown();
00363 imageSubscriber2.shutdown();
00364 }
00365
00366 void connectCb( )
00367 {
00368 boost::mutex::scoped_lock lock(this->mutexcalib);
00369 if (_pubDetection.getNumSubscribers() == 0 && _pubCornerPoint.getNumSubscribers() == 0 &&
00370 _pubPoseStamped.getNumSubscribers() == 0 && _pubPolygonArray.getNumSubscribers() == 0)
00371 {
00372 unsubscribe();
00373 }
00374 else
00375 {
00376 subscribe();
00377 }
00378 }
00379
00380 bool Detect(posedetection_msgs::ObjectDetection& objdetmsg,
00381 const sensor_msgs::Image& imagemsg,
00382 const sensor_msgs::CameraInfo& camInfoMsg)
00383 {
00384 image_geometry::PinholeCameraModel model;
00385 sensor_msgs::CameraInfo cam_info(camInfoMsg);
00386 if (cam_info.distortion_model.empty()) {
00387 cam_info.distortion_model = "plumb_bob";
00388 cam_info.D.resize(5, 0);
00389 }
00390 if (use_P) {
00391 for (size_t i = 0; i < cam_info.D.size(); i++) {
00392 cam_info.D[i] = 0.0;
00393 }
00394 }
00395
00396
00397 if (use_P || std::equal(cam_info.R.begin() + 1, cam_info.R.end(), cam_info.R.begin())) {
00398 cam_info.R[0] = 1.0;
00399 cam_info.R[4] = 1.0;
00400 cam_info.R[8] = 1.0;
00401 }
00402
00403
00404 if (use_P || std::equal(cam_info.K.begin() + 1, cam_info.K.end(), cam_info.K.begin())) {
00405 cam_info.K[0] = cam_info.P[0];
00406 cam_info.K[1] = cam_info.P[1];
00407 cam_info.K[2] = cam_info.P[2];
00408 cam_info.K[3] = cam_info.P[4];
00409 cam_info.K[4] = cam_info.P[5];
00410 cam_info.K[5] = cam_info.P[6];
00411 cam_info.K[6] = cam_info.P[8];
00412 cam_info.K[7] = cam_info.P[9];
00413 cam_info.K[8] = cam_info.P[10];
00414 }
00415 model.fromCameraInfo(cam_info);
00416 cv_bridge::CvImagePtr capture_ptr;
00417 try {
00418 if (imagemsg.encoding == "32FC1") {
00419 cv_bridge::CvImagePtr float_capture
00420 = cv_bridge::toCvCopy(imagemsg,
00421 sensor_msgs::image_encodings::TYPE_32FC1);
00422 cv::Mat float_image = float_capture->image;
00423 cv::Mat mono_image;
00424 float_image.convertTo(mono_image, CV_8UC1);
00425 capture_ptr.reset(new cv_bridge::CvImage());
00426 capture_ptr->image = mono_image;
00427 }
00428 else {
00429 capture_ptr = cv_bridge::toCvCopy(imagemsg, sensor_msgs::image_encodings::MONO8);
00430 }
00431 } catch (cv_bridge::Exception &e) {
00432 ROS_ERROR("failed to get image %s", e.what());
00433 return false;
00434 }
00435 cv::Mat capture = capture_ptr->image;
00436 if (invert_color) {
00437 capture = cv::Mat((capture + 0.0) * 1.0 / 1.0) * 1.0;
00438
00439 cv::Mat tmp;
00440 cv::bitwise_not(capture, tmp);
00441 capture = tmp;
00442 }
00443
00444 cv::Mat frame;
00445
00446 if( display ) {
00447 cv::cvtColor(capture, frame, CV_GRAY2BGR);
00448 }
00449
00450 vector<posedetection_msgs::Object6DPose> vobjects;
00451
00452 #pragma omp parallel for schedule(dynamic,1)
00453 for(int i = 0; i < (int)vcheckers.size(); ++i) {
00454 CHECKERBOARD& cb = vcheckers[i];
00455 int ncorners, board=0;
00456 posedetection_msgs::Object6DPose objpose;
00457
00458
00459 while((maxboard==-1)?1:((++board)<=maxboard)) {
00460 bool allfound = false;
00461 if (cb.board_type == "chess") {
00462 allfound = cv::findChessboardCorners(
00463 capture, cb.griddims, cb.corners);
00464 }
00465 else if (cb.board_type == "circle" ||
00466 cb.board_type == "circles") {
00467 allfound =
00468 cv::findCirclesGrid(capture, cb.griddims, cb.corners);
00469 }
00470 else if (cb.board_type == "acircle" ||
00471 cb.board_type == "acircles") {
00472
00473 allfound =
00474 cv::findCirclesGrid(
00475 capture, cb.griddims, cb.corners,
00476 cv::CALIB_CB_ASYMMETRIC_GRID | cv::CALIB_CB_CLUSTERING);
00477 }
00478
00479 if(!allfound || cb.corners.size() != cb.grid3d.size())
00480 break;
00481
00482
00483 const int borderthresh = 30;
00484
00485 for(int j = 0; j < ncorners; ++j) {
00486 int x = cb.corners[j].x;
00487 int y = cb.corners[j].y;
00488 if( x < borderthresh || x > capture.cols - borderthresh ||
00489 y < borderthresh || y > capture.rows - borderthresh )
00490 {
00491 allfound = false;
00492 break;
00493 }
00494 }
00495
00496
00497 cv::Point upperleft, lowerright;
00498 upperleft.x = lowerright.x = cb.corners[0].x;
00499 upperleft.y = lowerright.y = cb.corners[0].y;
00500 for(size_t j = 1; j < cb.corners.size(); ++j) {
00501 if( upperleft.x > cb.corners[j].x ) upperleft.x = cb.corners[j].x;
00502 if( upperleft.y > cb.corners[j].y ) upperleft.y = cb.corners[j].y;
00503 if( lowerright.x < cb.corners[j].x ) lowerright.x = cb.corners[j].x;
00504 if( lowerright.y < cb.corners[j].y ) lowerright.y = cb.corners[j].y;
00505 }
00506
00507 float step_size =
00508 (double)( ((upperleft.x - lowerright.x) * (upperleft.x - lowerright.x)) +
00509 ((upperleft.y - lowerright.y) * (upperleft.y - lowerright.y)) )
00510 /
00511 ( ((cb.griddims.width - 1) * (cb.griddims.width - 1)) +
00512 ((cb.griddims.height - 1) * (cb.griddims.height - 1)) );
00513 #if 0
00514 ROS_INFO("(%d %d) - (%d %d) -> %f ",
00515 upperleft.x, upperleft.y, lowerright.x, lowerright.y, sqrt(step_size));
00516 #endif
00517 int size = (int)(0.5*sqrt(step_size) + 0.5);
00518
00519 if( allfound ) {
00520 if (cb.board_type == "chess") {
00521 cv::cornerSubPix(capture, cb.corners,
00522 cv::Size(size,size), cv::Size(-1,-1),
00523 cv::TermCriteria(CV_TERMCRIT_ITER, 50, 1e-2));
00524 }
00525 objpose.pose = FindTransformation(cb.corners, cb.grid3d, cb.tlocaltrans, model);
00526 }
00527
00528 #pragma omp critical
00529 {
00530 if( allfound ) {
00531 vobjects.push_back(objpose);
00532 vobjects.back().type = vstrtypes[i];
00533 }
00534 cv::rectangle(capture, upperleft, lowerright,
00535 cv::Scalar(0,0,0), CV_FILLED);
00536 }
00537 }
00538
00539
00540 }
00541
00542 objdetmsg.objects = vobjects;
00543 objdetmsg.header.stamp = imagemsg.header.stamp;
00544 if( frame_id.size() > 0 )
00545 objdetmsg.header.frame_id = frame_id;
00546 else
00547 objdetmsg.header.frame_id = imagemsg.header.frame_id;
00548
00549 if( verbose > 0 )
00550 ROS_INFO("checkerboard: image: %ux%u (size=%u), num: %u, total: %.3fs",
00551 imagemsg.width, imagemsg.height,
00552 (unsigned int)imagemsg.data.size(), (unsigned int)objdetmsg.objects.size(),
00553 (float)(ros::Time::now() - lasttime).toSec());
00554 lasttime = ros::Time::now();
00555
00556 if( display ) {
00557
00558 for(size_t i = 0; i < vobjects.size(); ++i) {
00559 int itype = maptypes[vobjects[i].type];
00560 CHECKERBOARD& cb = vcheckers[itype];
00561 Transform tglobal;
00562 tglobal.trans = Vector(vobjects[i].pose.position.x,vobjects[i].pose.position.y,vobjects[i].pose.position.z);
00563 tglobal.rot = Vector(vobjects[i].pose.orientation.w,vobjects[i].pose.orientation.x,vobjects[i].pose.orientation.y, vobjects[i].pose.orientation.z);
00564 Transform tlocal = tglobal * cb.tlocaltrans.inverse();
00565
00566 cv::Point X[4];
00567
00568 Vector vaxes[4];
00569 vaxes[0] = Vector(0,0,0);
00570 vaxes[1] = Vector(0.05f,0,0);
00571 vaxes[2] = Vector(0,0.05f,0);
00572 vaxes[3] = Vector(0,0,0.05f);
00573
00574 for(int i = 0; i < 4; ++i) {
00575 Vector p = tglobal*vaxes[i];
00576 dReal fx = p.x*camInfoMsg.P[0] + p.y*camInfoMsg.P[1] + p.z*camInfoMsg.P[2] + camInfoMsg.P[3];
00577 dReal fy = p.x*camInfoMsg.P[4] + p.y*camInfoMsg.P[5] + p.z*camInfoMsg.P[6] + camInfoMsg.P[7];
00578 dReal fz = p.x*camInfoMsg.P[8] + p.y*camInfoMsg.P[9] + p.z*camInfoMsg.P[10] + camInfoMsg.P[11];
00579 X[i].x = (int)(fx/fz);
00580 X[i].y = (int)(fy/fz);
00581 }
00582
00583
00584 cv::Scalar col0(255,0,(64*itype)%256);
00585 cv::Scalar col1(0,255,(64*itype)%256);
00586 cv::Scalar col2((64*itype)%256,(64*itype)%256,255);
00587 cv::line(frame, X[0], X[1], col0, 1);
00588 cv::line(frame, X[0], X[2], col1, 1);
00589 cv::line(frame, X[0], X[3], col2, 1);
00590
00591
00592 for(size_t i = 0; i < cb.grid3d.size(); ++i) {
00593 Vector grid3d_vec(cb.grid3d[i].x, cb.grid3d[i].y, cb.grid3d[i].z);
00594 Vector p = tlocal * grid3d_vec;
00595 dReal fx = p.x*camInfoMsg.P[0] + p.y*camInfoMsg.P[1] + p.z*camInfoMsg.P[2] + camInfoMsg.P[3];
00596 dReal fy = p.x*camInfoMsg.P[4] + p.y*camInfoMsg.P[5] + p.z*camInfoMsg.P[6] + camInfoMsg.P[7];
00597 dReal fz = p.x*camInfoMsg.P[8] + p.y*camInfoMsg.P[9] + p.z*camInfoMsg.P[10] + camInfoMsg.P[11];
00598 int x = (int)(fx/fz);
00599 int y = (int)(fy/fz);
00600 cv::circle(frame, cv::Point(x,y), 6, cv::Scalar(0,0,0), 2);
00601 cv::circle(frame, cv::Point(x,y), 2, cv::Scalar(0,0,0), 2);
00602 cv::circle(frame, cv::Point(x,y), 4, cv::Scalar(64*itype,128,128), 3);
00603 }
00604
00605 cv::circle(frame, X[0], 3, cv::Scalar(255,255,128), 3);
00606
00607 geometry_msgs::PointStamped point_msg;
00608 point_msg.header = imagemsg.header;
00609 point_msg.point.x = X[0].x;
00610 point_msg.point.y = X[0].y;
00611 point_msg.point.z = vobjects[vobjects.size() - 1].pose.position.z;
00612 _pubCornerPoint.publish(point_msg);
00613
00614 }
00615
00616 cv::imshow("Checkerboard Detector",frame);
00617 cv::waitKey(1);
00618 }
00619
00620 return true;
00621 }
00622
00623
00625
00626 geometry_msgs::Pose FindTransformation(
00627 const vector<cv::Point2f> &imgpts, const vector<cv::Point3f> &objpts,
00628 const Transform& tlocal,
00629 const image_geometry::PinholeCameraModel& model)
00630 {
00631 geometry_msgs::Pose pose;
00632 Transform tchecker;
00633 cv::Mat R3_mat, T3_mat;
00634 cv::solvePnP(objpts, imgpts,
00635 model.intrinsicMatrix(),
00636 model.distortionCoeffs(),
00637 R3_mat, T3_mat, false);
00638 double fR3[3];
00639 for (size_t i = 0; i < 3; i++) {
00640 fR3[i] = R3_mat.at<double>(i);
00641 }
00642 tchecker.trans.x = T3_mat.at<double>(0);
00643 tchecker.trans.y = T3_mat.at<double>(1);
00644 tchecker.trans.z = T3_mat.at<double>(2);
00645 double fang = sqrt(fR3[0]*fR3[0] + fR3[1]*fR3[1] + fR3[2]*fR3[2]);
00646 if( fang >= 1e-6 ) {
00647 double fmult = sin(fang/2)/fang;
00648 tchecker.rot = Vector(cos(fang/2),fR3[0]*fmult, fR3[1]*fmult, fR3[2]*fmult);
00649 }
00650
00651 Transform tglobal = tchecker*tlocal;
00652 pose.position.x = tglobal.trans.x;
00653 pose.position.y = tglobal.trans.y;
00654 pose.position.z = tglobal.trans.z;
00655 pose.orientation.x = tglobal.rot.y;
00656 pose.orientation.y = tglobal.rot.z;
00657 pose.orientation.z = tglobal.rot.w;
00658 pose.orientation.w = tglobal.rot.x;
00659 return pose;
00660 }
00661 };
00662
00664
00665 int main(int argc, char **argv)
00666 {
00667 ros::init(argc,argv,"checkerboard_detector");
00668 if( !ros::master::check() )
00669 return 1;
00670
00671 CheckerboardDetector cd;
00672 ros::spin();
00673
00674 return 0;
00675 }