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/models.h>
00031
00032 #include <opencv2/imgproc/imgproc.hpp>
00033
00034 namespace swri_opencv_util
00035 {
00036
00037 int32_t Correspondence2d::GetInlierCount(const M& model, double max_error)
00038 {
00039 CalculateNorms(model, norms__);
00040
00041 cv::compare(norms__, cv::Scalar(max_error * max_error), thresholded__, cv::CMP_LT);
00042
00043 return cv::countNonZero(thresholded__);
00044 }
00045
00046 void Correspondence2d::GetInliers(const M& model, double max_error, std::vector<uint32_t>& indices)
00047 {
00048 CalculateNorms(model, norms__);
00049
00050 indices.clear();
00051 indices.reserve(norms__.rows);
00052 double threshold = max_error * max_error;
00053 for (int i = 0; i < norms__.rows; i++)
00054 {
00055 if (norms__.at<float>(i) < threshold)
00056 {
00057 indices.push_back(i);
00058 }
00059 }
00060 }
00061
00062 void Correspondence2d::CalculateNorms(const M& model, cv::Mat& norms)
00063 {
00064 cv::Mat src = data_(cv::Rect(0, 0, 2, data_.rows)).reshape(2);
00065 cv::transform(src, predicted__, model);
00066 cv::Mat measured = data_(cv::Rect(2, 0, 2, data_.rows));
00067 cv::subtract(predicted__.reshape(1), measured, delta__);
00068 cv::multiply(delta__, delta__, delta_squared__);
00069 cv::add(
00070 delta_squared__(cv::Rect(0, 0, 1, delta__.rows)),
00071 delta_squared__(cv::Rect(1, 0, 1, delta__.rows)),
00072 norms);
00073 }
00074
00075 bool Homography::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00076 {
00077 if (indices.size() != MIN_SIZE)
00078 {
00079 return false;
00080 }
00081
00082 cv::Mat src(MIN_SIZE, 1, CV_32FC2);
00083 cv::Mat dst(MIN_SIZE, 1, CV_32FC2);
00084
00085 for (int32_t i = 0; i < MIN_SIZE; i++)
00086 {
00087 const float* sample = data_.ptr<float>(indices[i]);
00088 src.at<cv::Vec2f>(i, 0) = cv::Vec2f(sample[0], sample[1]);
00089 dst.at<cv::Vec2f>(i, 0) = cv::Vec2f(sample[2], sample[3]);
00090 }
00091
00092 model = cv::getPerspectiveTransform(src, dst);
00093
00094
00095 cv::Mat predicted;
00096 cv::perspectiveTransform(src, predicted, model);
00097 cv::Mat delta, delta_squared, norms;
00098 cv::subtract(predicted.reshape(1), dst.reshape(1), delta);
00099 cv::multiply(delta, delta, delta_squared);
00100 cv::add(
00101 delta_squared(cv::Rect(0, 0, 1, delta.rows)),
00102 delta_squared(cv::Rect(1, 0, 1, delta.rows)),
00103 norms);
00104
00105 double min, max;
00106 cv::minMaxLoc(norms, &min, &max);
00107
00108 return max < max_error * max_error;
00109 }
00110
00111 void Homography::CalculateNorms(const M& model, cv::Mat& norms)
00112 {
00113 cv::Mat src = data_(cv::Rect(0, 0, 2, data_.rows)).reshape(2);
00114 cv::perspectiveTransform(src, predicted__, model);
00115 cv::Mat measured = data_(cv::Rect(2, 0, 2, data_.rows));
00116 cv::subtract(predicted__.reshape(1), measured, delta__);
00117 cv::multiply(delta__, delta__, delta_squared__);
00118 cv::add(
00119 delta_squared__(cv::Rect(0, 0, 1, delta__.rows)),
00120 delta_squared__(cv::Rect(1, 0, 1, delta__.rows)),
00121 norms);
00122 }
00123
00124 bool AffineTransform2d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00125 {
00126 if (indices.size() != MIN_SIZE)
00127 {
00128 return false;
00129 }
00130
00131 cv::Mat src(MIN_SIZE, 1, CV_32FC2);
00132 cv::Mat dst(MIN_SIZE, 1, CV_32FC2);
00133
00134 for (int32_t i = 0; i < MIN_SIZE; i++)
00135 {
00136 const float* sample = data_.ptr<float>(indices[i]);
00137 src.at<cv::Vec2f>(i, 0) = cv::Vec2f(sample[0], sample[1]);
00138 dst.at<cv::Vec2f>(i, 0) = cv::Vec2f(sample[2], sample[3]);
00139 }
00140
00141 model = cv::getAffineTransform(src, dst);
00142
00143
00144 cv::Mat predicted;
00145 cv::transform(src, predicted, model);
00146 cv::Mat delta, delta_squared, norms;
00147 cv::subtract(predicted.reshape(1), dst.reshape(1), delta);
00148 cv::multiply(delta, delta, delta_squared);
00149 cv::add(
00150 delta_squared(cv::Rect(0, 0, 1, delta.rows)),
00151 delta_squared(cv::Rect(1, 0, 1, delta.rows)),
00152 norms);
00153
00154 double min, max;
00155 cv::minMaxLoc(norms, &min, &max);
00156
00157 return max < max_error * max_error;
00158 }
00159
00160 bool RigidTransform2d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00161 {
00162 if (indices.size() != MIN_SIZE)
00163 {
00164 return false;
00165 }
00166
00167 cv::Point2f src[MIN_SIZE];
00168 cv::Point2f dst[MIN_SIZE];
00169
00170 for (int32_t i = 0; i < MIN_SIZE; i++)
00171 {
00172 const float* sample = data_.ptr<float>(indices[i]);
00173 src[i].x = sample[0];
00174 src[i].y = sample[1];
00175 dst[i].x = sample[2];
00176 dst[i].y = sample[3];
00177 }
00178
00179 double len_src = cv::norm(src[1] - src[0]);
00180 double len_dst = cv::norm(dst[1] - dst[0]);
00181 if (std::fabs(len_src - len_dst) >= max_error)
00182 {
00183 return false;
00184 }
00185
00186
00187 cv::Point2f src_x = (src[1] - src[0]) * (1.0 / len_src);
00188 cv::Point2f dst_x = (dst[1] - dst[0]) * (1.0 / len_dst);
00189
00190
00191 cv::Point2f src_y(src_x.y, -src_x.x);
00192 src_y *= 1.0 / cv::norm(src_y);
00193
00194 cv::Point2f dst_y(dst_x.y, -dst_x.x);
00195 dst_y *= 1.0 / cv::norm(dst_y);
00196
00197
00198 cv::Mat src_r(2, 2, CV_32F);
00199 src_r.at<float>(0, 0) = src_x.x;
00200 src_r.at<float>(1, 0) = src_x.y;
00201 src_r.at<float>(0, 1) = src_y.x;
00202 src_r.at<float>(1, 1) = src_y.y;
00203
00204 cv::Mat dst_r(2, 2, CV_32F);
00205 dst_r.at<float>(0, 0) = dst_x.x;
00206 dst_r.at<float>(1, 0) = dst_x.y;
00207 dst_r.at<float>(0, 1) = dst_y.x;
00208 dst_r.at<float>(1, 1) = dst_y.y;
00209
00210
00211
00212
00213 cv::Mat rotation = dst_r * src_r.t();
00214
00215
00216 cv::Mat src0_rotated(2, 1, CV_32F);
00217 src0_rotated.at<float>(0, 0) = src[0].x;
00218 src0_rotated.at<float>(1, 0) = src[0].y;
00219 src0_rotated = rotation * src0_rotated;
00220 float t_x = dst[0].x - src0_rotated.at<float>(0, 0);
00221 float t_y = dst[0].y - src0_rotated.at<float>(1, 0);
00222
00223 model.create(2, 3, CV_32F);
00224 model.at<float>(0, 0) = rotation.at<float>(0, 0);
00225 model.at<float>(0, 1) = rotation.at<float>(0, 1);
00226 model.at<float>(1, 0) = rotation.at<float>(1, 0);
00227 model.at<float>(1, 1) = rotation.at<float>(1, 1);
00228 model.at<float>(0, 2) = t_x;
00229 model.at<float>(1, 2) = t_y;
00230
00231 return true;
00232 }
00233
00234 bool Translation2d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00235 {
00236 if (indices.size() != MIN_SIZE)
00237 {
00238 return false;
00239 }
00240
00241 cv::Point2f src;
00242 cv::Point2f dst;
00243
00244 const float* sample = data_.ptr<float>(indices[0]);
00245 src.x = sample[0];
00246 src.y = sample[1];
00247 dst.x = sample[2];
00248 dst.y = sample[3];
00249
00250
00251 float t_x = dst.x - src.x;
00252 float t_y = dst.y - src.y;
00253
00254 model.create(2, 3, CV_32F);
00255 model.at<float>(0, 0) = 1.0f;
00256 model.at<float>(0, 1) = 0.0f;
00257 model.at<float>(1, 0) = 0.0f;
00258 model.at<float>(1, 1) = 1.0f;
00259 model.at<float>(0, 2) = t_x;
00260 model.at<float>(1, 2) = t_y;
00261
00262 return true;
00263 }
00264
00265 bool Valid2dPointCorrespondences(
00266 const cv::Mat& points1,
00267 const cv::Mat& points2)
00268 {
00269 if (points1.type() != points2.type())
00270 {
00271 return false;
00272 }
00273
00274 if (points1.type() != CV_32FC2)
00275 {
00276 return false;
00277 }
00278
00279 if (points1.cols != points2.cols || points1.rows != points2.rows)
00280 {
00281 return false;
00282 }
00283
00284 if (points1.cols != 1 && points1.rows != 1)
00285 {
00286 return false;
00287 }
00288
00289 return true;
00290 }
00291
00292 bool ZipCorrespondences(
00293 const cv::Mat& points1,
00294 const cv::Mat& points2,
00295 cv::Mat& correspondeces)
00296 {
00297 if (!Valid2dPointCorrespondences(points1, points2))
00298 {
00299 return false;
00300 }
00301
00302 size_t num_points = points1.cols;
00303 bool row_order = false;
00304 if (points1.rows > 1)
00305 {
00306 row_order = true;
00307 num_points = points1.rows;
00308 }
00309
00310
00311 if (row_order)
00312 {
00313 cv::hconcat(points1.reshape(1), points2.reshape(1), correspondeces);
00314 }
00315 else
00316 {
00317 cv::hconcat(
00318 points1.reshape(0, num_points).reshape(1),
00319 points2.reshape(0, num_points).reshape(1),
00320 correspondeces);
00321 }
00322
00323 return true;
00324 }
00325
00326
00327 bool PerpendicularPlaneWithPointFit::GetModel(const std::vector<int32_t>& indices, M& model,
00328 double max_error) const
00329 {
00330 if (indices.size() != MIN_SIZE)
00331 {
00332 return false;
00333 }
00334
00335
00336
00337 cv::Mat points = data_.reshape(3);
00338
00339 cv::Vec3f p1 = points.at<cv::Vec3f>(indices[0], 0);
00340 cv::Vec3f p2 = points.at<cv::Vec3f>(indices[1], 0);
00341 cv::Vec3f p3 = point_;
00342
00343 cv::Point3f v12 = p2 - p1;
00344 cv::Point3f v13 = p3 - p1;
00345 float d12 = cv::norm(v12);
00346 float d13 = cv::norm(v13);
00347 float d = std::fabs(d12 * d13);
00348 if (d == 0)
00349 {
00350 return false;
00351 }
00352
00353 float angle = std::acos(v12.dot(v13) / d);
00354 if (angle < min_angle_ || angle + min_angle_ > M_PI)
00355 {
00356 return false;
00357 }
00358
00359
00360
00361 cv::Vec3f normal = v12.cross(v13);
00362 normal = normal / cv::norm(normal);
00363
00364 if (std::acos(normal.dot(perp_axis_)) > max_axis_angle_)
00365 {
00366 return false;
00367 }
00368
00369 model.x = p1[0];
00370 model.y = p1[1];
00371 model.z = p1[2];
00372 model.i = normal[0];
00373 model.j = normal[1];
00374 model.k = normal[2];
00375
00376 return true;
00377 }
00378
00379 bool PlaneFit::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00380 {
00381 if (indices.size() != MIN_SIZE)
00382 {
00383 return false;
00384 }
00385
00386
00387
00388 cv::Mat points = data_.reshape(3);
00389
00390 cv::Vec3f p1 = points.at<cv::Vec3f>(indices[0], 0);
00391 cv::Vec3f p2 = points.at<cv::Vec3f>(indices[1], 0);
00392 cv::Vec3f p3 = points.at<cv::Vec3f>(indices[2], 0);
00393
00394 cv::Point3f v12 = p2 - p1;
00395 cv::Point3f v13 = p3 - p1;
00396 float d12 = cv::norm(v12);
00397 float d13 = cv::norm(v13);
00398 float d = std::fabs(d12 * d13);
00399 if (d == 0)
00400 {
00401 return false;
00402 }
00403
00404 float angle = std::acos(v12.dot(v13) / d);
00405 if (angle < min_angle_ || angle + min_angle_ > M_PI)
00406 {
00407 return false;
00408 }
00409
00410
00411
00412 cv::Vec3f normal = v12.cross(v13);
00413 normal = normal / cv::norm(normal);
00414
00415 model.x = p1[0];
00416 model.y = p1[1];
00417 model.z = p1[2];
00418 model.i = normal[0];
00419 model.j = normal[1];
00420 model.k = normal[2];
00421
00422 return true;
00423 }
00424
00425 void PlaneFit::CalculateNorms(const M& model, cv::Mat& norms)
00426 {
00427
00428 cv::Mat single_column = data_.reshape(3);
00429 cv::subtract(single_column, cv::Scalar(model.x, model.y, model.z), delta__);
00430
00431
00432
00433 cv::Mat split_columns = delta__.reshape(1);
00434 cv::Mat x = split_columns(cv::Rect(0, 0, 1, split_columns.rows));
00435 cv::Mat y = split_columns(cv::Rect(1, 0, 1, split_columns.rows));
00436 cv::Mat z = split_columns(cv::Rect(2, 0, 1, split_columns.rows));
00437 x = x * model.i;
00438 y = y * model.j;
00439 z = z * model.k;
00440 cv::add(x, y, norms);
00441 cv::add(norms, z, norms);
00442 norms = cv::abs(norms);
00443 }
00444
00445 bool LineFit3d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00446 {
00447 if (indices.size() != MIN_SIZE)
00448 {
00449 return false;
00450 }
00451
00452 cv::Mat points = data_.reshape(3);
00453
00454 cv::Point3f p1(points.at<cv::Vec3f>(indices[0], 0));
00455 cv::Point3f p2(points.at<cv::Vec3f>(indices[1], 0));
00456
00457 cv::Point3f v12 = p2 - p1;
00458 v12 = cv::Vec3f(v12) / cv::norm(v12);
00459
00460 model.x = p1.x;
00461 model.y = p1.y;
00462 model.z = p1.z;
00463 model.i = v12.x;
00464 model.j = v12.y;
00465 model.k = v12.z;
00466
00467 return true;
00468 }
00469
00470 void LineFit3d::CalculateNorms(const M& model, cv::Mat& norms)
00471 {
00472
00473
00474 cv::Scalar x0(model.x, model.y, model.z);
00475 cv::Scalar n(model.i, model.j, model.k);
00476 cv::Mat p = data_.reshape(3);
00477
00478 if (temp1__.size != p.size)
00479 {
00480 temp1__ = cv::Mat(p.rows, p.cols, p.type());
00481 }
00482 temp1__.setTo(n);
00483 cv::Mat n_columns = temp1__.reshape(1);
00484 cv::Mat n_x = n_columns(cv::Rect(0, 0, 1, n_columns.rows));
00485 cv::Mat n_y = n_columns(cv::Rect(1, 0, 1, n_columns.rows));
00486 cv::Mat n_z = n_columns(cv::Rect(2, 0, 1, n_columns.rows));
00487
00488
00489 cv::subtract(p, x0, x0_p__);
00490
00491
00492 cv::multiply(x0_p__, temp1__, temp2__);
00493 cv::reduce(temp2__.reshape(1), x0_p_dot_n__, 1, CV_REDUCE_SUM);
00494
00495
00496 cv::multiply(n_x, x0_p_dot_n__, n_x);
00497 cv::multiply(n_y, x0_p_dot_n__, n_y);
00498 cv::multiply(n_z, x0_p_dot_n__, n_z);
00499
00500
00501 cv::subtract(x0_p__, temp1__, temp1__);
00502
00503
00504 cv::multiply(n_x, n_x, n_x);
00505 cv::multiply(n_y, n_y, n_y);
00506 cv::multiply(n_z, n_z, n_z);
00507 cv::reduce(temp1__.reshape(1), norms, 1, CV_REDUCE_SUM);
00508 cv::sqrt(norms, norms);
00509 }
00510
00511 bool OrthoLineFit3d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00512 {
00513 if (indices.size() != MIN_SIZE)
00514 {
00515 return false;
00516 }
00517
00518 cv::Mat points = data_.reshape(3);
00519
00520 cv::Point3f p1(points.at<cv::Vec3f>(indices[0], 0));
00521 cv::Point3f p2(points.at<cv::Vec3f>(indices[1], 0));
00522
00523 cv::Point3f v12 = p2 - p1;
00524 v12 = cv::Vec3f(v12) / cv::norm(v12);
00525
00526
00527 cv::Point3f ortho(ortho_.i, ortho_.j, ortho_.k);
00528 ortho = cv::Vec3f(ortho) / cv::norm(ortho);
00529
00530 float angle = std::acos(v12.dot(ortho));
00531 float error = std::fabs(M_PI * 0.5 - angle);
00532 if (error > angle_tolerance_)
00533 {
00534 return false;
00535 }
00536
00537 model.x = p1.x;
00538 model.y = p1.y;
00539 model.z = p1.z;
00540 model.i = v12.x;
00541 model.j = v12.y;
00542 model.k = v12.z;
00543
00544 return true;
00545 }
00546
00547 bool CrossFit3d::GetModel(const std::vector<int32_t>& indices, M& model, double max_error) const
00548 {
00549 if (indices.size() != MIN_SIZE)
00550 {
00551 return false;
00552 }
00553
00554
00555
00556 cv::Mat points = data_.reshape(3);
00557
00558 cv::Point3f p1(points.at<cv::Vec3f>(indices[0], 0));
00559 cv::Point3f p2(points.at<cv::Vec3f>(indices[1], 0));
00560 cv::Point3f p3(points.at<cv::Vec3f>(indices[2], 0));
00561
00562 cv::Point3f v12 = p2 - p1;
00563 cv::Point3f v13 = p3 - p1;
00564 float d12 = cv::norm(v12);
00565 float d13 = cv::norm(v13);
00566 float d = std::fabs(d12 * d13);
00567 if (d == 0)
00568 {
00569 return false;
00570 }
00571
00572 float angle = std::acos(v12.dot(v13) / d);
00573 if (angle < min_angle_ || angle + min_angle_ > M_PI)
00574 {
00575 return false;
00576 }
00577
00578
00579
00580
00581
00582
00583 cv::Point3f p4 = p1 + (v13.dot(v12) / v12.dot(v12)) * v12;
00584 cv::Point3f v34 = p4 - p3;
00585
00586
00587 v12 = cv::Vec3f(v12) / cv::norm(v12);
00588 v34 = cv::Vec3f(v34) / cv::norm(v34);
00589
00590 model.x = p4.x;
00591 model.y = p4.y;
00592 model.z = p4.z;
00593 model.i1 = v12.x;
00594 model.j1 = v12.y;
00595 model.k1 = v12.z;
00596 model.i2 = v34.x;
00597 model.j2 = v34.y;
00598 model.k2 = v34.z;
00599
00600 return true;
00601 }
00602
00603 void CrossFit3d::CalculateNorms(const M& model, cv::Mat& norms)
00604 {
00606
00608
00609
00610
00611 cv::Scalar x0(model.x, model.y, model.z);
00612 cv::Scalar n(model.i1, model.j1, model.k1);
00613 cv::Mat p = data_.reshape(3);
00614
00615 if (temp1__.size != p.size)
00616 {
00617 temp1__ = cv::Mat(p.rows, p.cols, p.type());
00618 }
00619 temp1__.setTo(n);
00620 cv::Mat n_columns = temp1__.reshape(1);
00621 cv::Mat n_x = n_columns(cv::Rect(0, 0, 1, n_columns.rows));
00622 cv::Mat n_y = n_columns(cv::Rect(1, 0, 1, n_columns.rows));
00623 cv::Mat n_z = n_columns(cv::Rect(2, 0, 1, n_columns.rows));
00624
00625
00626 cv::subtract(p, x0, x0_p__);
00627
00628
00629 cv::multiply(x0_p__, temp1__, temp2__);
00630 cv::reduce(temp2__.reshape(1), x0_p_dot_n__, 1, CV_REDUCE_SUM);
00631
00632
00633 cv::multiply(n_x, x0_p_dot_n__, n_x);
00634 cv::multiply(n_y, x0_p_dot_n__, n_y);
00635 cv::multiply(n_z, x0_p_dot_n__, n_z);
00636
00637
00638 cv::subtract(x0_p__, temp1__, temp1__);
00639
00640
00641 cv::multiply(n_x, n_x, n_x);
00642 cv::multiply(n_y, n_y, n_y);
00643 cv::multiply(n_z, n_z, n_z);
00644 cv::reduce(temp1__.reshape(1), temp3__, 1, CV_REDUCE_SUM);
00645 cv::sqrt(temp3__, temp3__);
00646
00647
00649
00651
00652
00653
00654 n = cv::Scalar(model.i2, model.j2, model.k2);
00655 temp1__.setTo(n);
00656
00657
00658 cv::subtract(p, x0, x0_p__);
00659
00660
00661 cv::multiply(x0_p__, temp1__, temp2__);
00662 cv::reduce(temp2__.reshape(1), x0_p_dot_n__, 1, CV_REDUCE_SUM);
00663
00664
00665 cv::multiply(n_x, x0_p_dot_n__, n_x);
00666 cv::multiply(n_y, x0_p_dot_n__, n_y);
00667 cv::multiply(n_z, x0_p_dot_n__, n_z);
00668
00669
00670 cv::subtract(x0_p__, temp1__, temp1__);
00671
00672
00673 cv::multiply(n_x, n_x, n_x);
00674 cv::multiply(n_y, n_y, n_y);
00675 cv::multiply(n_z, n_z, n_z);
00676 cv::reduce(temp1__.reshape(1), norms, 1, CV_REDUCE_SUM);
00677 cv::sqrt(norms, norms);
00678
00679
00680 norms = cv::min(norms, temp3__);
00681 }
00682 }