checkerboard_detector.cpp
Go to the documentation of this file.
00001 // -*- mode: c++; indent-tabs-mode: nil; c-basic-offset: 4; -*-
00002 // Software License Agreement (BSD License)
00003 // Copyright (c) 2008, JSK Lab, Inc.
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are met:
00006 //   * Redistributions of source code must retain the above copyright notice,
00007 //     this list of conditions and the following disclaimer.
00008 //   * Redistributions in binary form must reproduce the above copyright
00009 //     notice, this list of conditions and the following disclaimer in the
00010 //     documentation and/or other materials provided with the distribution.
00011 //   * The name of the author may not be used to endorse or promote products
00012 //     derived from this software without specific prior written permission.
00013 //
00014 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00015 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00016 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00017 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00018 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00019 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00020 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00021 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00022 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00023 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00024 // POSSIBILITY OF SUCH DAMAGE.
00025 //
00026 // author: Rosen Diankov
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>    // ftime(), struct timeb
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         //vector<CvPoint2D32f> corners;
00072         //cv::Mat corners;
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; // tf frame id
00091     bool invert_color;
00092     int display, verbose, maxboard;
00093     vector<CHECKERBOARD> vcheckers; // grid points for every checkerboard
00094     vector< string > vstrtypes; // type names for every grid point
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     // Constructor
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         //this->camInfoSubscriber = _node.subscribe("camera_info", 1, &CheckerboardDetector::caminfo_cb, this);
00235         //this->imageSubscriber = _node.subscribe("image",1, &CheckerboardDetector::image_cb, this);
00236         //this->camInfoSubscriber2 = _node.subscribe("CameraInfo", 1, &CheckerboardDetector::caminfo_cb2, this);
00237         //this->imageSubscriber2 = _node.subscribe("Image",1, &CheckerboardDetector::image_cb2, this);
00238         _srvDetect = _node.advertiseService("Detect",&CheckerboardDetector::detect_cb,this);
00239     }
00240 
00242     // Destructor
00243     virtual ~CheckerboardDetector()
00244     {
00245     }
00246 
00248     // Camera info callback
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         // only get the camera info once <- this is dumb
00256         //this->camInfoSubscriber.shutdown();
00257         //this->camInfoSubscriber2.shutdown();
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     // Image data callback
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         // check all the value of R is zero or not
00396         // if zero, normalzie it
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         // check all the value of K is zero or not
00403         // if zero, copy all the value from P
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             //capture = 255 - capture;
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             // do until no more checkerboards detected
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                     // sometime cv::findCirclesGrid hangs
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                 // remove any corners that are close to the border
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                 // mark out the image
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") { // subpixel only for chessboard
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             //cvSaveImage("temp.jpg", pimggray);
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             // draw each found checkerboard
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                 // draw three lines
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                 // draw all the points
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                 // publish X[0]
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     // FindTransformation
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 // MAIN
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 }


checkerboard_detector
Author(s): Rosen Diankov (rdiankov@cs.cmu.edu)
autogenerated on Wed Sep 16 2015 04:37:40