TagDetection.cc
Go to the documentation of this file.
00001 
00002 #include "opencv2/opencv.hpp"
00003 
00004 #include "TagDetection.h"
00005 #include "MathUtil.h"
00006 
00007 #ifdef PLATFORM_APERIOS
00008 //missing/broken isnan
00009 namespace std {
00010         static bool isnan(float x) {
00011                 const int EXP  = 0x7f800000;
00012                 const int FRAC = 0x007fffff;
00013                 const int y = *((int*)(&x));
00014                 return ((y&EXP)==EXP && (y&FRAC)!=0);
00015         }
00016 }
00017 #endif
00018 
00019 namespace AprilTags {
00020 
00021 TagDetection::TagDetection() 
00022   : good(false), obsCode(), code(), id(), hammingDistance(), rotation(), p(),
00023     cxy(), observedPerimeter(), homography(), hxy() {
00024   homography.setZero();
00025 }
00026 
00027 TagDetection::TagDetection(int _id)
00028   : good(false), obsCode(), code(), id(_id), hammingDistance(), rotation(), p(),
00029     cxy(), observedPerimeter(), homography(), hxy() {
00030   homography.setZero();
00031 }
00032 
00033 float TagDetection::getXYOrientation() const {
00034   // Because the order of segments in a quad is arbitrary, so is the
00035   // homography's rotation, so we can't determine orientation directly
00036   // from the homography.  Instead, use the homography to find two
00037   // bottom corners of a properly oriented tag in pixel coordinates,
00038   // and then compute orientation from that.
00039   std::pair<float,float> p0 = interpolate(-1,-1);   // lower left corner of tag
00040   std::pair<float,float> p1 = interpolate(1,-1);    // lower right corner of tag
00041   float orient = atan2(p1.second - p0.second, p1.first - p0.first);
00042   return ! std::isnan(float(orient)) ? orient : 0.;
00043 }
00044 
00045 std::pair<float,float> TagDetection::interpolate(float x, float y) const {
00046   float z = homography(2,0)*x + homography(2,1)*y + homography(2,2);
00047   if ( z == 0 )
00048     return std::pair<float,float>(0,0);  // prevents returning a pair with a -NaN, for which gcc 4.4 flubs isnan
00049   float newx = (homography(0,0)*x + homography(0,1)*y + homography(0,2))/z + hxy.first;
00050   float newy = (homography(1,0)*x + homography(1,1)*y + homography(1,2))/z + hxy.second;
00051   return std::pair<float,float>(newx,newy);
00052 }
00053 
00054 bool TagDetection::overlapsTooMuch(const TagDetection &other) const {
00055   // Compute a sort of "radius" of the two targets. We'll do this by
00056   // computing the average length of the edges of the quads (in
00057   // pixels).
00058   float radius =
00059     ( MathUtil::distance2D(p[0], p[1]) +
00060       MathUtil::distance2D(p[1], p[2]) +
00061       MathUtil::distance2D(p[2], p[3]) +
00062       MathUtil::distance2D(p[3], p[0]) +
00063       MathUtil::distance2D(other.p[0], other.p[1]) +
00064       MathUtil::distance2D(other.p[1], other.p[2]) +
00065       MathUtil::distance2D(other.p[2], other.p[3]) +
00066       MathUtil::distance2D(other.p[3], other.p[0]) ) / 16.0f;
00067 
00068   // distance (in pixels) between two tag centers
00069   float dist = MathUtil::distance2D(cxy, other.cxy);
00070 
00071   // reject pairs where the distance between centroids is smaller than
00072   // the "radius" of one of the tags.
00073   return ( dist < radius );
00074 }
00075 
00076 Eigen::Matrix4d TagDetection::getRelativeTransform(double tag_size, double fx, double fy, double px, double py) const {
00077   std::vector<cv::Point3f> objPts;
00078   std::vector<cv::Point2f> imgPts;
00079   double s = tag_size/2.;
00080   objPts.push_back(cv::Point3f(-s,-s, 0));
00081   objPts.push_back(cv::Point3f( s,-s, 0));
00082   objPts.push_back(cv::Point3f( s, s, 0));
00083   objPts.push_back(cv::Point3f(-s, s, 0));
00084 
00085   std::pair<float, float> p1 = p[0];
00086   std::pair<float, float> p2 = p[1];
00087   std::pair<float, float> p3 = p[2];
00088   std::pair<float, float> p4 = p[3];
00089   imgPts.push_back(cv::Point2f(p1.first, p1.second));
00090   imgPts.push_back(cv::Point2f(p2.first, p2.second));
00091   imgPts.push_back(cv::Point2f(p3.first, p3.second));
00092   imgPts.push_back(cv::Point2f(p4.first, p4.second));
00093 
00094   cv::Mat rvec, tvec;
00095   cv::Matx33f cameraMatrix(
00096                            fx, 0, px,
00097                            0, fy, py,
00098                            0,  0,  1);
00099   cv::Vec4f distParam(0,0,0,0); // all 0?
00100   cv::solvePnP(objPts, imgPts, cameraMatrix, distParam, rvec, tvec);
00101   cv::Matx33d r;
00102   cv::Rodrigues(rvec, r);
00103   Eigen::Matrix3d wRo;
00104   wRo << r(0,0), r(0,1), r(0,2), r(1,0), r(1,1), r(1,2), r(2,0), r(2,1), r(2,2);
00105 
00106   Eigen::Matrix4d T; 
00107   T.topLeftCorner(3,3) = wRo;
00108   T.col(3).head(3) << tvec.at<double>(0), tvec.at<double>(1), tvec.at<double>(2);
00109   T.row(3) << 0,0,0,1;
00110 
00111   return T;
00112 }
00113 
00114 void TagDetection::getRelativeTranslationRotation(double tag_size, double fx, double fy, double px, double py,
00115                                                   Eigen::Vector3d& trans, Eigen::Matrix3d& rot) const {
00116   Eigen::Matrix4d T =
00117     getRelativeTransform(tag_size, fx, fy, px, py);
00118 
00119   // converting from camera frame (z forward, x right, y down) to
00120   // object frame (x forward, y left, z up)
00121   Eigen::Matrix4d M;
00122   M <<
00123     0,  0, 1, 0,
00124     -1, 0, 0, 0,
00125     0, -1, 0, 0,
00126     0,  0, 0, 1;
00127   Eigen::Matrix4d MT = M*T;
00128   // translation vector from camera to the April tag
00129   trans = MT.col(3).head(3);
00130   // orientation of April tag with respect to camera: the camera
00131   // convention makes more sense here, because yaw,pitch,roll then
00132   // naturally agree with the orientation of the object
00133   rot = T.block(0,0,3,3);
00134 }
00135 
00136 // draw one April tag detection on actual image
00137 void TagDetection::draw(cv::Mat& image) const {
00138   // use corner points detected by line intersection
00139   std::pair<float, float> p1 = p[0];
00140   std::pair<float, float> p2 = p[1];
00141   std::pair<float, float> p3 = p[2];
00142   std::pair<float, float> p4 = p[3];
00143 
00144   // plot outline
00145   cv::line(image, cv::Point2f(p1.first, p1.second), cv::Point2f(p2.first, p2.second), cv::Scalar(255,0,0,0) );
00146   cv::line(image, cv::Point2f(p2.first, p2.second), cv::Point2f(p3.first, p3.second), cv::Scalar(0,255,0,0) );
00147   cv::line(image, cv::Point2f(p3.first, p3.second), cv::Point2f(p4.first, p4.second), cv::Scalar(0,0,255,0) );
00148   cv::line(image, cv::Point2f(p4.first, p4.second), cv::Point2f(p1.first, p1.second), cv::Scalar(255,0,255,0) );
00149 
00150   // mark center
00151   cv::circle(image, cv::Point2f(cxy.first, cxy.second), 8, cv::Scalar(0,0,255,0), 2);
00152 
00153   // print ID
00154   std::ostringstream strSt;
00155   strSt << "#" << id;
00156   cv::putText(image, strSt.str(),
00157               cv::Point2f(cxy.first + 10, cxy.second + 10),
00158               cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0,0,255));
00159 }
00160 
00161 } // namespace


apriltags
Author(s): Mitchell Wills
autogenerated on Thu Aug 27 2015 12:23:28