1
/*M///////////////////////////////////////////////////////////////////////////////////////
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
11
// For Open Source Computer Vision Library
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
43
#include "precomp.hpp"
44
#include "opencv2/calib3d/calib3d_c.h"
45
#include "opencv2/core/cvdef.h"
48
using namespace cv::detail;
54
IncDistance(std::vector<int> &vdists) : dists(&vdists[0]) {}
55
void operator ()(const GraphEdge &edge) { dists[edge.to] = dists[edge.from] + 1; }
62
CalcRotation(int _num_images, const std::vector<MatchesInfo> &_pairwise_matches, std::vector<CameraParams> &_cameras)
63
: num_images(_num_images), pairwise_matches(&_pairwise_matches[0]), cameras(&_cameras[0]) {}
65
void operator ()(const GraphEdge &edge)
67
int pair_idx = edge.from * num_images + edge.to;
69
Mat_<double> K_from = Mat::eye(3, 3, CV_64F);
70
K_from(0,0) = cameras[edge.from].focal;
71
K_from(1,1) = cameras[edge.from].focal * cameras[edge.from].aspect;
72
K_from(0,2) = cameras[edge.from].ppx;
73
K_from(1,2) = cameras[edge.from].ppy;
75
Mat_<double> K_to = Mat::eye(3, 3, CV_64F);
76
K_to(0,0) = cameras[edge.to].focal;
77
K_to(1,1) = cameras[edge.to].focal * cameras[edge.to].aspect;
78
K_to(0,2) = cameras[edge.to].ppx;
79
K_to(1,2) = cameras[edge.to].ppy;
81
Mat R = K_from.inv() * pairwise_matches[pair_idx].H.inv() * K_to;
82
cameras[edge.to].R = cameras[edge.from].R * R;
86
const MatchesInfo* pairwise_matches;
87
CameraParams* cameras;
91
//////////////////////////////////////////////////////////////////////////////
93
void calcDeriv(const Mat &err1, const Mat &err2, double h, Mat res)
95
for (int i = 0; i < err1.rows; ++i)
96
res.at<double>(i, 0) = (err2.at<double>(i, 0) - err1.at<double>(i, 0)) / h;
105
bool HomographyBasedEstimator::estimate(
106
const std::vector<ImageFeatures> &features,
107
const std::vector<MatchesInfo> &pairwise_matches,
108
std::vector<CameraParams> &cameras)
110
LOGLN("Estimating rotations...");
112
int64 t = getTickCount();
115
const int num_images = static_cast<int>(features.size());
118
// Robustly estimate focal length from rotating cameras
120
for (int iter = 0; iter < 100; ++iter)
122
int len = 2 + rand()%(pairwise_matches.size() - 1);
123
std::vector<int> subset;
124
selectRandomSubset(len, pairwise_matches.size(), subset);
126
for (size_t i = 0; i < subset.size(); ++i)
127
if (!pairwise_matches[subset[i]].H.empty())
128
Hs.push_back(pairwise_matches[subset[i]].H);
132
if (calibrateRotatingCamera(Hs, K))
138
if (!is_focals_estimated_)
140
// Estimate focal length and set it for all cameras
141
std::vector<double> focals;
142
estimateFocal(features, pairwise_matches, focals);
143
cameras.assign(num_images, CameraParams());
144
for (int i = 0; i < num_images; ++i)
145
cameras[i].focal = focals[i];
149
for (int i = 0; i < num_images; ++i)
151
cameras[i].ppx -= 0.5 * features[i].img_size.width;
152
cameras[i].ppy -= 0.5 * features[i].img_size.height;
156
// Restore global motion
158
std::vector<int> span_tree_centers;
159
findMaxSpanningTree(num_images, pairwise_matches, span_tree, span_tree_centers);
160
span_tree.walkBreadthFirst(span_tree_centers[0], CalcRotation(num_images, pairwise_matches, cameras));
162
// As calculations were performed under assumption that p.p. is in image center
163
for (int i = 0; i < num_images; ++i)
165
cameras[i].ppx += 0.5 * features[i].img_size.width;
166
cameras[i].ppy += 0.5 * features[i].img_size.height;
169
LOGLN("Estimating rotations, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
174
//////////////////////////////////////////////////////////////////////////////
176
bool BundleAdjusterBase::estimate(const std::vector<ImageFeatures> &features,
177
const std::vector<MatchesInfo> &pairwise_matches,
178
std::vector<CameraParams> &cameras)
180
LOG_CHAT("Bundle adjustment");
182
int64 t = getTickCount();
185
num_images_ = static_cast<int>(features.size());
186
features_ = &features[0];
187
pairwise_matches_ = &pairwise_matches[0];
189
setUpInitialCameraParams(cameras);
191
// Leave only consistent image pairs
193
for (int i = 0; i < num_images_ - 1; ++i)
195
for (int j = i + 1; j < num_images_; ++j)
197
const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
198
if (matches_info.confidence > conf_thresh_)
199
edges_.push_back(std::make_pair(i, j));
203
// Compute number of correspondences
204
total_num_matches_ = 0;
205
for (size_t i = 0; i < edges_.size(); ++i)
206
total_num_matches_ += static_cast<int>(pairwise_matches[edges_[i].first * num_images_ +
207
edges_[i].second].num_inliers);
209
CvLevMarq solver(num_images_ * num_params_per_cam_,
210
total_num_matches_ * num_errs_per_measurement_,
214
CvMat matParams = cam_params_;
215
cvCopy(&matParams, solver.param);
220
const CvMat* _param = 0;
224
bool proceed = solver.update(_param, _jac, _err);
226
cvCopy(_param, &matParams);
228
if (!proceed || !_err)
249
LOGLN_CHAT("Bundle adjustment, final RMS error: " << std::sqrt(err.dot(err) / total_num_matches_));
250
LOGLN_CHAT("Bundle adjustment, iterations done: " << iter);
252
// Check if all camera parameters are valid
254
for (int i = 0; i < cam_params_.rows; ++i)
256
if (cvIsNaN(cam_params_.at<double>(i,0)))
265
obtainRefinedCameraParams(cameras);
267
// Normalize motion to center image
269
std::vector<int> span_tree_centers;
270
findMaxSpanningTree(num_images_, pairwise_matches, span_tree, span_tree_centers);
271
Mat R_inv = cameras[span_tree_centers[0]].R.inv();
272
for (int i = 0; i < num_images_; ++i)
273
cameras[i].R = R_inv * cameras[i].R;
275
LOGLN_CHAT("Bundle adjustment, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
280
//////////////////////////////////////////////////////////////////////////////
282
void BundleAdjusterReproj::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
284
cam_params_.create(num_images_ * 7, 1, CV_64F);
286
for (int i = 0; i < num_images_; ++i)
288
cam_params_.at<double>(i * 7, 0) = cameras[i].focal;
289
cam_params_.at<double>(i * 7 + 1, 0) = cameras[i].ppx;
290
cam_params_.at<double>(i * 7 + 2, 0) = cameras[i].ppy;
291
cam_params_.at<double>(i * 7 + 3, 0) = cameras[i].aspect;
293
svd(cameras[i].R, SVD::FULL_UV);
294
Mat R = svd.u * svd.vt;
295
if (determinant(R) < 0)
300
CV_Assert(rvec.type() == CV_32F);
301
cam_params_.at<double>(i * 7 + 4, 0) = rvec.at<float>(0, 0);
302
cam_params_.at<double>(i * 7 + 5, 0) = rvec.at<float>(1, 0);
303
cam_params_.at<double>(i * 7 + 6, 0) = rvec.at<float>(2, 0);
308
void BundleAdjusterReproj::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
310
for (int i = 0; i < num_images_; ++i)
312
cameras[i].focal = cam_params_.at<double>(i * 7, 0);
313
cameras[i].ppx = cam_params_.at<double>(i * 7 + 1, 0);
314
cameras[i].ppy = cam_params_.at<double>(i * 7 + 2, 0);
315
cameras[i].aspect = cam_params_.at<double>(i * 7 + 3, 0);
317
Mat rvec(3, 1, CV_64F);
318
rvec.at<double>(0, 0) = cam_params_.at<double>(i * 7 + 4, 0);
319
rvec.at<double>(1, 0) = cam_params_.at<double>(i * 7 + 5, 0);
320
rvec.at<double>(2, 0) = cam_params_.at<double>(i * 7 + 6, 0);
321
Rodrigues(rvec, cameras[i].R);
324
cameras[i].R.convertTo(tmp, CV_32F);
330
void BundleAdjusterReproj::calcError(Mat &err)
332
err.create(total_num_matches_ * 2, 1, CV_64F);
335
for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
337
int i = edges_[edge_idx].first;
338
int j = edges_[edge_idx].second;
339
double f1 = cam_params_.at<double>(i * 7, 0);
340
double f2 = cam_params_.at<double>(j * 7, 0);
341
double ppx1 = cam_params_.at<double>(i * 7 + 1, 0);
342
double ppx2 = cam_params_.at<double>(j * 7 + 1, 0);
343
double ppy1 = cam_params_.at<double>(i * 7 + 2, 0);
344
double ppy2 = cam_params_.at<double>(j * 7 + 2, 0);
345
double a1 = cam_params_.at<double>(i * 7 + 3, 0);
346
double a2 = cam_params_.at<double>(j * 7 + 3, 0);
349
Mat R1_(3, 3, CV_64F, R1);
350
Mat rvec(3, 1, CV_64F);
351
rvec.at<double>(0, 0) = cam_params_.at<double>(i * 7 + 4, 0);
352
rvec.at<double>(1, 0) = cam_params_.at<double>(i * 7 + 5, 0);
353
rvec.at<double>(2, 0) = cam_params_.at<double>(i * 7 + 6, 0);
354
Rodrigues(rvec, R1_);
357
Mat R2_(3, 3, CV_64F, R2);
358
rvec.at<double>(0, 0) = cam_params_.at<double>(j * 7 + 4, 0);
359
rvec.at<double>(1, 0) = cam_params_.at<double>(j * 7 + 5, 0);
360
rvec.at<double>(2, 0) = cam_params_.at<double>(j * 7 + 6, 0);
361
Rodrigues(rvec, R2_);
363
const ImageFeatures& features1 = features_[i];
364
const ImageFeatures& features2 = features_[j];
365
const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
367
Mat_<double> K1 = Mat::eye(3, 3, CV_64F);
368
K1(0,0) = f1; K1(0,2) = ppx1;
369
K1(1,1) = f1*a1; K1(1,2) = ppy1;
371
Mat_<double> K2 = Mat::eye(3, 3, CV_64F);
372
K2(0,0) = f2; K2(0,2) = ppx2;
373
K2(1,1) = f2*a2; K2(1,2) = ppy2;
375
Mat_<double> H = K2 * R2_.inv() * R1_ * K1.inv();
377
for (size_t k = 0; k < matches_info.matches.size(); ++k)
379
if (!matches_info.inliers_mask[k])
382
const DMatch& m = matches_info.matches[k];
383
Point2f p1 = features1.keypoints[m.queryIdx].pt;
384
Point2f p2 = features2.keypoints[m.trainIdx].pt;
385
double x = H(0,0)*p1.x + H(0,1)*p1.y + H(0,2);
386
double y = H(1,0)*p1.x + H(1,1)*p1.y + H(1,2);
387
double z = H(2,0)*p1.x + H(2,1)*p1.y + H(2,2);
389
err.at<double>(2 * match_idx, 0) = p2.x - x/z;
390
err.at<double>(2 * match_idx + 1, 0) = p2.y - y/z;
397
void BundleAdjusterReproj::calcJacobian(Mat &jac)
399
jac.create(total_num_matches_ * 2, num_images_ * 7, CV_64F);
403
const double step = 1e-4;
405
for (int i = 0; i < num_images_; ++i)
407
if (refinement_mask_.at<uchar>(0, 0))
409
val = cam_params_.at<double>(i * 7, 0);
410
cam_params_.at<double>(i * 7, 0) = val - step;
412
cam_params_.at<double>(i * 7, 0) = val + step;
414
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7));
415
cam_params_.at<double>(i * 7, 0) = val;
417
if (refinement_mask_.at<uchar>(0, 2))
419
val = cam_params_.at<double>(i * 7 + 1, 0);
420
cam_params_.at<double>(i * 7 + 1, 0) = val - step;
422
cam_params_.at<double>(i * 7 + 1, 0) = val + step;
424
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 1));
425
cam_params_.at<double>(i * 7 + 1, 0) = val;
427
if (refinement_mask_.at<uchar>(1, 2))
429
val = cam_params_.at<double>(i * 7 + 2, 0);
430
cam_params_.at<double>(i * 7 + 2, 0) = val - step;
432
cam_params_.at<double>(i * 7 + 2, 0) = val + step;
434
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 2));
435
cam_params_.at<double>(i * 7 + 2, 0) = val;
437
if (refinement_mask_.at<uchar>(1, 1))
439
val = cam_params_.at<double>(i * 7 + 3, 0);
440
cam_params_.at<double>(i * 7 + 3, 0) = val - step;
442
cam_params_.at<double>(i * 7 + 3, 0) = val + step;
444
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 3));
445
cam_params_.at<double>(i * 7 + 3, 0) = val;
447
for (int j = 4; j < 7; ++j)
449
val = cam_params_.at<double>(i * 7 + j, 0);
450
cam_params_.at<double>(i * 7 + j, 0) = val - step;
452
cam_params_.at<double>(i * 7 + j, 0) = val + step;
454
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + j));
455
cam_params_.at<double>(i * 7 + j, 0) = val;
461
//////////////////////////////////////////////////////////////////////////////
463
void BundleAdjusterRay::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
465
cam_params_.create(num_images_ * 4, 1, CV_64F);
467
for (int i = 0; i < num_images_; ++i)
469
cam_params_.at<double>(i * 4, 0) = cameras[i].focal;
471
svd(cameras[i].R, SVD::FULL_UV);
472
Mat R = svd.u * svd.vt;
473
if (determinant(R) < 0)
478
CV_Assert(rvec.type() == CV_32F);
479
cam_params_.at<double>(i * 4 + 1, 0) = rvec.at<float>(0, 0);
480
cam_params_.at<double>(i * 4 + 2, 0) = rvec.at<float>(1, 0);
481
cam_params_.at<double>(i * 4 + 3, 0) = rvec.at<float>(2, 0);
486
void BundleAdjusterRay::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
488
for (int i = 0; i < num_images_; ++i)
490
cameras[i].focal = cam_params_.at<double>(i * 4, 0);
492
Mat rvec(3, 1, CV_64F);
493
rvec.at<double>(0, 0) = cam_params_.at<double>(i * 4 + 1, 0);
494
rvec.at<double>(1, 0) = cam_params_.at<double>(i * 4 + 2, 0);
495
rvec.at<double>(2, 0) = cam_params_.at<double>(i * 4 + 3, 0);
496
Rodrigues(rvec, cameras[i].R);
499
cameras[i].R.convertTo(tmp, CV_32F);
505
void BundleAdjusterRay::calcError(Mat &err)
507
err.create(total_num_matches_ * 3, 1, CV_64F);
510
for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
512
int i = edges_[edge_idx].first;
513
int j = edges_[edge_idx].second;
514
double f1 = cam_params_.at<double>(i * 4, 0);
515
double f2 = cam_params_.at<double>(j * 4, 0);
518
Mat R1_(3, 3, CV_64F, R1);
519
Mat rvec(3, 1, CV_64F);
520
rvec.at<double>(0, 0) = cam_params_.at<double>(i * 4 + 1, 0);
521
rvec.at<double>(1, 0) = cam_params_.at<double>(i * 4 + 2, 0);
522
rvec.at<double>(2, 0) = cam_params_.at<double>(i * 4 + 3, 0);
523
Rodrigues(rvec, R1_);
526
Mat R2_(3, 3, CV_64F, R2);
527
rvec.at<double>(0, 0) = cam_params_.at<double>(j * 4 + 1, 0);
528
rvec.at<double>(1, 0) = cam_params_.at<double>(j * 4 + 2, 0);
529
rvec.at<double>(2, 0) = cam_params_.at<double>(j * 4 + 3, 0);
530
Rodrigues(rvec, R2_);
532
const ImageFeatures& features1 = features_[i];
533
const ImageFeatures& features2 = features_[j];
534
const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
536
Mat_<double> K1 = Mat::eye(3, 3, CV_64F);
537
K1(0,0) = f1; K1(0,2) = features1.img_size.width * 0.5;
538
K1(1,1) = f1; K1(1,2) = features1.img_size.height * 0.5;
540
Mat_<double> K2 = Mat::eye(3, 3, CV_64F);
541
K2(0,0) = f2; K2(0,2) = features2.img_size.width * 0.5;
542
K2(1,1) = f2; K2(1,2) = features2.img_size.height * 0.5;
544
Mat_<double> H1 = R1_ * K1.inv();
545
Mat_<double> H2 = R2_ * K2.inv();
547
for (size_t k = 0; k < matches_info.matches.size(); ++k)
549
if (!matches_info.inliers_mask[k])
552
const DMatch& m = matches_info.matches[k];
554
Point2f p1 = features1.keypoints[m.queryIdx].pt;
555
double x1 = H1(0,0)*p1.x + H1(0,1)*p1.y + H1(0,2);
556
double y1 = H1(1,0)*p1.x + H1(1,1)*p1.y + H1(1,2);
557
double z1 = H1(2,0)*p1.x + H1(2,1)*p1.y + H1(2,2);
558
double len = std::sqrt(x1*x1 + y1*y1 + z1*z1);
559
x1 /= len; y1 /= len; z1 /= len;
561
Point2f p2 = features2.keypoints[m.trainIdx].pt;
562
double x2 = H2(0,0)*p2.x + H2(0,1)*p2.y + H2(0,2);
563
double y2 = H2(1,0)*p2.x + H2(1,1)*p2.y + H2(1,2);
564
double z2 = H2(2,0)*p2.x + H2(2,1)*p2.y + H2(2,2);
565
len = std::sqrt(x2*x2 + y2*y2 + z2*z2);
566
x2 /= len; y2 /= len; z2 /= len;
568
double mult = std::sqrt(f1 * f2);
569
err.at<double>(3 * match_idx, 0) = mult * (x1 - x2);
570
err.at<double>(3 * match_idx + 1, 0) = mult * (y1 - y2);
571
err.at<double>(3 * match_idx + 2, 0) = mult * (z1 - z2);
579
void BundleAdjusterRay::calcJacobian(Mat &jac)
581
jac.create(total_num_matches_ * 3, num_images_ * 4, CV_64F);
584
const double step = 1e-3;
586
for (int i = 0; i < num_images_; ++i)
588
for (int j = 0; j < 4; ++j)
590
val = cam_params_.at<double>(i * 4 + j, 0);
591
cam_params_.at<double>(i * 4 + j, 0) = val - step;
593
cam_params_.at<double>(i * 4 + j, 0) = val + step;
595
calcDeriv(err1_, err2_, 2 * step, jac.col(i * 4 + j));
596
cam_params_.at<double>(i * 4 + j, 0) = val;
602
//////////////////////////////////////////////////////////////////////////////
604
void waveCorrect(std::vector<Mat> &rmats, WaveCorrectKind kind)
606
LOGLN("Wave correcting...");
608
int64 t = getTickCount();
610
if (rmats.size() <= 1)
612
LOGLN("Wave correcting, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
616
Mat moment = Mat::zeros(3, 3, CV_32F);
617
for (size_t i = 0; i < rmats.size(); ++i)
619
Mat col = rmats[i].col(0);
620
moment += col * col.t();
622
Mat eigen_vals, eigen_vecs;
623
eigen(moment, eigen_vals, eigen_vecs);
626
if (kind == WAVE_CORRECT_HORIZ)
627
rg1 = eigen_vecs.row(2).t();
628
else if (kind == WAVE_CORRECT_VERT)
629
rg1 = eigen_vecs.row(0).t();
631
CV_Error(CV_StsBadArg, "unsupported kind of wave correction");
633
Mat img_k = Mat::zeros(3, 1, CV_32F);
634
for (size_t i = 0; i < rmats.size(); ++i)
635
img_k += rmats[i].col(2);
636
Mat rg0 = rg1.cross(img_k);
637
double rg0_norm = norm(rg0);
639
if( rg0_norm <= DBL_MIN )
646
Mat rg2 = rg0.cross(rg1);
649
if (kind == WAVE_CORRECT_HORIZ)
651
for (size_t i = 0; i < rmats.size(); ++i)
652
conf += rg0.dot(rmats[i].col(0));
659
else if (kind == WAVE_CORRECT_VERT)
661
for (size_t i = 0; i < rmats.size(); ++i)
662
conf -= rg1.dot(rmats[i].col(0));
670
Mat R = Mat::zeros(3, 3, CV_32F);
672
Mat(rg0.t()).copyTo(tmp);
674
Mat(rg1.t()).copyTo(tmp);
676
Mat(rg2.t()).copyTo(tmp);
678
for (size_t i = 0; i < rmats.size(); ++i)
679
rmats[i] = R * rmats[i];
681
LOGLN("Wave correcting, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
685
//////////////////////////////////////////////////////////////////////////////
687
String matchesGraphAsString(std::vector<String> &pathes, std::vector<MatchesInfo> &pairwise_matches,
688
float conf_threshold)
690
std::stringstream str;
691
str << "graph matches_graph{\n";
693
const int num_images = static_cast<int>(pathes.size());
694
std::set<std::pair<int,int> > span_tree_edges;
695
DisjointSets comps(num_images);
697
for (int i = 0; i < num_images; ++i)
699
for (int j = 0; j < num_images; ++j)
701
if (pairwise_matches[i*num_images + j].confidence < conf_threshold)
703
int comp1 = comps.findSetByElem(i);
704
int comp2 = comps.findSetByElem(j);
707
comps.mergeSets(comp1, comp2);
708
span_tree_edges.insert(std::make_pair(i, j));
713
for (std::set<std::pair<int,int> >::const_iterator itr = span_tree_edges.begin();
714
itr != span_tree_edges.end(); ++itr)
716
std::pair<int,int> edge = *itr;
717
if (span_tree_edges.find(edge) != span_tree_edges.end())
719
String name_src = pathes[edge.first];
720
size_t prefix_len = name_src.find_last_of("/\\");
721
if (prefix_len != String::npos) prefix_len++; else prefix_len = 0;
722
name_src = name_src.substr(prefix_len, name_src.size() - prefix_len);
724
String name_dst = pathes[edge.second];
725
prefix_len = name_dst.find_last_of("/\\");
726
if (prefix_len != String::npos) prefix_len++; else prefix_len = 0;
727
name_dst = name_dst.substr(prefix_len, name_dst.size() - prefix_len);
729
int pos = edge.first*num_images + edge.second;
730
str << "\"" << name_src.c_str() << "\" -- \"" << name_dst.c_str() << "\""
731
<< "[label=\"Nm=" << pairwise_matches[pos].matches.size()
732
<< ", Ni=" << pairwise_matches[pos].num_inliers
733
<< ", C=" << pairwise_matches[pos].confidence << "\"];\n";
737
for (size_t i = 0; i < comps.size.size(); ++i)
739
if (comps.size[comps.findSetByElem((int)i)] == 1)
741
String name = pathes[i];
742
size_t prefix_len = name.find_last_of("/\\");
743
if (prefix_len != String::npos) prefix_len++; else prefix_len = 0;
744
name = name.substr(prefix_len, name.size() - prefix_len);
745
str << "\"" << name.c_str() << "\";\n";
750
return str.str().c_str();
753
std::vector<int> leaveBiggestComponent(std::vector<ImageFeatures> &features, std::vector<MatchesInfo> &pairwise_matches,
754
float conf_threshold)
756
const int num_images = static_cast<int>(features.size());
758
DisjointSets comps(num_images);
759
for (int i = 0; i < num_images; ++i)
761
for (int j = 0; j < num_images; ++j)
763
if (pairwise_matches[i*num_images + j].confidence < conf_threshold)
765
int comp1 = comps.findSetByElem(i);
766
int comp2 = comps.findSetByElem(j);
768
comps.mergeSets(comp1, comp2);
772
int max_comp = static_cast<int>(std::max_element(comps.size.begin(), comps.size.end()) - comps.size.begin());
774
std::vector<int> indices;
775
std::vector<int> indices_removed;
776
for (int i = 0; i < num_images; ++i)
777
if (comps.findSetByElem(i) == max_comp)
778
indices.push_back(i);
780
indices_removed.push_back(i);
782
std::vector<ImageFeatures> features_subset;
783
std::vector<MatchesInfo> pairwise_matches_subset;
784
for (size_t i = 0; i < indices.size(); ++i)
786
features_subset.push_back(features[indices[i]]);
787
for (size_t j = 0; j < indices.size(); ++j)
789
pairwise_matches_subset.push_back(pairwise_matches[indices[i]*num_images + indices[j]]);
790
pairwise_matches_subset.back().src_img_idx = static_cast<int>(i);
791
pairwise_matches_subset.back().dst_img_idx = static_cast<int>(j);
795
if (static_cast<int>(features_subset.size()) == num_images)
798
LOG("Removed some images, because can't match them or there are too similar images: (");
799
LOG(indices_removed[0] + 1);
800
for (size_t i = 1; i < indices_removed.size(); ++i)
801
LOG(", " << indices_removed[i]+1);
803
LOGLN("Try to decrease the match confidence threshold and/or check if you're stitching duplicates.");
805
features = features_subset;
806
pairwise_matches = pairwise_matches_subset;
812
void findMaxSpanningTree(int num_images, const std::vector<MatchesInfo> &pairwise_matches,
813
Graph &span_tree, std::vector<int> ¢ers)
815
Graph graph(num_images);
816
std::vector<GraphEdge> edges;
818
// Construct images graph and remember its edges
819
for (int i = 0; i < num_images; ++i)
821
for (int j = 0; j < num_images; ++j)
823
if (pairwise_matches[i * num_images + j].H.empty())
825
float conf = static_cast<float>(pairwise_matches[i * num_images + j].num_inliers);
826
graph.addEdge(i, j, conf);
827
edges.push_back(GraphEdge(i, j, conf));
831
DisjointSets comps(num_images);
832
span_tree.create(num_images);
833
std::vector<int> span_tree_powers(num_images, 0);
835
// Find maximum spanning tree
836
sort(edges.begin(), edges.end(), std::greater<GraphEdge>());
837
for (size_t i = 0; i < edges.size(); ++i)
839
int comp1 = comps.findSetByElem(edges[i].from);
840
int comp2 = comps.findSetByElem(edges[i].to);
843
comps.mergeSets(comp1, comp2);
844
span_tree.addEdge(edges[i].from, edges[i].to, edges[i].weight);
845
span_tree.addEdge(edges[i].to, edges[i].from, edges[i].weight);
846
span_tree_powers[edges[i].from]++;
847
span_tree_powers[edges[i].to]++;
851
// Find spanning tree leafs
852
std::vector<int> span_tree_leafs;
853
for (int i = 0; i < num_images; ++i)
854
if (span_tree_powers[i] == 1)
855
span_tree_leafs.push_back(i);
857
// Find maximum distance from each spanning tree vertex
858
std::vector<int> max_dists(num_images, 0);
859
std::vector<int> cur_dists;
860
for (size_t i = 0; i < span_tree_leafs.size(); ++i)
862
cur_dists.assign(num_images, 0);
863
span_tree.walkBreadthFirst(span_tree_leafs[i], IncDistance(cur_dists));
864
for (int j = 0; j < num_images; ++j)
865
max_dists[j] = std::max(max_dists[j], cur_dists[j]);
868
// Find min-max distance
869
int min_max_dist = max_dists[0];
870
for (int i = 1; i < num_images; ++i)
871
if (min_max_dist > max_dists[i])
872
min_max_dist = max_dists[i];
874
// Find spanning tree centers
876
for (int i = 0; i < num_images; ++i)
877
if (max_dists[i] == min_max_dist)
878
centers.push_back(i);
879
CV_Assert(centers.size() > 0 && centers.size() <= 2);
882
} // namespace detail