00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00082
00083
00084
00085
00086 cv::Scalar centroid1 = cv::mean(points1);
00087 cv::Scalar centroid2 = cv::mean(points2);
00088
00089
00090 cv::Mat points1_centered = (points1 - centroid1);
00091 cv::Mat points2_centered = (points2 - centroid2);
00092
00093
00094 points1_centered = points1_centered.reshape(1, points1.rows);
00095 points2_centered = points2_centered.reshape(1, points1.rows);
00096
00097
00098 cv::Mat cov = points1_centered.t() * points2_centered;
00099
00100
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
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
00174
00175
00176
00177
00178
00179
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 }