calcPose.cpp
Go to the documentation of this file.
00001 
00002 /*
00003 
00004 This library computes the pose of
00005 the fiducial relative to a fiducial centered on the origin.
00006 
00007 */
00008 
00009 #include <stdio.h>
00010 #include <math.h>
00011 #include <malloc.h>
00012 
00013 #include <ros/ros.h>
00014 #include <tf/transform_broadcaster.h>
00015 #include <tf/LinearMath/Matrix3x3.h>
00016 
00017 #include <opencv2/opencv.hpp>
00018 #include <opencv2/core/core.hpp>
00019 #include <opencv2/calib3d/calib3d.hpp>
00020 #include <opencv2/imgproc/imgproc.hpp>
00021 
00022 #include "RPP.h"
00023 #include "fiducial_pose/rosrpp.h"
00024 
00025 // Radians to degrees
00026 double r2d(double r) 
00027 {
00028   return r / M_PI * 180.0;
00029 }
00030 
00031 // Euclidean distance between two points
00032 double dist(cv::Mat pts, int i1, int i2)
00033 {
00034   double x1 = pts.at<double>(0, i1);
00035   double y1 = pts.at<double>(1, i1);
00036   double x2 = pts.at<double>(0, i2);
00037   double y2 = pts.at<double>(1, i2);
00038 
00039   double dx = x1 - x2;
00040   double dy = y1 - y2;
00041 
00042   return sqrt(dx*dx + dy*dy);
00043 }
00044 
00045 // Compute area in image of a fiducial, using Heron's formula
00046 // to find the area of two triangles
00047 double calcFiducialArea(cv::Mat pts)
00048 {
00049   double a1 = dist(pts, 0, 1);
00050   double b1 = dist(pts, 0, 3);
00051   double c1 = dist(pts, 1, 3);
00052   
00053   double a2 = dist(pts, 1, 2);
00054   double b2 = dist(pts, 2, 3);
00055   double c2 = c1;
00056 
00057   double s1 = (a1 + b1 + c1) / 2.0;
00058   double s2 = (a2 + b2 + c2) / 2.0;
00059 
00060   a1 = sqrt(s1*(s1-a1)*(s1-b1)*(s1-c1));
00061   a2 = sqrt(s2*(s2-a2)*(s2-b2)*(s2-c2));
00062   return a1+a2;
00063 }
00064 
00065 
00066 void undistortPoints(cv::Mat pts, cv::Mat K, cv::Mat dist, bool doUndistort)
00067 {
00068   if (!doUndistort) {
00069     printf("fx %lf fy %lf cx %lf cy %lf", K.at<double>(0, 0), K.at<double>(1, 1), K.at<double>(0, 2), K.at<double>(1, 2));
00070     for (int i=0; i<pts.cols; i++) {
00071       pts.at<double>(0, i) = (pts.at<double>(0, i) - K.at<double>(0, 2)) / K.at<double>(0, 0);
00072       pts.at<double>(1, i) = (pts.at<double>(1, i) - K.at<double>(1, 2)) / K.at<double>(1, 1);
00073     }
00074   }
00075   else {
00076     cv::Mat src(1, pts.cols, CV_64FC2);
00077     cv::Mat dst(1, pts.cols, CV_64FC2);
00078   
00079     for (int i=0; i<pts.cols; i++) {
00080       src.at<cv::Vec2d>(0, i)[0] = pts.at<double>(0, i);
00081       src.at<cv::Vec2d>(0, i)[1] = pts.at<double>(1, i);
00082     }
00083     std::vector<cv::Point2f> dest;
00084     cv::undistortPoints(src, dst, K, dist);
00085 
00086     for (int i=0; i<pts.cols; i++) {
00087       pts.at<double>(0, i) = dst.at<cv::Vec2d>(0, i)[0];
00088       pts.at<double>(1, i) = dst.at<cv::Vec2d>(0, i)[1];
00089     } 
00090   }
00091 }
00092 
00093 
00094 bool RosRpp::fiducialCallback(fiducial_pose::Fiducial* msg,
00095                               fiducial_pose::FiducialTransform* ft)
00096 {
00097   ROS_INFO("date %d id %d direction %d", 
00098            msg->header.stamp.sec, msg->fiducial_id,
00099            msg->direction);
00100 
00101   if (!haveCamInfo) {
00102     ROS_ERROR("No camera info");
00103     return false;
00104   }
00105 
00106   if (currentFrame != msg->image_seq) {
00107     //frameTime = msg->header.stamp;
00108     frameTime = ros::Time::now();
00109     currentFrame = msg->image_seq;
00110   }
00111 
00112   /* The verices are ordered anti-clockwise, starting with the top-left
00113      we want to end up with this:
00114        2  3
00115        1  0
00116   */
00117 
00118   printf("frame %d fid %d dir %d vertices %lf %lf %lf %lf %lf %lf %lf %lf\n",
00119          msg->image_seq, msg->fiducial_id, msg->direction, 
00120          msg->x0, msg->y0, msg->x1, msg->y1,
00121          msg->x2, msg->y2, msg->x3, msg->y3);
00122   
00123   switch(msg->direction) {
00124     case 0: 
00125       // 0 1 2 3
00126       ipts.at<double>(0,0) = msg->x0;
00127       ipts.at<double>(1,0) = msg->y0;
00128       ipts.at<double>(0,1) = msg->x1;
00129       ipts.at<double>(1,1) = msg->y1;
00130       ipts.at<double>(0,2) = msg->x2;
00131       ipts.at<double>(1,2) = msg->y2;
00132       ipts.at<double>(0,3) = msg->x3;
00133       ipts.at<double>(1,3) = msg->y3;
00134       break;
00135        
00136     case 1: 
00137       // 3 0 1 2
00138       ipts.at<double>(0,0) = msg->x3;
00139       ipts.at<double>(1,0) = msg->y3;
00140       ipts.at<double>(0,1) = msg->x0;
00141       ipts.at<double>(1,1) = msg->y0;
00142       ipts.at<double>(0,2) = msg->x1;
00143       ipts.at<double>(1,2) = msg->y1;
00144       ipts.at<double>(0,3) = msg->x2;
00145       ipts.at<double>(1,3) = msg->y2;
00146         break;
00147         
00148     case 2:
00149       // 2 3 0 1
00150       ipts.at<double>(0,0) = msg->x2;
00151       ipts.at<double>(1,0) = msg->y2;
00152       ipts.at<double>(0,1) = msg->x3;
00153       ipts.at<double>(1,1) = msg->y3;
00154       ipts.at<double>(0,2) = msg->x0;
00155       ipts.at<double>(1,2) = msg->y0;
00156       ipts.at<double>(0,3) = msg->x1;
00157       ipts.at<double>(1,3) = msg->y1;
00158       break;
00159       
00160     case 3: 
00161       // 1 2 3 0
00162       ipts.at<double>(0,0) = msg->x1;
00163       ipts.at<double>(1,0) = msg->y1;
00164       ipts.at<double>(0,1) = msg->x2;
00165       ipts.at<double>(1,1) = msg->y2;
00166       ipts.at<double>(0,2) = msg->x3;
00167       ipts.at<double>(1,2) = msg->y3;
00168       ipts.at<double>(0,3) = msg->x0;
00169       ipts.at<double>(1,3) = msg->y0;
00170       break;
00171   }
00172 
00173 #if 0
00174   // This was an attempt to replace RPP with OpenCV's pose estimation.
00175   // It seemed to be more noisy, probably because it is not designed to work with coplanar points.
00176 
00177   std::vector<cv::Point2f> imagePoints;
00178   std::vector<cv::Point3f> model2;
00179   for (int i=0; i<4; i++) {
00180       imagePoints.push_back(cv::Point2f(ipts.at<double>(0, i), ipts.at<double>(1, i)));
00181       model2.push_back(cv::Point3f(model.at<double>(0, i), model.at<double>(1, i), model.at<double>(2, i)));
00182       ROS_INFO("model %f %f %f", model.at<double>(0, i), model.at<double>(1, i), model.at<double>(2, i));
00183   }
00184 
00185   cv::Mat rvec(3,1,cv::DataType<double>::type);
00186   cv::Mat tvec(3,1,cv::DataType<double>::type);
00187 
00188   cv::solvePnP(model2, imagePoints, K, dist, rvec, tvec, false, CV_EPNP);
00189 
00190   ROS_INFO("tvec %lf %lf %lf", tvec.at<double>(0, 0), tvec.at<double>(1, 0), tvec.at<double>(2, 0));
00191   ROS_INFO("rvec %lf %lf %lf", r2d(rvec.at<double>(0, 0)), r2d(rvec.at<double>(1, 0)), r2d(rvec.at<double>(2, 0)));
00192 
00193   tf::Vector3 translation(tvec.at<double>(0, 0), tvec.at<double>(1, 0), tvec.at<double>(2, 0));
00194   tf::Quaternion rotation;
00195   rotation.setRPY(rvec.at<double>(0, 0), rvec.at<double>(1, 0), rvec.at<double>(2, 0));
00196   tf::Transform transform(rotation, translation);
00197 
00198   ft->transform.translation.x = translation.x();
00199   ft->transform.translation.y = translation.y();                
00200   ft->transform.translation.z = translation.z(); 
00201 
00202   ft->transform.rotation.w = rotation.w();
00203   ft->transform.rotation.x = rotation.x();
00204   ft->transform.rotation.y = rotation.y();
00205   ft->transform.rotation.z = rotation.z();
00206   ft->fiducial_id = msg->fiducial_id;
00207 #else
00208 
00209   undistortPoints(ipts, K, dist, doUndistort);
00210     
00211   cv::Mat rotation;
00212   cv::Mat translation;
00213   int iterations;
00214   double obj_err;
00215   double img_err;
00216 
00217   std::vector<RPP::Solution> sol;
00218 
00219   std::map<int, cv::Mat>::iterator it;
00220 
00221   it = prevRots.find(msg->fiducial_id);
00222   if (it == prevRots.end()) 
00223      rotation = cv::Mat();
00224   else 
00225      rotation = it->second;
00226 
00227   if(!RPP::Rpp(model, ipts, rotation, translation, iterations, obj_err, img_err, sol)) {
00228     ROS_ERROR("Cannot find transform for fiducial %d", msg->fiducial_id);
00229     return false;
00230   }
00231     
00232   prevRots[msg->fiducial_id] = rotation;
00233 
00234   //ROS_INFO("fid %d iterations %d object error %f image error %f", 
00235   //       msg->fiducial_id, iterations, obj_err, img_err);
00236     
00237   /*
00238   ROS_INFO("fid %d solutions %lu", msg->fiducial_id, sol.size());
00239   for (unsigned int i=0; i<sol.size(); i++) {
00240     double r, p, y;
00241     tf::Matrix3x3 m(sol[i].R.at<double>(0,0), sol[i].R.at<double>(0,1), sol[i].R.at<double>(0,2),
00242                     sol[i].R.at<double>(1,0), sol[i].R.at<double>(1,1), sol[i].R.at<double>(1,2),
00243                     sol[i].R.at<double>(2,0), sol[i].R.at<double>(2,1), sol[i].R.at<double>(2,2));
00244 
00245     tf::Vector3 t(translation.at<double>(0), translation.at<double>(1), translation.at<double>(2));    
00246     
00247     tf::Transform trans(m, t);
00248 
00249     for (int j=0; j<4; j++) {
00250       tf::Vector3 pi(model.at<double>(0,j), model.at<double>(1,j), 0);
00251       tf::Vector3 pw = trans * pi;
00252       ROS_INFO("vertex %d %f %f %f", j, pw.x(), pw.y(), pw.z());
00253     }
00254     m.getRPY(r, p, y);
00255     ROS_INFO("fid %d sol %d R: %.2f %.2f %.2f", msg->fiducial_id, i, r2d(r), r2d(p), r2d(y));
00256   }
00257   */
00258 
00259   tf::Matrix3x3 m1(rotation.at<double>(0,0), rotation.at<double>(0,1), rotation.at<double>(0,2),
00260                    rotation.at<double>(1,0), rotation.at<double>(1,1), rotation.at<double>(1,2),
00261                    rotation.at<double>(2,0), rotation.at<double>(2,1), rotation.at<double>(2,2));
00262   tf::Vector3 t1(translation.at<double>(0), translation.at<double>(1), translation.at<double>(2));    
00263 
00264   tf::Transform trans1(m1, t1);
00265 
00266   frameTransforms[msg->fiducial_id] = trans1;
00267   t1 = trans1.getOrigin();
00268   m1 = trans1.getBasis();
00269 
00270   double r, p, y;
00271   m1.getRPY(r, p, y);
00272   ROS_INFO("fid %d T: %.3lf %.3lf %.3lf R: %.2f %.2f %.2f",
00273            msg->fiducial_id,
00274            t1.x(), t1.y(), t1.z(),
00275            r2d(r), r2d(p), r2d(y));
00276   
00277   /*
00278   ft->header.stamp = frameTime;
00279   char t1name[32];
00280   sprintf(t1name, "fiducial_%d", msg->fiducial_id);
00281   ft->header.frame_id = t1name;
00282   */
00283 
00284   ft->transform.translation.x = t1.x();
00285   ft->transform.translation.y = t1.y();         
00286   ft->transform.translation.z = t1.z(); 
00287   tf::Quaternion q = trans1.getRotation();
00288   ft->transform.rotation.w = q.w();
00289   ft->transform.rotation.x = q.x();
00290   ft->transform.rotation.y = q.y();
00291   ft->transform.rotation.z = q.z();
00292   
00293   ft->fiducial_id = msg->fiducial_id;
00294   //  ft->image_seq = msg->image_seq;
00295   ft->image_error = img_err;
00296   ft->object_error = obj_err;
00297   ft->fiducial_area = calcFiducialArea(ipts);
00298 #endif
00299   return true;
00300 }
00301 
00302 
00303 void RosRpp::camInfoCallback(const sensor_msgs::CameraInfo::ConstPtr& msg)
00304 {
00305   if (haveCamInfo) {
00306     return;
00307   }
00308 
00309   for (int i=0; i<3; i++) {
00310     for (int j=0; j<3; j++) {
00311       K.at<double>(i, j) = msg->K[i*3+j];
00312     }
00313   }
00314   
00315   printf("camera intrinsics:\n");
00316   RPP::Print(K);
00317 
00318   for (int i=0; i<5; i++) {
00319     dist.at<double>(0,i) = msg->D[i];
00320   }
00321   
00322   printf("distortion coefficients:\n");
00323   RPP::Print(dist);
00324 
00325   haveCamInfo = true;
00326 }
00327 
00328 
00329 RosRpp::RosRpp(double fiducialLen, bool doUndistort)
00330 {
00331   this->fiducialLen = fiducialLen;
00332   this->doUndistort = doUndistort;
00333 
00334   // Camera intrinsics
00335   K = cv::Mat::zeros(3, 3, CV_64F);
00336 
00337   // distortion coefficients
00338   dist = cv::Mat::zeros(1, 5, CV_64F);
00339 
00340   // homogeneous 2D points
00341   ipts = cv::Mat::ones(3, 4, CV_64F);
00342 
00343   // 3D points of a fiducial at the origin z = 0
00344   model = cv::Mat::zeros(3, 4, CV_64F); 
00345 
00346   haveCamInfo = false;
00347 
00348   /*
00349      Vertex ordering:
00350 
00351        2  3
00352        1  0
00353 
00354      World 
00355      y
00356      ^
00357      |
00358      `-->x
00359 
00360     Fiducial with origin at center:
00361   */
00362 
00363   model.at<double>(0,0) =  fiducialLen / 2.0;
00364   model.at<double>(1,0) = -fiducialLen / 2.0;
00365   
00366   model.at<double>(0,1) = -fiducialLen / 2.0;
00367   model.at<double>(1,1) = -fiducialLen / 2.0;
00368 
00369   model.at<double>(0,2) = -fiducialLen / 2.0;
00370   model.at<double>(1,2) =  fiducialLen / 2.0;
00371 
00372   model.at<double>(0,3) =  fiducialLen / 2.0;
00373   model.at<double>(1,3) =  fiducialLen / 2.0;
00374 
00375   currentFrame = 0;
00376 } 


fiducial_pose
Author(s): Jim Vaughan
autogenerated on Thu Jun 6 2019 18:08:11