checkerboard_detector.cpp
Go to the documentation of this file.
00001 // Software License Agreement (BSD License)
00002 // Copyright (c) 2008, Willow Garage, Inc.
00003 // Redistribution and use in source and binary forms, with or without
00004 // modification, are permitted provided that the following conditions are met:
00005 //   * Redistributions of source code must retain the above copyright notice,
00006 //     this list of conditions and the following disclaimer.
00007 //   * Redistributions in binary form must reproduce the above copyright
00008 //     notice, this list of conditions and the following disclaimer in the
00009 //     documentation and/or other materials provided with the distribution.
00010 //   * The name of the author may not be used to endorse or promote products
00011 //     derived from this software without specific prior written permission.
00012 //
00013 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00014 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00015 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00016 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00017 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00018 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00019 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00020 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00021 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00022 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00023 // POSSIBILITY OF SUCH DAMAGE.
00024 //
00025 // author: Rosen Diankov
00026 #include <cstdio>
00027 #include <vector>
00028 #include <sstream>
00029 #include <ros/ros.h>
00030 
00031 #include <boost/thread/mutex.hpp>
00032 
00033 #include "opencv/cv.h"
00034 #include "opencv/highgui.h"
00035 #include "cv_bridge/cv_bridge.h"
00036 #include "sensor_msgs/image_encodings.h"
00037 #include "sensor_msgs/CameraInfo.h"
00038 #include "sensor_msgs/Image.h"
00039 #include "posedetection_msgs/ObjectDetection.h"
00040 #include "posedetection_msgs/Detect.h"
00041 #include "geometry_msgs/PointStamped.h"
00042 #include "math.h"
00043 
00044 #include <sys/timeb.h>    // ftime(), struct timeb
00045 #include <sys/time.h>
00046 
00047 using namespace std;
00048 using namespace ros;
00049 
00050 class CheckerboardDetector
00051 {
00052     template <typename T>
00053     static vector<T> tokenizevector(const string& s)
00054     {
00055         stringstream ss(s);
00056         return vector<T>((istream_iterator<T>(ss)), istream_iterator<T>());
00057     }
00058 
00059 public:
00060     struct CHECKERBOARD
00061     {
00062         CvSize griddims; 
00063         vector<Vector> grid3d;
00064         vector<CvPoint2D32f> corners;
00065         TransformMatrix tlocaltrans;
00066     };
00067 
00068     posedetection_msgs::ObjectDetection _objdetmsg;
00069     cv_bridge::CvImagePtr capture;
00070     sensor_msgs::CameraInfo _camInfoMsg;
00071 
00072     ros::Subscriber camInfoSubscriber,camInfoSubscriber2;
00073     ros::Subscriber imageSubscriber,imageSubscriber2;
00074     ros::Publisher _pubDetection;
00075     ros::Publisher _pubCornerPoint;
00076     ros::ServiceServer _srvDetect;
00077 
00078     string frame_id; // tf frame id
00079 
00080     int display, verbose, maxboard;
00081     vector<CHECKERBOARD> vcheckers; // grid points for every checkerboard
00082     vector< string > vstrtypes; // type names for every grid point
00083     map<string,int> maptypes;
00084     ros::Time lasttime;
00085     CvMat *intrinsic_matrix; // intrinsic matrices
00086     boost::mutex mutexcalib;
00087     IplImage* frame;
00088 
00089     ros::NodeHandle _node;
00090 
00092     // Constructor
00093     CheckerboardDetector() : intrinsic_matrix(NULL), frame(NULL)
00094     {
00095         _node.param("display", display, 0);
00096         _node.param("verbose", verbose, 1);
00097         _node.param("maxboard", maxboard, -1);
00098         
00099         char str[32];
00100         int index = 0;
00101 
00102         while(1) {
00103             int dimx, dimy;
00104             double fRectSize[2];
00105             string type;
00106 
00107             sprintf(str,"grid%d_size_x",index);
00108             if( !_node.getParam(str,dimx) )
00109                 break;
00110             if (dimx < 3) {
00111                 ROS_ERROR("Param: %s must be greater than 2",str);
00112                 return;
00113             }
00114 
00115             sprintf(str,"grid%d_size_y",index);
00116             if( !_node.getParam(str,dimy) )
00117                 break;
00118             if (dimy < 3) {
00119                 ROS_ERROR("Param: %s must be greater than 2",str);
00120                 return;
00121             }
00122 
00123             sprintf(str,"rect%d_size_x",index);
00124             if( !_node.getParam(str,fRectSize[0]) )
00125                 break;
00126 
00127             sprintf(str,"rect%d_size_y",index);
00128             if( !_node.getParam(str,fRectSize[1]) )
00129                 break;
00130 
00131             sprintf(str,"type%d",index);
00132             if( !_node.getParam(str,type) ) {
00133                 sprintf(str,"checker%dx%d", dimx, dimy);
00134                 type = str;
00135             }
00136 
00137             string strtranslation,strrotation;
00138             sprintf(str,"translation%d",index);
00139             _node.param(str,strtranslation,string());
00140 
00141             vector<float> vtranslation = tokenizevector<float>(strtranslation);
00142             sprintf(str,"rotation%d",index);
00143             _node.param(str,strrotation,string());
00144 
00145             vector<float> vrotation = tokenizevector<float>(strrotation);
00146 
00147             CHECKERBOARD cb;
00148             cb.griddims = cvSize(dimx,dimy);
00149 
00150             cb.grid3d.resize(dimx*dimy);
00151             int j=0;
00152             for(int y=0; y<dimy; ++y)
00153                 for(int x=0; x<dimx; ++x)
00154                     cb.grid3d[j++] = Vector(x*fRectSize[0], y*fRectSize[1], 0);
00155 
00156             if( vtranslation.size() == 3 )
00157                 cb.tlocaltrans.trans = 
00158                     Vector(vtranslation[0],vtranslation[1],vtranslation[2]);
00159 
00160             if( vrotation.size() == 9 )  {
00161                 for(int k = 0; k < 3; ++k) {
00162                     cb.tlocaltrans.m[4*k+0] = vrotation[3*k+0];
00163                     cb.tlocaltrans.m[4*k+1] = vrotation[3*k+1];
00164                     cb.tlocaltrans.m[4*k+2] = vrotation[3*k+2];
00165                 }
00166             }
00167 
00168             vcheckers.push_back(cb);
00169             vstrtypes.push_back(type);
00170             maptypes[vstrtypes.back()] = index;
00171             index++;
00172         }
00173 
00174         _node.param("frame_id", frame_id,string(""));
00175 
00176         if( maptypes.size() == 0 ) {
00177             ROS_ERROR("no checkerboards to detect");
00178             return;
00179         }
00180 
00181         if( display ) {
00182           // enable to set other window flag // use display value if display != 1 because only CV_WINDOW_AUTOSIZE is supported officially
00183           cvNamedWindow("Checkerboard Detector", (display == 1? CV_WINDOW_AUTOSIZE : display));
00184             cvStartWindowThread();
00185         }
00186 
00187         lasttime = ros::Time::now();
00188 
00189         ros::SubscriberStatusCallback connect_cb = boost::bind( &CheckerboardDetector::connectCb, this);
00190         _pubDetection =
00191           _node.advertise<posedetection_msgs::ObjectDetection> ("ObjectDetection", 1,
00192                                                                 connect_cb, connect_cb);
00193         _pubCornerPoint = _node.advertise<geometry_msgs::PointStamped>("corner_point", 1, connect_cb, connect_cb);
00194         //this->camInfoSubscriber = _node.subscribe("camera_info", 1, &CheckerboardDetector::caminfo_cb, this);
00195         //this->imageSubscriber = _node.subscribe("image",1, &CheckerboardDetector::image_cb, this);
00196         //this->camInfoSubscriber2 = _node.subscribe("CameraInfo", 1, &CheckerboardDetector::caminfo_cb2, this);
00197         //this->imageSubscriber2 = _node.subscribe("Image",1, &CheckerboardDetector::image_cb2, this);
00198         _srvDetect = _node.advertiseService("Detect",&CheckerboardDetector::detect_cb,this);
00199     }
00200 
00202     // Destructor
00203     virtual ~CheckerboardDetector()
00204     {
00205         if( frame )
00206             cvReleaseImage(&frame);
00207         if( this->intrinsic_matrix )
00208             cvReleaseMat(&this->intrinsic_matrix);
00209         _srvDetect.shutdown();
00210         this->camInfoSubscriber.shutdown();
00211         this->imageSubscriber.shutdown();
00212         this->camInfoSubscriber2.shutdown();
00213         this->imageSubscriber2.shutdown();
00214     }
00215 
00217     // Camera info callback
00218     void caminfo_cb(const sensor_msgs::CameraInfoConstPtr &msg)
00219     {
00220         boost::mutex::scoped_lock lock(this->mutexcalib);
00221 
00222         this->_camInfoMsg = *msg;
00223 
00224         // only get the camera info once <- this is dumb
00225         //this->camInfoSubscriber.shutdown();
00226         //this->camInfoSubscriber2.shutdown();
00227     }
00228     void caminfo_cb2(const sensor_msgs::CameraInfoConstPtr &msg)
00229     {
00230         ROS_WARN("The topic CameraInfo has been deprecated.  Please change your launch file to use camera_info instead.");
00231         caminfo_cb(msg);
00232     }
00233 
00234     void image_cb2(const sensor_msgs::ImageConstPtr &msg)
00235     {
00236         ROS_WARN("The topic Image has been deprecated.  Please change your launch file to use image instead.");
00237         boost::mutex::scoped_lock lock(this->mutexcalib);
00238         if( Detect(_objdetmsg,*msg,this->_camInfoMsg) )
00239             _pubDetection.publish(_objdetmsg);
00240     }
00241 
00243     // Image data callback
00244     void image_cb(const sensor_msgs::ImageConstPtr &msg)
00245     {
00246         boost::mutex::scoped_lock lock(this->mutexcalib);
00247         if( Detect(_objdetmsg,*msg,this->_camInfoMsg) )
00248             _pubDetection.publish(_objdetmsg);
00249     }
00250 
00251     bool detect_cb(posedetection_msgs::Detect::Request& req, posedetection_msgs::Detect::Response& res)
00252     {
00253         return Detect(res.object_detection,req.image,req.camera_info);
00254     }
00255 
00256     //
00257     void connectCb( )
00258     {
00259       boost::mutex::scoped_lock lock(this->mutexcalib);
00260       if (_pubDetection.getNumSubscribers() == 0 && _pubCornerPoint.getNumSubscribers() == 0)
00261         {
00262           camInfoSubscriber.shutdown();
00263           camInfoSubscriber2.shutdown();
00264           imageSubscriber.shutdown();
00265           imageSubscriber2.shutdown();
00266         }
00267       else
00268         {
00269           if ( camInfoSubscriber == NULL )
00270             camInfoSubscriber = _node.subscribe("camera_info", 1, &CheckerboardDetector::caminfo_cb, this);
00271           if ( imageSubscriber == NULL )
00272             imageSubscriber = _node.subscribe("image", 1, &CheckerboardDetector::image_cb, this);
00273           if ( camInfoSubscriber2 == NULL )
00274             camInfoSubscriber2 = _node.subscribe("CameraInfo", 1, &CheckerboardDetector::caminfo_cb2, this);
00275           if ( imageSubscriber2 == NULL )
00276             imageSubscriber2 = _node.subscribe("Image",1, &CheckerboardDetector::image_cb2, this);
00277         }
00278     }
00279 
00280     bool Detect(posedetection_msgs::ObjectDetection& objdetmsg, const sensor_msgs::Image& imagemsg, const sensor_msgs::CameraInfo& camInfoMsg)
00281     {
00282         if( this->intrinsic_matrix == NULL )
00283             this->intrinsic_matrix = cvCreateMat(3,3,CV_32FC1);
00284 
00285         for(int i = 0; i < 3; ++i)
00286             for(int j = 0; j < 3; ++j)
00287                 this->intrinsic_matrix->data.fl[3*i+j] = camInfoMsg.P[4*i+j];
00288 
00289         try {
00290           if (imagemsg.encoding == "32FC1") {
00291             cv_bridge::CvImagePtr float_capture
00292               = cv_bridge::toCvCopy(imagemsg,
00293                                     sensor_msgs::image_encodings::TYPE_32FC1);
00294             cv::Mat float_image = float_capture->image;
00295             cv::Mat mono_image;
00296             float_image.convertTo(mono_image, CV_8UC1);
00297             capture.reset(new cv_bridge::CvImage());
00298             capture->image = mono_image;
00299           }
00300           else {
00301             capture = cv_bridge::toCvCopy(imagemsg, sensor_msgs::image_encodings::MONO8);
00302           }
00303         } catch (cv_bridge::Exception &e) {
00304             ROS_ERROR("failed to get image %s", e.what());
00305             return false;
00306         }
00307 
00308         IplImage imggray = capture->image;
00309         IplImage *pimggray = &imggray;
00310         if( display ) {
00311             // copy the raw image
00312             if( frame != NULL && (frame->width != (int)imagemsg.width || frame->height != (int)imagemsg.height) ) {
00313                 cvReleaseImage(&frame);
00314                 frame = NULL;
00315             }
00316             imggray = capture->image;
00317             pimggray = &imggray;
00318 
00319             if( frame == NULL ) 
00320                 frame = cvCreateImage(cvSize(imagemsg.width,imagemsg.height),IPL_DEPTH_8U, 3);
00321 
00322             cvCvtColor(pimggray,frame,CV_GRAY2RGB);
00323         }
00324 
00325         vector<posedetection_msgs::Object6DPose> vobjects;
00326 
00327 #pragma omp parallel for schedule(dynamic,1)
00328         for(int i = 0; i < (int)vcheckers.size(); ++i) {
00329             CHECKERBOARD& cb = vcheckers[i];
00330             int ncorners, board=0;
00331             posedetection_msgs::Object6DPose objpose;
00332 
00333             // do until no more checkerboards detected
00334             while((maxboard==-1)?1:((++board)<=maxboard)) {
00335                 cb.corners.resize(200);
00336                 int allfound = cvFindChessboardCorners( pimggray, cb.griddims, &cb.corners[0], &ncorners,
00337                                                         CV_CALIB_CB_ADAPTIVE_THRESH );
00338                 cb.corners.resize(ncorners);
00339 
00340                 //cvDrawChessboardCorners(pimgGray, itbox->second.griddims, &corners[0], ncorners, allfound);
00341                 //cvSaveImage("temp.jpg", pimgGray);
00342 
00343                 if(!allfound || ncorners != (int)cb.grid3d.size())
00344                     break;
00345 
00346                 // remove any corners that are close to the border
00347                 const int borderthresh = 30;
00348 
00349                 for(int j = 0; j < ncorners; ++j) {
00350                     int x = cb.corners[j].x;
00351                     int y = cb.corners[j].y;
00352                     if( x < borderthresh || x > pimggray->width-borderthresh ||
00353                         y < borderthresh || y > pimggray->height-borderthresh )
00354                     {
00355                         allfound = 0;
00356                         break;
00357                     }
00358                 }
00359 
00360                 // mark out the image
00361                 CvPoint upperleft, lowerright;
00362                 upperleft.x = lowerright.x = cb.corners[0].x;
00363                 upperleft.y = lowerright.y = cb.corners[0].y;
00364                 for(int j = 1; j < (int)cb.corners.size(); ++j) {
00365                     if( upperleft.x > cb.corners[j].x ) upperleft.x = cb.corners[j].x;
00366                     if( upperleft.y > cb.corners[j].y ) upperleft.y = cb.corners[j].y;
00367                     if( lowerright.x < cb.corners[j].x ) lowerright.x = cb.corners[j].x;
00368                     if( lowerright.y < cb.corners[j].y ) lowerright.y = cb.corners[j].y;
00369                 }
00370 
00371                 float step_size =
00372                   (double)( ((upperleft.x - lowerright.x) * (upperleft.x - lowerright.x)) +
00373                             ((upperleft.y - lowerright.y) * (upperleft.y - lowerright.y)) )
00374                   /
00375                   ( ((cb.griddims.width - 1) * (cb.griddims.width - 1)) +
00376                     ((cb.griddims.height - 1) * (cb.griddims.height - 1)) );
00377 #if 0
00378                 ROS_INFO("(%d %d) - (%d %d) -> %f ",
00379                          upperleft.x, upperleft.y, lowerright.x, lowerright.y, sqrt(step_size));
00380 #endif
00381                 int size = (int)(0.5*sqrt(step_size) + 0.5);
00382 
00383                 if( allfound ) {
00384                     cvFindCornerSubPix(pimggray, &cb.corners[0], cb.corners.size(), cvSize(size,size), cvSize(-1,-1),
00385                                        cvTermCriteria(CV_TERMCRIT_ITER, 50, 1e-2));
00386                     objpose.pose = FindTransformation(cb.corners, cb.grid3d, cb.tlocaltrans);
00387                 }
00388 
00389 #pragma omp critical
00390                 {
00391                     if( allfound ) {
00392                         vobjects.push_back(objpose);
00393                         vobjects.back().type = vstrtypes[i];
00394                     }
00395 
00396                     cvRectangle(pimggray, upperleft, lowerright, CV_RGB(0,0,0),CV_FILLED);
00397                 }
00398             }
00399 
00400             //cvSaveImage("temp.jpg", pimggray);
00401         }
00402 
00403         objdetmsg.objects = vobjects;
00404         objdetmsg.header.stamp = imagemsg.header.stamp;
00405         if( frame_id.size() > 0 )
00406             objdetmsg.header.frame_id = frame_id;
00407         else
00408             objdetmsg.header.frame_id = imagemsg.header.frame_id;
00409 
00410         if( verbose > 0 )
00411             ROS_INFO("checkerboard: image: %ux%u (size=%u), num: %u, total: %.3fs",imagemsg.width,imagemsg.height,
00412                      (unsigned int)imagemsg.data.size(), (unsigned int)objdetmsg.objects.size(),
00413                      (float)(ros::Time::now()-lasttime).toSec());
00414         lasttime = ros::Time::now();
00415 
00416         if( display ) {
00417             // draw each found checkerboard
00418             for(size_t i = 0; i < vobjects.size(); ++i) {
00419                 int itype = maptypes[vobjects[i].type];
00420                 CHECKERBOARD& cb = vcheckers[itype];
00421                 Transform tglobal;
00422                 tglobal.trans = Vector(vobjects[i].pose.position.x,vobjects[i].pose.position.y,vobjects[i].pose.position.z);
00423                 tglobal.rot = Vector(vobjects[i].pose.orientation.w,vobjects[i].pose.orientation.x,vobjects[i].pose.orientation.y, vobjects[i].pose.orientation.z);
00424                 Transform tlocal = tglobal * cb.tlocaltrans.inverse();
00425 
00426                 CvPoint X[4];
00427 
00428                 Vector vaxes[4];
00429                 vaxes[0] = Vector(0,0,0);
00430                 vaxes[1] = Vector(0.05f,0,0);
00431                 vaxes[2] = Vector(0,0.05f,0);
00432                 vaxes[3] = Vector(0,0,0.05f);
00433 
00434                 for(int i = 0; i < 4; ++i) {
00435                     Vector p = tglobal*vaxes[i];
00436                     dReal fx = p.x*camInfoMsg.P[0] + p.y*camInfoMsg.P[1] + p.z*camInfoMsg.P[2] + camInfoMsg.P[3];
00437                     dReal fy = p.x*camInfoMsg.P[4] + p.y*camInfoMsg.P[5] + p.z*camInfoMsg.P[6] + camInfoMsg.P[7];
00438                     dReal fz = p.x*camInfoMsg.P[8] + p.y*camInfoMsg.P[9] + p.z*camInfoMsg.P[10] + camInfoMsg.P[11];
00439                     X[i].x = (int)(fx/fz);
00440                     X[i].y = (int)(fy/fz);
00441                 }
00442 
00443                 // draw three lines
00444                 CvScalar col0 = CV_RGB(255,0,(64*itype)%256);
00445                 CvScalar col1 = CV_RGB(0,255,(64*itype)%256);
00446                 CvScalar col2 = CV_RGB((64*itype)%256,(64*itype)%256,255);
00447                 cvLine(frame, X[0], X[1], col0, 1);
00448                 cvLine(frame, X[0], X[2], col1, 1);
00449                 cvLine(frame, X[0], X[3], col2, 1);
00450 
00451                 // draw all the points
00452                 for(size_t i = 0; i < cb.grid3d.size(); ++i) {
00453                     Vector p = tlocal * cb.grid3d[i];
00454                     dReal fx = p.x*camInfoMsg.P[0] + p.y*camInfoMsg.P[1] + p.z*camInfoMsg.P[2] + camInfoMsg.P[3];
00455                     dReal fy = p.x*camInfoMsg.P[4] + p.y*camInfoMsg.P[5] + p.z*camInfoMsg.P[6] + camInfoMsg.P[7];
00456                     dReal fz = p.x*camInfoMsg.P[8] + p.y*camInfoMsg.P[9] + p.z*camInfoMsg.P[10] + camInfoMsg.P[11];
00457                     int x = (int)(fx/fz);
00458                     int y = (int)(fy/fz);
00459                     cvCircle(frame, cvPoint(x,y), 6, CV_RGB(0,0,0), 2);
00460                     cvCircle(frame, cvPoint(x,y), 2, CV_RGB(0,0,0), 2);
00461                     cvCircle(frame, cvPoint(x,y), 4, CV_RGB(128,128,64*itype), 3);
00462                 }
00463 
00464                 cvCircle(frame, X[0], 3, CV_RGB(255,255,128), 3);
00465                 // publish X[0]
00466                 geometry_msgs::PointStamped point_msg;
00467                 point_msg.header = imagemsg.header;
00468                 point_msg.point.x = X[0].x;
00469                 point_msg.point.y = X[0].y;
00470                 point_msg.point.z = vobjects[i].pose.position.z;
00471                 _pubCornerPoint.publish(point_msg);
00472             }
00473 
00474             cvShowImage("Checkerboard Detector",frame);
00475         }
00476 
00477         return true;
00478     }
00479 
00480 
00482     // FindTransformation
00483     geometry_msgs::Pose FindTransformation(const vector<CvPoint2D32f> &imgpts, const vector<Vector> &objpts, const Transform& tlocal)
00484     {
00485         CvMat *objpoints = cvCreateMat(3,objpts.size(),CV_32FC1);
00486         for(size_t i=0; i<objpts.size(); ++i) {
00487             cvSetReal2D(objpoints, 0,i, objpts[i].x);
00488             cvSetReal2D(objpoints, 1,i, objpts[i].y);
00489             cvSetReal2D(objpoints, 2,i, objpts[i].z);
00490         }
00491 
00492         geometry_msgs::Pose pose;
00493         Transform tchecker;
00494         assert(sizeof(tchecker.trans.x)==sizeof(float));
00495         float fR3[3];
00496         CvMat R3, T3;
00497         assert(sizeof(pose.position.x) == sizeof(double));
00498         cvInitMatHeader(&R3, 3, 1, CV_32FC1, fR3);
00499         cvInitMatHeader(&T3, 3, 1, CV_32FC1, &tchecker.trans.x);
00500 
00501         float kc[4] = {0};
00502         CvMat kcmat;
00503         cvInitMatHeader(&kcmat,1,4,CV_32FC1,kc);
00504 
00505         CvMat img_points;
00506         cvInitMatHeader(&img_points, 1,imgpts.size(), CV_32FC2, const_cast<CvPoint2D32f*>(&imgpts[0]));
00507 
00508         cvFindExtrinsicCameraParams2(objpoints, &img_points, this->intrinsic_matrix, &kcmat, &R3, &T3);
00509         cvReleaseMat(&objpoints);
00510 
00511         double fang = sqrt(fR3[0]*fR3[0] + fR3[1]*fR3[1] + fR3[2]*fR3[2]);
00512         if( fang >= 1e-6 ) {
00513             double fmult = sin(fang/2)/fang;
00514             tchecker.rot = Vector(cos(fang/2),fR3[0]*fmult, fR3[1]*fmult, fR3[2]*fmult);
00515         }
00516 
00517         Transform tglobal = tchecker*tlocal;
00518         pose.position.x = tglobal.trans.x;
00519         pose.position.y = tglobal.trans.y;
00520         pose.position.z = tglobal.trans.z;
00521         pose.orientation.x = tglobal.rot.y;
00522         pose.orientation.y = tglobal.rot.z;
00523         pose.orientation.z = tglobal.rot.w;
00524         pose.orientation.w = tglobal.rot.x;
00525         return pose;
00526     }
00527 };
00528 
00530 // MAIN
00531 int main(int argc, char **argv)
00532 {
00533     ros::init(argc,argv,"checkerboard_detector");
00534     if( !ros::master::check() )
00535         return 1;
00536   
00537     CheckerboardDetector cd;
00538     ros::spin();
00539 
00540     return 0;
00541 }


checkerboard_detector
Author(s): Rosen Diankov (rdiankov@cs.cmu.edu)
autogenerated on Mon Oct 6 2014 01:16:45