Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
TagDetection.ccGo to the documentation of this file.00001 #include "TagDetection.h" 00002 #include "MathUtil.h" 00003 #include "Shared/mathutils.h" // for isnan fix 00004 using namespace std; 00005 namespace AprilTags { 00006 00007 TagDetection::TagDetection() 00008 : good(false), obsCode(), code(), id(), hammingDistance(), rotation(), p(), 00009 cxy(), observedPerimeter(), homography(), hxy() {} 00010 00011 TagDetection::TagDetection(int _id) 00012 : good(false), obsCode(), code(), id(_id), hammingDistance(), rotation(), p(), 00013 cxy(), observedPerimeter(), homography(), hxy() {} 00014 00015 AngSignPi TagDetection::getXYOrientation() const { 00016 // Original code said: 00017 // Because the order of segments in a quad is arbitrary, so is the 00018 // homography's rotation, so we can't determine orientation directly 00019 // from the homography. Instead, use the homography to find two 00020 // bottom corners of a properly oriented tag in pixel coordinates, 00021 // and then compute orientation from that. 00022 // std::pair<float,float> p0 = interpolate(-1,-1); // lower left corner of tag 00023 // std::pair<float,float> p1 = interpolate(1,-1); // lower right corner of tag 00024 // But we're not computing orientation until the tag is decoded, so 00025 // the points ARE in the right order. Using the points instead of the 00026 // homography avoids occasional buggy behavior with the homography. -- DST 00027 const std::pair<float,float> &p0 = p[0]; 00028 const std::pair<float,float> &p1 = p[1]; 00029 AngSignPi orient = std::atan2(p1.second - p0.second, p1.first - p0.first); 00030 return ! std::isnan(float(orient)) ? orient : AngSignPi(0); 00031 } 00032 00033 fmat::Matrix<4,4> TagDetection::getRotMatrix() const { 00034 // This code was taken in April 2014 from the latest AprilTags 00035 // Java source, but it does not appear to work correctly. -- DST 00036 float s = (7*25.4) / 1000; 00037 float cx = 640/2, cy = 480/2; 00038 float fx = 500, fy = 500; 00039 00040 fmat::Matrix<4,4> M; 00041 M(0,0) = (homography(0,0)-cx*homography(2,0)) / fx; 00042 M(0,1) = (homography(0,1)-cx*homography(2,1)) / fx; 00043 M(0,3) = (homography(0,2)-cx*homography(2,2)) / fx; 00044 M(1,0) = (homography(1,0)-cy*homography(2,0)) / fy; 00045 M(1,1) = (homography(1,1)-cy*homography(2,1)) / fy; 00046 M(1,3) = (homography(1,2)-cy*homography(2,2)) / fy; 00047 M(2,0) = s * homography(2,0); 00048 M(2,1) = s * homography(2,1); 00049 M(2,3) = s * homography(2,2); 00050 00051 float scale0 = sqrt(M(0,0)*M(0,0) + M(1,0)*M(1,0) + M(2,0)*M(2,0)); 00052 float scale1 = sqrt(M(0,1)*M(0,1) + M(1,1)*M(1,1) + M(2,1)*M(2,1)); 00053 float scale = sqrt(scale0 * scale1); 00054 00055 M = M / scale; 00056 if ( M(2,3) > 0 ) 00057 M = M * -1.0; 00058 00059 M(3,0) = M(3,1) = M(3,2) = 0; 00060 M(3,3) = 1; 00061 00062 // Recover third rotation vector by cross product. 00063 fmat::Column<3> a = fmat::pack(M(0,0), M(1,0), M(2,0)); 00064 fmat::Column<3> b = fmat::pack(M(0,1), M(1,1), M(2,1)); 00065 fmat::Column<3> ab = fmat::crossProduct(a,b); 00066 M(0,2) = ab[0]; 00067 M(1,2) = ab[1]; 00068 M(2,2) = ab[2]; 00069 00070 // Pull out just the rotation component so we can normalize it. 00071 fmat::Matrix<3,3> R = fmat::SubMatrix<3,3>(M,0,0); 00072 00073 // Polar decomposition, R = (UV')(VSV') 00074 NEWMAT::Matrix tm(3,3), tmu(3,3), tmv(3,3); 00075 NEWMAT::DiagonalMatrix tmd; 00076 R.exportToNewmat(tm); 00077 NEWMAT::SVD(tm, tmd, tmu, tmv, true, true); 00078 NEWMAT::Matrix MR = tmu * tmv.t(); 00079 R.importFromNewmat(MR); 00080 fmat::SubMatrix<3,3>(M,0,0) = R; 00081 return M; 00082 } 00083 00084 /* 00085 // ***** OLD CODE HERE 00086 00087 double tagSize = 0.200; 00088 double f = 500.0; 00089 00090 // cout << "homography: " << endl << homography.fmt() << endl; 00091 00092 // double F[][] = LinAlg.identity(3); 00093 // F[1][1] = -1; 00094 // F[2][2] = -1; 00095 00096 fmat::Matrix<3,3> identMatrix(fmat::Matrix<3,3>::identity()); 00097 identMatrix(1, 1) = -1; 00098 identMatrix(2, 2) = -1; 00099 // cout << identMatrix.fmt() << endl; 00100 00101 // h = LinAlg.matrixAB(F, h); 00102 fmat::Matrix<3,3> h = identMatrix * homography; 00103 // cout << h.fmt() << endl; 00104 00105 // double M[][] = new double[4][4]; 00106 // M[0][0] = h[0][0] / f; 00107 // M[0][1] = h[0][1] / f; 00108 // M[0][3] = h[0][2] / f; 00109 // M[1][0] = h[1][0] / f; 00110 // M[1][1] = h[1][1] / f; 00111 // M[1][3] = h[1][2] / f; 00112 // M[2][0] = h[2][0]; 00113 // M[2][1] = h[2][1]; 00114 // M[2][3] = h[2][2]; 00115 00116 fmat::Matrix<4,4> m; 00117 00118 // cout << m.fmt() << endl; 00119 00120 m(0,0) = h(0,0) / f; 00121 m(0,1) = h(0,1) / f; 00122 m(0,3) = h(0,2) / f; 00123 m(1,0) = h(1,0) / f; 00124 m(1,1) = h(1,1) / f; 00125 m(1,3) = h(1,2) / f; 00126 m(2,0) = h(2,0); 00127 m(2,1) = h(2,1); 00128 m(2,3) = h(2,2); 00129 00130 // cout << m.fmt() << endl; 00131 00132 // // Compute the scale. The columns of M should be made to be 00133 // // unit vectors. This is over-determined, so we take the 00134 // // geometric average. 00135 // double scale0 = Math.sqrt(sq(M[0][0]) + sq(M[1][0]) + sq(M[2][0])); 00136 // double scale1 = Math.sqrt(sq(M[0][1]) + sq(M[1][1]) + sq(M[2][1])); 00137 // double scale = Math.sqrt(scale0*scale1); 00138 00139 double scale0 = sqrt(MathUtil::square(m(0,0)) + MathUtil::square(m(1,0)) + MathUtil::square(m(2,0))); 00140 double scale1 = sqrt(MathUtil::square(m(0,1)) + MathUtil::square(m(1,1)) + MathUtil::square(m(2,1))); 00141 double scale = sqrt(scale0 * scale1); 00142 00143 // M = LinAlg.scale(M, 1.0/scale); 00144 00145 m = m * (1.0/scale); 00146 00147 // cout << "Scaled" << m.fmt() << endl; 00148 00149 // recover sign of scale factor by noting that observations must occur in front of the camera. 00150 // if (M[2][3] > 0) 00151 // M = LinAlg.scale(M, -1); 00152 00153 if (m(2,3) > 0) 00154 m = m * -1; 00155 00156 // // The bottom row should always be [0 0 0 1]. We reset the 00157 // // first three elements, even though they must be zero, in 00158 // // order to make sure that they are +0. (We could have -0 due 00159 // // to the sign flip above. This is theoretically harmless but 00160 // // annoying in practice.) 00161 // M[3][0] = 0; 00162 // M[3][1] = 0; 00163 // M[3][2] = 0; 00164 // M[3][3] = 1; 00165 00166 m(3,0) = 0; 00167 m(3,1) = 0; 00168 m(3,2) = 0; 00169 m(3,3) = 1; 00170 00171 // // recover third rotation vector by crossproduct of the other two rotation vectors. 00172 // double a[] = new double[] { M[0][0], M[1][0], M[2][0] }; 00173 // double b[] = new double[] { M[0][1], M[1][1], M[2][1] }; 00174 // double ab[] = LinAlg.crossProduct(a,b); 00175 00176 // M[0][2] = ab[0]; 00177 // M[1][2] = ab[1]; 00178 // M[2][2] = ab[2]; 00179 00180 fmat::Column<3> a = fmat::pack(m(0,0), m(1,0), m(2,0)); 00181 fmat::Column<3> b = fmat::pack(m(0,1), m(1,1), m(2,1)); 00182 fmat::Column<3> ab = fmat::crossProduct(a,b); 00183 00184 // cout << ab.fmt() << endl; 00185 00186 m(0,2) = ab[0]; 00187 m(1,2) = ab[1]; 00188 m(2,2) = ab[2]; 00189 00190 // // pull out just the rotation component so we can normalize it. 00191 // double R[][] = new double[3][3]; 00192 // for (int i = 0; i < 3; i++) 00193 // for (int j = 0; j < 3; j++) 00194 // R[i][j] = M[i][j]; 00195 00196 fmat::Matrix<3,3> m2; 00197 for (int i = 0; i < 3; i++) 00198 for (int j = 0; j < 3; j++) 00199 m2(i,j) = m(i,j); 00200 00201 // cout << m2 << endl; 00202 00203 // SingularValueDecomposition svd = new SingularValueDecomposition(new Matrix(R)); 00204 // // polar decomposition, R = (UV')(VSV') 00205 // Matrix MR = svd.getU().times(svd.getV().transpose()); 00206 // for (int i = 0; i < 3; i++) 00207 // for (int j = 0; j < 3; j++) 00208 // M[i][j] = MR.get(i,j); 00209 00210 NEWMAT::Matrix tm(3,3); 00211 m2.exportToNewmat(tm); 00212 NEWMAT::Matrix tmu(3,3); 00213 NEWMAT::Matrix tmv(3,3); 00214 NEWMAT::DiagonalMatrix tmd; 00215 NEWMAT::SVD(tm, tmd, tmu, tmv, true, true); 00216 NEWMAT::Matrix tm2 = tmu * tmv.t(); 00217 fmat::Matrix<3,3> m3; 00218 m3.importFromNewmat(tm2); 00219 00220 // cout << "imported" << endl << m3.fmt() << endl; 00221 00222 for (int i = 0; i < 3; i++) 00223 for (int j = 0; j < 3; j++) 00224 m(i,j) = m3(i,j); 00225 00226 00227 // Scale the results based on the scale in the homography. The 00228 // homography assumes that tags span from -1 to +1, i.e., that 00229 // they are two units wide (and tall). 00230 // for (int i = 0; i < 3; i++) 00231 // M[i][3] *= tagSize / 2; 00232 for (int i = 0; i < 3; i++) 00233 m(i,3) *= tagSize / 2; 00234 00235 // cout << "final" << endl << m << endl; 00236 return m; 00237 } 00238 00239 */ 00240 00241 std::pair<float,float> TagDetection::interpolate(float x, float y) const { 00242 float z = homography(2,0)*x + homography(2,1)*y + homography(2,2); 00243 if ( z == 0 ) 00244 return std::pair<float,float>(0,0); // prevents returning a pair with a -NaN, for which gcc 4.4 flubs isnan 00245 float newx = (homography(0,0)*x + homography(0,1)*y + homography(0,2))/z + hxy.first; 00246 float newy = (homography(1,0)*x + homography(1,1)*y + homography(1,2))/z + hxy.second; 00247 return std::pair<float,float>(newx,newy); 00248 } 00249 00250 bool TagDetection::overlapsTooMuch(const TagDetection &other) const { 00251 // Compute a sort of "radius" of the two targets. We'll do this by 00252 // computing the average length of the edges of the quads (in 00253 // pixels). 00254 float radius = 00255 ( MathUtil::distance2D(p[0], p[1]) + 00256 MathUtil::distance2D(p[1], p[2]) + 00257 MathUtil::distance2D(p[2], p[3]) + 00258 MathUtil::distance2D(p[3], p[0]) + 00259 MathUtil::distance2D(other.p[0], other.p[1]) + 00260 MathUtil::distance2D(other.p[1], other.p[2]) + 00261 MathUtil::distance2D(other.p[2], other.p[3]) + 00262 MathUtil::distance2D(other.p[3], other.p[0]) ) / 16.0f; 00263 00264 // distance (in pixels) between two tag centers 00265 float dist = MathUtil::distance2D(cxy, other.cxy); 00266 00267 // reject pairs where the distance between centroids is smaller than 00268 // the "radius" of one of the tags. 00269 if ( dist < radius ) 00270 std::cout << "AprilTags: rejecting AprilTag with dist=" << dist << " radius=" << radius << std::endl; 00271 return ( dist < radius ); 00272 } 00273 00274 } // namespace |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:51 2016 by Doxygen 1.6.3 |