00001 #include "Vision/AprilTags/FloatImage.h"
00002 #include "Vision/AprilTags/MathUtil.h"
00003 #include "Vision/AprilTags/GLine2D.h"
00004 #include "Vision/AprilTags/Quad.h"
00005 #include "Vision/AprilTags/Segment.h"
00006
00007 namespace AprilTags {
00008
00009 const float Quad::maxQuadAspectRatio = 32;
00010
00011 Quad::Quad(const std::vector< std::pair<float,float> >& p, const std::pair<float,float>& opticalCenter)
00012 : quadPoints(p), segments(), observedPerimeter(), homography(opticalCenter) {
00013 homography.addCorrespondence(-1, -1, quadPoints[0].first, quadPoints[0].second);
00014 homography.addCorrespondence( 1, -1, quadPoints[1].first, quadPoints[1].second);
00015 homography.addCorrespondence( 1, 1, quadPoints[2].first, quadPoints[2].second);
00016 homography.addCorrespondence(-1, 1, quadPoints[3].first, quadPoints[3].second);
00017 }
00018
00019 std::pair<float,float> Quad::interpolate(float x, float y) {
00020 return homography.project(x,y);
00021 }
00022
00023 std::pair<float,float> Quad::interpolate01(float x, float y) {
00024 return interpolate(2*x-1, 2*y-1);
00025 }
00026
00027 void Quad::search(const FloatImage& fImage, std::vector<Segment*>& path,
00028 Segment& parent, int depth, std::vector<Quad>& quads) {
00029
00030
00031 if (depth == 4) {
00032
00033
00034
00035 if (path[4] == path[0]) {
00036
00037 std::vector< std::pair<float,float> > p(4);
00038 float calculatedPerimeter = 0;
00039 bool bad = false;
00040 for (int i = 0; i < 4; i++) {
00041
00042
00043 GLine2D linea(std::make_pair(path[i]->getX0(),path[i]->getY0()),
00044 std::make_pair(path[i]->getX1(),path[i]->getY1()));
00045 GLine2D lineb(std::make_pair(path[i+1]->getX0(),path[i+1]->getY0()),
00046 std::make_pair(path[i+1]->getX1(),path[i+1]->getY1()));
00047
00048 p[i] = linea.intersectionWith(lineb);
00049 calculatedPerimeter += path[i]->getLength();
00050
00051
00052 if (p[i].first == -1)
00053 bad = true;
00054 }
00055
00056
00057
00058 if (!bad) {
00059 float t0 = std::atan2(p[1].second-p[0].second, p[1].first-p[0].first);
00060 float t1 = std::atan2(p[2].second-p[1].second, p[2].first-p[1].first);
00061 float t2 = std::atan2(p[3].second-p[2].second, p[3].first-p[2].first);
00062 float t3 = std::atan2(p[0].second-p[3].second, p[0].first-p[3].first);
00063
00064
00065
00066 float ttheta = MathUtil::mod2pi(t1-t0) + MathUtil::mod2pi(t2-t1) +
00067 MathUtil::mod2pi(t3-t2) + MathUtil::mod2pi(t0-t3);
00068
00069
00070
00071 if (ttheta < -7 || ttheta > -5)
00072 bad = true;
00073 }
00074
00075 if (!bad) {
00076 float d0 = MathUtil::distance2D(p[0], p[1]);
00077 float d1 = MathUtil::distance2D(p[1], p[2]);
00078 float d2 = MathUtil::distance2D(p[2], p[3]);
00079 float d3 = MathUtil::distance2D(p[3], p[0]);
00080 float d4 = MathUtil::distance2D(p[0], p[2]);
00081 float d5 = MathUtil::distance2D(p[1], p[3]);
00082
00083
00084 if (d0 < Quad::minimumEdgeLength || d1 < Quad::minimumEdgeLength || d2 < Quad::minimumEdgeLength ||
00085 d3 < Quad::minimumEdgeLength || d4 < Quad::minimumEdgeLength || d5 < Quad::minimumEdgeLength) {
00086 bad = true;
00087
00088 }
00089
00090
00091 float dmax = max(max(d0,d1), max(d2,d3));
00092 float dmin = min(min(d0,d1), min(d2,d3));
00093
00094 if (dmax > dmin*Quad::maxQuadAspectRatio) {
00095 bad = true;
00096
00097 }
00098 }
00099
00100 if (!bad) {
00101 std::pair<float,float> opticalCenter(fImage.getWidth()/2, fImage.getHeight()/2);
00102 Quad q(p, opticalCenter);
00103 q.segments=path;
00104 q.observedPerimeter = calculatedPerimeter;
00105 quads.push_back(q);
00106 }
00107 }
00108 return;
00109 }
00110
00111
00112
00113
00114
00115 for (unsigned int i = 0; i < parent.children.size(); i++) {
00116 Segment &child = *parent.children[i];
00117
00118
00119
00120
00121
00122
00123
00124
00125 if ( child.getTheta() > path[0]->getTheta() ) {
00126
00127 continue;
00128 }
00129 path[depth+1] = &child;
00130 search(fImage, path, child, depth+1, quads);
00131 }
00132 }
00133
00134 }