model_fit.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <swri_opencv_util/model_fit.h>
00031 
00032 #include <ros/ros.h>
00033 
00034 #include <opencv2/imgproc/imgproc.hpp>
00035 
00036 namespace swri_opencv_util
00037 {
00038   cv::Mat FindTranslation2d(
00039     const cv::Mat& points1,
00040     const cv::Mat& points2,
00041     cv::Mat& inliers1,
00042     cv::Mat& inliers2,
00043     std::vector<uint32_t> &good_points,
00044     int32_t& iterations,
00045     double max_error,
00046     double confidence,
00047     int32_t max_iterations,
00048     swri_math_util::RandomGeneratorPtr rng)
00049   {
00050     return FindModel2d<Translation2d>(
00051       points1, points2, inliers1, inliers2, good_points, iterations, max_error,
00052       confidence, max_iterations, rng);
00053   }
00054 
00055   cv::Mat FindRigidTransform2d(
00056     const cv::Mat& points1,
00057     const cv::Mat& points2,
00058     cv::Mat& inliers1,
00059     cv::Mat& inliers2,
00060     std::vector<uint32_t> &good_points,
00061     int32_t& iterations,
00062     double max_error,
00063     double confidence,
00064     int32_t max_iterations,
00065     swri_math_util::RandomGeneratorPtr rng)
00066   {
00067     return FindModel2d<RigidTransform2d>(
00068       points1, points2, inliers1, inliers2, good_points, iterations, max_error,
00069       confidence, max_iterations, rng);
00070   }
00071 
00072   cv::Mat FitRigidTransform2d(const cv::Mat& points1, const cv::Mat& points2)
00073   {
00074     cv::Mat transform;
00075 
00076     if (!Valid2dPointCorrespondences(points1, points2))
00077     {
00078       return transform;
00079     }
00080 
00081     // The Kabsch algorithm, for calculating the optimal rotation matrix that
00082     // minimizes the RMSD (root mean squared deviation) between two paired sets
00083     // of points.  http://en.wikipedia.org/wiki/Kabsch_algorithm
00084 
00085     // Get the centroids of the points.
00086     cv::Scalar centroid1 = cv::mean(points1);
00087     cv::Scalar centroid2 = cv::mean(points2);
00088 
00089     // Center the points around the origin.
00090     cv::Mat points1_centered = (points1 - centroid1);
00091     cv::Mat points2_centered = (points2 - centroid2);
00092 
00093     // Reshape the points into 2xN matrices.
00094     points1_centered = points1_centered.reshape(1, points1.rows);
00095     points2_centered = points2_centered.reshape(1, points1.rows);
00096 
00097     // Compute the covariance matrix.
00098     cv::Mat cov = points1_centered.t() * points2_centered;
00099 
00100     // Compute the optimal rotation matrix.
00101     cv::Mat W, U, Vt;
00102     cv::SVD::compute(cov, W, U, Vt);
00103     double d = cv::determinant(Vt.t() * U.t()) > 0 ? 1.0 : -1.0;
00104     cv::Mat I = cv::Mat::eye(2, 2, CV_32F);
00105     I.at<float>(1, 1) = d;
00106     cv::Mat rotation = Vt.t() * I * U.t();
00107 
00108     // Compute the optimal translation.
00109     cv::Mat c1_r(2, 1, CV_32F);
00110     c1_r.at<float>(0, 0) = centroid1[0];
00111     c1_r.at<float>(1, 0) = centroid1[1];
00112     c1_r = rotation * c1_r;
00113     float t_x = centroid2[0] - c1_r.at<float>(0, 0);
00114     float t_y = centroid2[1] - c1_r.at<float>(1, 0);
00115 
00116     transform.create(2, 3, CV_32F);
00117     transform.at<float>(0, 0) = rotation.at<float>(0, 0);
00118     transform.at<float>(0, 1) = rotation.at<float>(0, 1);
00119     transform.at<float>(1, 0) = rotation.at<float>(1, 0);
00120     transform.at<float>(1, 1) = rotation.at<float>(1, 1);
00121     transform.at<float>(0, 2) = t_x;
00122     transform.at<float>(1, 2) = t_y;
00123 
00124     return transform;
00125   }
00126 
00127   cv::Mat FindAffineTransform2d(
00128     const cv::Mat& points1,
00129     const cv::Mat& points2,
00130     cv::Mat& inliers1,
00131     cv::Mat& inliers2,
00132     std::vector<uint32_t> &good_points,
00133     int32_t& iterations,
00134     double max_error,
00135     double confidence,
00136     int32_t max_iterations,
00137     swri_math_util::RandomGeneratorPtr rng)
00138   {
00139     return FindModel2d<AffineTransform2d>(
00140       points1, points2, inliers1, inliers2, good_points, iterations, max_error,
00141       confidence, max_iterations, rng);
00142   }
00143 
00144   cv::Mat FindHomography(
00145     const cv::Mat& points1,
00146     const cv::Mat& points2,
00147     cv::Mat& inliers1,
00148     cv::Mat& inliers2,
00149     std::vector<uint32_t> &good_points,
00150     int32_t& iterations,
00151     double max_error,
00152     double confidence,
00153     int32_t max_iterations,
00154     swri_math_util::RandomGeneratorPtr rng)
00155   {
00156     return FindModel2d<Homography>(
00157       points1, points2, inliers1, inliers2, good_points, iterations, max_error,
00158       confidence, max_iterations, rng);
00159   }
00160 
00161   cv::Mat FitAffineTransform2d(const cv::Mat& points1, const cv::Mat& points2)
00162   {
00163     cv::Mat transform;
00164 
00165     if (!Valid2dPointCorrespondences(points1, points2))
00166     {
00167       return transform;
00168     }
00169 
00170     bool row_order = points1.rows > 1;
00171     int32_t size = row_order ? points1.rows : points1.cols;
00172 
00173     // Perform least squares fit on inliers to refine model.
00174     //    For least squares there are several decomposition methods:
00175     //       DECOMP_LU
00176     //       DECOMP_CHOLESKY ([A] must be symmetrical)
00177     //       DECOMP_EIG ([A] must be symmetrical)
00178     //       DECOMP_SVD
00179     //       DECOMP_QR
00180     cv::Mat A(size, 3, CV_32F);
00181     cv::Mat B = points2.reshape(1, 2);
00182     if (row_order)
00183     {
00184       for (int32_t i = 0; i < size; ++i)
00185       {
00186         const cv::Vec2f& point = points1.at<cv::Vec2f>(i, 0);
00187         cv::Vec3f& A_i = A.at<cv::Vec3f>(i, 0);
00188         A_i[0] = point[0];
00189         A_i[1] = point[1];
00190         A_i[2] = 1.0;
00191       }
00192     }
00193     else
00194     {
00195       B = points2.t();
00196       B = B.reshape(1, 2);
00197 
00198       for (int32_t i = 0; i < size; ++i)
00199       {
00200         const cv::Vec2f& point = points1.at<cv::Vec2f>(0, i);
00201         cv::Vec3f& A_i = A.at<cv::Vec3f>(i, 0);
00202         A_i[0] = point[0];
00203         A_i[1] = point[1];
00204         A_i[2] = 1.0;
00205       }
00206     }
00207 
00208     cv::Mat x;
00209     if (cv::solve(A, B, x))
00210     {
00211       transform = x;
00212     }
00213 
00214     return transform;
00215   }
00216 
00217   PlaneModel FindPerpendicularPlaneWithPoint(
00218     const cv::Vec3f& point_on_plane,
00219     const cv::Vec3f& perp_axis,
00220     double max_angle_from_perp,
00221     const cv::Mat& points,
00222     cv::Mat& inliers,
00223     std::vector<uint32_t> &good_points,
00224     int32_t& iterations,
00225     double max_error,
00226     double confidence,
00227     int32_t min_iterations,
00228     int32_t max_iterations,
00229     swri_math_util::RandomGeneratorPtr rng)
00230   {
00231     swri_math_util::Ransac<PerpendicularPlaneWithPointFit> ransac(rng);
00232 
00233     cv::Mat reshaped = points.reshape(3);
00234     PerpendicularPlaneWithPointFit fit_model(reshaped, point_on_plane, perp_axis, max_angle_from_perp);
00235     PlaneModel model = ransac.FitModel(
00236       fit_model, max_error, confidence, min_iterations, max_iterations, good_points, iterations);
00237 
00238     if (good_points.empty())
00239     {
00240       return model;
00241     }
00242 
00243     inliers = cv::Mat(good_points.size(), reshaped.cols, reshaped.type());
00244     for (size_t i = 0; i < good_points.size(); ++i)
00245     {
00246       inliers.at<cv::Vec3f>(i, 0) = reshaped.at<cv::Vec3f>(good_points[i], 0);
00247     }
00248     inliers.reshape(points.channels());
00249     return model;
00250   }
00251 
00252 
00253   PlaneModel FindPlane(
00254     const cv::Mat& points,
00255     cv::Mat& inliers,
00256     std::vector<uint32_t> &good_points,
00257     int32_t& iterations,
00258     double max_error,
00259     double confidence,
00260     int32_t min_iterations,
00261     int32_t max_iterations,
00262     swri_math_util::RandomGeneratorPtr rng)
00263   {
00264     swri_math_util::Ransac<PlaneFit> ransac(rng);
00265 
00266     cv::Mat reshaped = points.reshape(3);
00267     PlaneFit fit_model(reshaped);
00268     PlaneModel model = ransac.FitModel(
00269       fit_model, max_error, confidence, min_iterations, max_iterations, good_points, iterations);
00270 
00271     if (good_points.empty())
00272     {
00273       return model;
00274     }
00275 
00276     inliers = cv::Mat(good_points.size(), reshaped.cols, reshaped.type());
00277     for (size_t i = 0; i < good_points.size(); ++i)
00278     {
00279       inliers.at<cv::Vec3f>(i, 0) = reshaped.at<cv::Vec3f>(good_points[i], 0);
00280     }
00281     inliers.reshape(points.channels());
00282     return model;
00283   }
00284 
00285   PlaneModel FitPlane(const cv::Mat& points)
00286   {
00287     PlaneModel model;
00288     if (points.rows < 3)
00289     {
00290       return model;
00291     }
00292     cv::Mat centroid;
00293     cv::reduce(points.reshape(3), centroid, 0, CV_REDUCE_AVG);
00294 
00295     cv::Scalar c(centroid.at<float>(0, 0), centroid.at<float>(0, 1), centroid.at<float>(0, 2)); 
00296 
00297     cv::Mat A;
00298     cv::subtract(points, c, A);
00299 
00300     cv::SVD svd;
00301     cv::Mat w, u, vt;
00302     cv::Mat At;
00303     cv::transpose(A.reshape(1), At);
00304     svd.compute(At, w, u, vt);
00305 
00306     cv::Point min_w_loc;
00307     cv::minMaxLoc(w, NULL, NULL, &min_w_loc);
00308 
00309     model.x = centroid.at<float>(0, 0);
00310     model.y = centroid.at<float>(0, 1);
00311     model.z = centroid.at<float>(0, 2);
00312     model.i = u.at<float>(0, min_w_loc.y);
00313     model.j = u.at<float>(1, min_w_loc.y);
00314     model.k = u.at<float>(2, min_w_loc.y);
00315 
00316     return model;
00317   }
00318 
00319   LineModel3d FindLine3d(
00320     const cv::Mat& points,
00321     cv::Mat& inliers,
00322     std::vector<uint32_t> &good_points,
00323     int32_t& iterations,
00324     double max_error,
00325     double confidence,
00326     int32_t min_iterations,
00327     int32_t max_iterations,
00328     swri_math_util::RandomGeneratorPtr rng)
00329   {
00330     swri_math_util::Ransac<LineFit3d> ransac(rng);
00331 
00332     cv::Mat reshaped = points.reshape(3);
00333     LineFit3d fit_model(reshaped);
00334     LineModel3d model = ransac.FitModel(
00335       fit_model, max_error, confidence, min_iterations, max_iterations, good_points, iterations);
00336 
00337     if (good_points.empty())
00338     {
00339       return model;
00340     }
00341 
00342     inliers = cv::Mat(good_points.size(), reshaped.cols, reshaped.type());
00343     for (size_t i = 0; i < good_points.size(); ++i)
00344     {
00345       inliers.at<cv::Vec3f>(i, 0) = reshaped.at<cv::Vec3f>(good_points[i], 0);
00346     }
00347     inliers.reshape(points.channels());
00348     return model;
00349   }
00350 
00351   LineModel3d FindOrthoLine3d(
00352     const cv::Mat& points,
00353     const LineModel3d& ortho,
00354     cv::Mat& inliers,
00355     std::vector<uint32_t> &good_points,
00356     int32_t& iterations,
00357     double max_error,
00358     double confidence,
00359     int32_t min_iterations,
00360     int32_t max_iterations,
00361     swri_math_util::RandomGeneratorPtr rng)
00362   {
00363     swri_math_util::Ransac<LineFit3d> ransac(rng);
00364 
00365     cv::Mat reshaped = points.reshape(3);
00366     OrthoLineFit3d fit_model(reshaped, ortho);
00367     LineModel3d model = ransac.FitModel(
00368       fit_model, max_error, confidence, min_iterations, max_iterations, good_points, iterations);
00369 
00370     if (good_points.empty())
00371     {
00372       return model;
00373     }
00374 
00375     inliers = cv::Mat(good_points.size(), reshaped.cols, reshaped.type());
00376     for (size_t i = 0; i < good_points.size(); ++i)
00377     {
00378       inliers.at<cv::Vec3f>(i, 0) = reshaped.at<cv::Vec3f>(good_points[i], 0);
00379     }
00380     inliers.reshape(points.channels());
00381     return model;
00382   }
00383 
00384   LineModel3d FitLine3d(const cv::Mat& points)
00385   {
00386     LineModel3d model;
00387     if (points.rows < 2)
00388     {
00389       return model;
00390     }
00391     cv::Mat centroid;
00392     cv::reduce(points.reshape(3), centroid, 0, CV_REDUCE_AVG);
00393 
00394     cv::Scalar c(centroid.at<float>(0, 0), centroid.at<float>(0, 1), centroid.at<float>(0, 2)); 
00395    
00396     cv::Mat A;
00397     cv::subtract(points, c, A);
00398 
00399     cv::SVD svd;
00400     cv::Mat w, u, vt;
00401     cv::Mat At;
00402     cv::transpose(A.reshape(1), At);
00403     svd.compute(At, w, u, vt);
00404 
00405     cv::Point max_w_loc;
00406     cv::minMaxLoc(w, NULL, NULL, NULL, &max_w_loc);
00407 
00408     model.x = centroid.at<float>(0, 0);
00409     model.y = centroid.at<float>(0, 1);
00410     model.z = centroid.at<float>(0, 2);
00411     model.i = u.at<float>(0, max_w_loc.y);
00412     model.j = u.at<float>(1, max_w_loc.y);
00413     model.k = u.at<float>(2, max_w_loc.y);
00414 
00415     return model;
00416   }
00417 
00418   CrossModel3d FindCross3d(
00419     const cv::Mat& points,
00420     cv::Mat& inliers,
00421     std::vector<uint32_t> &good_points,
00422     int32_t& iterations,
00423     double max_error,
00424     double confidence,
00425     int32_t min_iterations,
00426     int32_t max_iterations,
00427     swri_math_util::RandomGeneratorPtr rng)
00428   {
00429     swri_math_util::Ransac<CrossFit3d> ransac(rng);
00430 
00431     cv::Mat reshaped = points.reshape(3);
00432     CrossFit3d fit_model(reshaped);
00433     CrossModel3d model = ransac.FitModel(
00434       fit_model, max_error, confidence, min_iterations, max_iterations, good_points, iterations);
00435 
00436     if (good_points.empty())
00437     {
00438       return model;
00439     }
00440 
00441     inliers = cv::Mat(good_points.size(), reshaped.cols, reshaped.type());
00442     for (size_t i = 0; i < good_points.size(); ++i)
00443     {
00444       inliers.at<cv::Vec3f>(i, 0) = reshaped.at<cv::Vec3f>(good_points[i], 0);
00445     }
00446     inliers.reshape(points.channels());
00447     return model;
00448   }
00449 }


swri_opencv_util
Author(s): Marc Alban
autogenerated on Tue Oct 3 2017 03:19:24