esm.cpp
Go to the documentation of this file.
00001 #include <posest/esm.hpp>
00002 using namespace cv;
00003 
00004 void rect2vertices(const Rect &rect, vector<Point2f> &vertices);
00005 
00006 void HomoESM::setTemplateImage(const Mat &image)
00007 {
00008   assert( image.type() == CV_8UC1 );
00009   templateImage = image;
00010   Mat templateImageDouble;
00011   image.convertTo(templateImageDouble, CV_64FC1);
00012   templateImageRowDouble = templateImageDouble.reshape(0, 1);
00013 
00014   Mat templateDx, templateDy;
00015   computeGradient(templateImage, templateDx, templateDy);
00016   templateDxRow = templateDx.reshape(0, 1);
00017   templateDyRow = templateDy.reshape(0, 1);
00018 
00019   xx.create(1, image.rows * image.cols, CV_64FC1);
00020   yy.create(1, image.rows * image.cols, CV_64FC1);
00021   for (int i = 0; i < image.rows * image.cols; i++)
00022   {
00023     xx.at<double> (0, i) = i % image.cols;
00024     yy.at<double> (0, i) = i / image.cols;
00025   }
00026 
00027   rect2vertices(Rect(0, 0, templateImage.cols, templateImage.rows), templateVertices);
00028 
00029   templatePoints.create(templateImage.size().area(), 1, CV_32FC2);
00030   for (int y = 0; y < templateImage.rows; y++)
00031   {
00032     for (int x = 0; x < templateImage.cols; x++)
00033     {
00034       templatePoints.at<Vec2f> (y * templateImage.cols + x, 0) = Vec2f(x, y);
00035     }
00036   }
00037 }
00038 
00039 void HomoESM::setTestImage(const Mat &image)
00040 {
00041   assert( image.type() == CV_8UC1 );
00042   testImage = image;
00043 }
00044 
00045 double HomoESM::computeRMSError(const Mat &error)
00046 {
00047   return norm(error) / sqrt((double)error.size().area());
00048 }
00049 
00050 void HomoESM::track(int nIters, Mat &H, double &rmsError, Ptr<LieAlgebra> lieAlgebra, bool saveComputations, vector<
00051     HomoESMState> *computations) const
00052 {
00053   if (saveComputations)
00054   {
00055     assert( computations != 0 );
00056     computations->clear();
00057   }
00058 
00059   for (int iter = 0; iter < nIters; iter++)
00060   {
00061     Mat warpedHomogeneousPoints;
00062     transform(templatePoints, warpedHomogeneousPoints, H);
00063     vector<Point2f> warpedPoints;
00064     convertPointsHomogeneous(warpedHomogeneousPoints, warpedPoints);
00065 
00066     Mat warpedTemplateDouble;
00067     constructImage(testImage, warpedPoints, warpedTemplateDouble);
00068 
00069     Mat errorRow = warpedTemplateDouble.reshape(0, 1) - templateImageRowDouble;
00070 
00071     if (saveComputations)
00072     {
00073       HomoESMState state;
00074       H.copyTo(state.H);
00075       state.error = computeRMSError(errorRow);
00076       computations->push_back(state);
00077     }
00078 
00079     if (iter == nIters - 1)
00080     {
00081       rmsError = computeRMSError(errorRow);
00082       break;
00083     }
00084 
00085     Mat warpedTestImageDx, warpedTestImageDy;
00086     computeGradient(warpedTemplateDouble, warpedTestImageDx, warpedTestImageDy);
00087 
00088     Mat Jt;
00089     computeJacobian(templateDxRow + warpedTestImageDx.reshape(0, 1), templateDyRow + warpedTestImageDy.reshape(0, 1),
00090                     Jt, lieAlgebra);
00091 
00092     Mat JtJ;
00093     mulTransposed(Jt, JtJ, false);
00094     //TODO: Is JtJ always non-singular?
00095     Mat d = -2 * JtJ.inv(DECOMP_CHOLESKY) * Jt * errorRow.t();
00096 
00097     Mat delta = lieAlgebra->algebra2group(d);
00098     H = H * delta;
00099   }
00100 }
00101 
00102 void HomoESM::projectVertices(const cv::Mat &H, std::vector<cv::Point2f> &vertices) const
00103 {
00104   vertices.clear();
00105   Mat transformedVertices;
00106   transform(Mat(templateVertices), transformedVertices, H);
00107   convertPointsHomogeneous(transformedVertices, vertices);
00108 }
00109 
00110 void HomoESM::visualizeTracking(const Mat &H, Mat &visualization) const
00111 {
00112   vector<Point2f> vertices;
00113   projectVertices(H, vertices);
00114 
00115   cvtColor(testImage, visualization, CV_GRAY2RGB);
00116   Scalar color = Scalar(0, 255, 0);
00117   int thickness = 2;
00118   for (size_t i = 0; i < vertices.size(); i++)
00119   {
00120     line(visualization, vertices[i], vertices[(i + 1) % vertices.size()], color, thickness);
00121   }
00122 }
00123 
00124 void HomoESM::computeGradient(const Mat &image, Mat &dx, Mat &dy)
00125 {
00126   Sobel(image, dx, CV_64FC1, 1, 0);
00127   Sobel(image, dy, CV_64FC1, 0, 1);
00128 
00129   //normalize to get derivative
00130   dx /= 8.;
00131   dy /= 8.;
00132 }
00133 
00134 void HomoESM::computeJacobian(const Mat &dx, const Mat &dy, Mat &Jt, Ptr<LieAlgebra> lieAlgebra) const
00135 {
00136   assert( dx.rows == 1 );
00137   assert( dy.rows == 1 );
00138   Mat Ix = dx;
00139   Mat Iy = dy;
00140 
00141   const int dim = 3;
00142   Mat JiJw_t(dim * dim, Ix.cols, CV_64FC1);
00143   JiJw_t.row(0) = Ix.mul(xx);
00144   JiJw_t.row(1) = Ix.mul(yy);
00145 
00146   Mat tmpMat = JiJw_t.row(2);
00147   Ix.copyTo(tmpMat);
00148 
00149   JiJw_t.row(3) = Iy.mul(xx);
00150   JiJw_t.row(4) = Iy.mul(yy);
00151 
00152   tmpMat = JiJw_t.row(5);
00153   Iy.copyTo(tmpMat);
00154 
00155   JiJw_t.row(6) = -(xx.mul(JiJw_t.row(0)) + yy.mul(JiJw_t.row(3)));
00156   JiJw_t.row(7) = -(xx.mul(JiJw_t.row(1)) + yy.mul(JiJw_t.row(4)));
00157   JiJw_t.row(8) = -(xx.mul(JiJw_t.row(2)) + yy.mul(JiJw_t.row(5)));
00158 
00159   lieAlgebra->dot(JiJw_t, Jt);
00160 }
00161 
00162 void HomoESM::constructImage(const Mat &srcImage, const vector<Point2f> &points, Mat &intensity) const
00163 {
00164   assert( srcImage.type() == CV_8UC1 );
00165   intensity.create(templateImage.size(), CV_64FC1);
00166 
00167   const double defaultValue = 0;
00168   //Nearest neighbor interpolation
00169   /*
00170   for (size_t i = 0; i < points.size(); i++)
00171   {
00172     double val;
00173     Point pt = points[i];
00174     if (0 <= pt.x && pt.x < srcImage.cols && 0 <= pt.y && pt.y < srcImage.rows)
00175       val = srcImage.at<uchar> (pt.y, pt.x);
00176     else
00177       val = defaultValue;
00178     intensity.at<double> (i / templateImage.cols, i % templateImage.cols) = val;
00179   }
00180   */
00181 
00182   //Bilinear interpolation
00183   for (size_t i = 0; i < points.size(); i++)
00184   {
00185     double val;
00186     Point2f pt = points[i];
00187     if (0 <= pt.x && pt.x < srcImage.cols - 1 && 0 <= pt.y && pt.y < srcImage.rows - 1)
00188     {
00189       Point tl = Point(floor(pt.x), floor(pt.y));
00190       double x1 = pt.x - tl.x;
00191       double y1 = pt.y - tl.y;
00192       double y2 = 1 - y2;
00193       val = (1 - x1) * (1 - y1) * srcImage.at<uchar> (tl.y, tl.x) + x1 * (1 - y1) * srcImage.at<uchar> (tl.y, tl.x + 1)
00194           + (1 - x1) * y1 * srcImage.at<uchar> (tl.y + 1, tl.x) + x1 * y1 * srcImage.at<uchar> (tl.y + 1, tl.x + 1);
00195     }
00196     else
00197       val = defaultValue;
00198     intensity.at<double> (i / templateImage.cols, i % templateImage.cols) = val;
00199   }
00200 }
00201 
00202 void HomoESM::checkAccuracy(vector<vector<HomoESMState> > &computations, string groundTruthFile, double &meanSSDError,
00203                             double &meanSpatialError) const
00204 {
00205   FileStorage fs(groundTruthFile, FileStorage::READ);
00206   assert( fs.isOpened() );
00207 
00208   double ssdErrorSum = 0;
00209   double spatialErrorSum = 0;
00210   const double minSSDError = 1.;
00211   int iterationsCount = 0;
00212   int errorsCount = 0;
00213   for (size_t frameIdx = 0; frameIdx < computations.size(); frameIdx++)
00214   {
00215     for (size_t iterIdx = 0; iterIdx < computations[frameIdx].size(); iterIdx++)
00216     {
00217       std::stringstream frame, iter;
00218       frame << "frame_" << frameIdx;
00219       iter << "iter_" << iterIdx;
00220       double groundTruthError = fs["ESM_results"][frame.str()][iter.str()]["rms_error"];
00221       double error = computations[frameIdx][iterIdx].error;
00222       if (groundTruthError > minSSDError)
00223       {
00224         ssdErrorSum += error / groundTruthError;
00225         errorsCount++;
00226       }
00227       Mat groundTruthH;
00228       fs["ESM_results"][frame.str()][iter.str()]["warp_p"] >> groundTruthH;
00229       Mat H = computations[frameIdx][iterIdx].H;
00230       vector<Point2f> groundTruthVertices;
00231       vector<Point2f> vertices;
00232       projectVertices(groundTruthH, groundTruthVertices);
00233       projectVertices(H, vertices);
00234       double spatialError = norm(Mat(groundTruthVertices), Mat(vertices));
00235       spatialErrorSum += spatialError;
00236       iterationsCount++;
00237     }
00238   }
00239   fs.release();
00240   meanSSDError = ssdErrorSum / errorsCount;
00241   meanSpatialError = spatialErrorSum / iterationsCount;
00242 }
00243 
00244 LieAlgebraHomography::LieAlgebraHomography()
00245 {
00246   basis.resize(8);
00247   basis[0].addPositive(2);
00248   basis[1].addPositive(5);
00249   basis[2].addPositive(1);
00250   basis[3].addPositive(3);
00251 
00252   basis[4].addPositive(0);
00253   basis[4].addNegative(4);
00254   basis[5].addNegative(4);
00255   basis[5].addPositive(8);
00256 
00257   basis[6].addPositive(6);
00258   basis[7].addPositive(7);
00259 }
00260 
00261 LieAlgebraRotation3d::LieAlgebraRotation3d()
00262 {
00263   basis.resize(3);
00264   basis[0].addPositive(1);
00265   basis[0].addNegative(3);
00266   basis[1].addPositive(2);
00267   basis[1].addNegative(6);
00268   basis[2].addPositive(5);
00269   basis[2].addNegative(7);
00270 }
00271 
00272 LieAlgebraTranslation::LieAlgebraTranslation()
00273 {
00274   basis.resize(2);
00275   basis[0].addPositive(2);
00276   basis[1].addPositive(5);
00277 }
00278 
00279 LieAlgebraEuclidean::LieAlgebraEuclidean()
00280 {
00281   LieAlgebraBasisVector vector;
00282   vector.addPositive(1);
00283   vector.addNegative(3);
00284 
00285   basis.push_back(vector);
00286 }
00287 
00288 LieAlgebraSimilarity::LieAlgebraSimilarity()
00289 {
00290   LieAlgebraBasisVector vector;
00291   vector.addPositive(0);
00292   vector.addPositive(4);
00293 
00294   basis.push_back(vector);
00295 }
00296 
00297 LieAlgebraAffine::LieAlgebraAffine()
00298 {
00299   basis.resize(6);
00300   basis[0].addPositive(0);
00301   basis[1].addPositive(1);
00302   basis[2].addPositive(3);
00303   basis[3].addPositive(4);
00304   basis[4].addPositive(2);
00305   basis[5].addPositive(5);
00306 }
00307 
00308 void LieAlgebra::LieAlgebraBasisVector::dot(const Mat &src, Mat dst) const
00309 {
00310   assert( dst.rows == 1 && dst.cols == src.cols );
00311   assert( dst.type() == src.type() );
00312 
00313   for (size_t i = 0; i < positives.size(); i++)
00314     dst += src.row(positives[i]);
00315   for (size_t i = 0; i < negatives.size(); i++)
00316     dst -= src.row(negatives[i]);
00317 }
00318 
00319 Mat LieAlgebra::LieAlgebraBasisVector::vector2mat(double coordinate) const
00320 {
00321   const int dim = 3;
00322   Mat result(dim, dim, CV_64FC1, Scalar(0));
00323 
00324   for (size_t i = 0; i < positives.size(); i++)
00325   {
00326     int row = positives[i] / dim;
00327     int col = positives[i] % dim;
00328     result.at<double> (row, col) = coordinate;
00329   }
00330 
00331   for (size_t i = 0; i < negatives.size(); i++)
00332   {
00333     int row = negatives[i] / dim;
00334     int col = negatives[i] % dim;
00335     result.at<double> (row, col) = -coordinate;
00336   }
00337 
00338   return result;
00339 }
00340 
00341 void LieAlgebra::dot(const Mat &src, Mat &dst) const
00342 {
00343   dst.create(basis.size(), src.cols, CV_64FC1);
00344   dst.setTo(0);
00345 
00346   for (size_t i = 0; i < basis.size(); i++)
00347   {
00348     basis[i].dot(src, dst.row(i));
00349   }
00350 }
00351 
00352 Mat LieAlgebra::algebra2group(const Mat &lieAlgebraCoords) const
00353 {
00354   Mat coords = lieAlgebraCoords.reshape(0, 1);
00355   assert( coords.cols == basis.size() );
00356   assert( coords.type() == CV_64FC1 );
00357 
00358   const int dim = 3;
00359   Mat lieAlgebraMat(dim, dim, CV_64F, Scalar(0));
00360   for (size_t i = 0; i < basis.size(); i++)
00361   {
00362     lieAlgebraMat += basis[i].vector2mat(coords.at<double> (0, i));
00363   }
00364 
00365   Mat lieGroupMat = matrixExp(lieAlgebraMat);
00366   return lieGroupMat;
00367 }
00368 
00369 Mat LieAlgebra::matrixExp(const Mat &mat)
00370 {
00371   assert( mat.rows == 3 );
00372   assert( mat.cols == 3 );
00373   assert( mat.type() == CV_64FC1 );
00374 
00375   Eigen::Matrix<double, 3, 3> eigenMat;
00376   cv2eigen(mat, eigenMat);
00377   Eigen::Matrix<double, 3, 3> matExp;
00378   matExp = eigenMat.exp();
00379 
00380   Mat result;
00381   eigen2cv(matExp, result);
00382   return result;
00383 }
00384 
00385 void rect2vertices(const Rect &rect, vector<Point2f> &vertices)
00386 {
00387   vertices.clear();
00388   vertices.push_back(Point2f(rect.x, rect.y));
00389   vertices.push_back(Point2f(rect.x + rect.width, rect.y));
00390   vertices.push_back(Point2f(rect.x + rect.width, rect.y + rect.height));
00391   vertices.push_back(Point2f(rect.x, rect.y + rect.height));
00392 }


posest
Author(s): Kurt Konolige
autogenerated on Thu Jan 2 2014 12:12:17