1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
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.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
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.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
22 //
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.
26 //
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.
29 //
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.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44 #include "opencv2/calib3d/calib3d_c.h"
45 #include "opencv2/core/cvdef.h"
46
47 using namespace cv;
48 using namespace cv::detail;
49
50 namespace {
51
52 struct IncDistance
53 {
IncDistance__anonc4d9fe160111::IncDistance54 IncDistance(std::vector<int> &vdists) : dists(&vdists[0]) {}
operator ()__anonc4d9fe160111::IncDistance55 void operator ()(const GraphEdge &edge) { dists[edge.to] = dists[edge.from] + 1; }
56 int* dists;
57 };
58
59
60 struct CalcRotation
61 {
CalcRotation__anonc4d9fe160111::CalcRotation62 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]) {}
64
operator ()__anonc4d9fe160111::CalcRotation65 void operator ()(const GraphEdge &edge)
66 {
67 int pair_idx = edge.from * num_images + edge.to;
68
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;
74
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;
80
81 Mat R = K_from.inv() * pairwise_matches[pair_idx].H.inv() * K_to;
82 cameras[edge.to].R = cameras[edge.from].R * R;
83 }
84
85 int num_images;
86 const MatchesInfo* pairwise_matches;
87 CameraParams* cameras;
88 };
89
90
91 //////////////////////////////////////////////////////////////////////////////
92
calcDeriv(const Mat & err1,const Mat & err2,double h,Mat res)93 void calcDeriv(const Mat &err1, const Mat &err2, double h, Mat res)
94 {
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;
97 }
98
99 } // namespace
100
101
102 namespace cv {
103 namespace detail {
104
estimate(const std::vector<ImageFeatures> & features,const std::vector<MatchesInfo> & pairwise_matches,std::vector<CameraParams> & cameras)105 bool HomographyBasedEstimator::estimate(
106 const std::vector<ImageFeatures> &features,
107 const std::vector<MatchesInfo> &pairwise_matches,
108 std::vector<CameraParams> &cameras)
109 {
110 LOGLN("Estimating rotations...");
111 #if ENABLE_LOG
112 int64 t = getTickCount();
113 #endif
114
115 const int num_images = static_cast<int>(features.size());
116
117 #if 0
118 // Robustly estimate focal length from rotating cameras
119 std::vector<Mat> Hs;
120 for (int iter = 0; iter < 100; ++iter)
121 {
122 int len = 2 + rand()%(pairwise_matches.size() - 1);
123 std::vector<int> subset;
124 selectRandomSubset(len, pairwise_matches.size(), subset);
125 Hs.clear();
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);
129 Mat_<double> K;
130 if (Hs.size() >= 2)
131 {
132 if (calibrateRotatingCamera(Hs, K))
133 cin.get();
134 }
135 }
136 #endif
137
138 if (!is_focals_estimated_)
139 {
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];
146 }
147 else
148 {
149 for (int i = 0; i < num_images; ++i)
150 {
151 cameras[i].ppx -= 0.5 * features[i].img_size.width;
152 cameras[i].ppy -= 0.5 * features[i].img_size.height;
153 }
154 }
155
156 // Restore global motion
157 Graph span_tree;
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));
161
162 // As calculations were performed under assumption that p.p. is in image center
163 for (int i = 0; i < num_images; ++i)
164 {
165 cameras[i].ppx += 0.5 * features[i].img_size.width;
166 cameras[i].ppy += 0.5 * features[i].img_size.height;
167 }
168
169 LOGLN("Estimating rotations, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
170 return true;
171 }
172
173
174 //////////////////////////////////////////////////////////////////////////////
175
estimate(const std::vector<ImageFeatures> & features,const std::vector<MatchesInfo> & pairwise_matches,std::vector<CameraParams> & cameras)176 bool BundleAdjusterBase::estimate(const std::vector<ImageFeatures> &features,
177 const std::vector<MatchesInfo> &pairwise_matches,
178 std::vector<CameraParams> &cameras)
179 {
180 LOG_CHAT("Bundle adjustment");
181 #if ENABLE_LOG
182 int64 t = getTickCount();
183 #endif
184
185 num_images_ = static_cast<int>(features.size());
186 features_ = &features[0];
187 pairwise_matches_ = &pairwise_matches[0];
188
189 setUpInitialCameraParams(cameras);
190
191 // Leave only consistent image pairs
192 edges_.clear();
193 for (int i = 0; i < num_images_ - 1; ++i)
194 {
195 for (int j = i + 1; j < num_images_; ++j)
196 {
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));
200 }
201 }
202
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);
208
209 CvLevMarq solver(num_images_ * num_params_per_cam_,
210 total_num_matches_ * num_errs_per_measurement_,
211 term_criteria_);
212
213 Mat err, jac;
214 CvMat matParams = cam_params_;
215 cvCopy(&matParams, solver.param);
216
217 int iter = 0;
218 for(;;)
219 {
220 const CvMat* _param = 0;
221 CvMat* _jac = 0;
222 CvMat* _err = 0;
223
224 bool proceed = solver.update(_param, _jac, _err);
225
226 cvCopy(_param, &matParams);
227
228 if (!proceed || !_err)
229 break;
230
231 if (_jac)
232 {
233 calcJacobian(jac);
234 CvMat tmp = jac;
235 cvCopy(&tmp, _jac);
236 }
237
238 if (_err)
239 {
240 calcError(err);
241 LOG_CHAT(".");
242 iter++;
243 CvMat tmp = err;
244 cvCopy(&tmp, _err);
245 }
246 }
247
248 LOGLN_CHAT("");
249 LOGLN_CHAT("Bundle adjustment, final RMS error: " << std::sqrt(err.dot(err) / total_num_matches_));
250 LOGLN_CHAT("Bundle adjustment, iterations done: " << iter);
251
252 // Check if all camera parameters are valid
253 bool ok = true;
254 for (int i = 0; i < cam_params_.rows; ++i)
255 {
256 if (cvIsNaN(cam_params_.at<double>(i,0)))
257 {
258 ok = false;
259 break;
260 }
261 }
262 if (!ok)
263 return false;
264
265 obtainRefinedCameraParams(cameras);
266
267 // Normalize motion to center image
268 Graph span_tree;
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;
274
275 LOGLN_CHAT("Bundle adjustment, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
276 return true;
277 }
278
279
280 //////////////////////////////////////////////////////////////////////////////
281
setUpInitialCameraParams(const std::vector<CameraParams> & cameras)282 void BundleAdjusterReproj::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
283 {
284 cam_params_.create(num_images_ * 7, 1, CV_64F);
285 SVD svd;
286 for (int i = 0; i < num_images_; ++i)
287 {
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;
292
293 svd(cameras[i].R, SVD::FULL_UV);
294 Mat R = svd.u * svd.vt;
295 if (determinant(R) < 0)
296 R *= -1;
297
298 Mat rvec;
299 Rodrigues(R, rvec);
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);
304 }
305 }
306
307
obtainRefinedCameraParams(std::vector<CameraParams> & cameras) const308 void BundleAdjusterReproj::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
309 {
310 for (int i = 0; i < num_images_; ++i)
311 {
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);
316
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);
322
323 Mat tmp;
324 cameras[i].R.convertTo(tmp, CV_32F);
325 cameras[i].R = tmp;
326 }
327 }
328
329
calcError(Mat & err)330 void BundleAdjusterReproj::calcError(Mat &err)
331 {
332 err.create(total_num_matches_ * 2, 1, CV_64F);
333
334 int match_idx = 0;
335 for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
336 {
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);
347
348 double R1[9];
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_);
355
356 double R2[9];
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_);
362
363 const ImageFeatures& features1 = features_[i];
364 const ImageFeatures& features2 = features_[j];
365 const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
366
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;
370
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;
374
375 Mat_<double> H = K2 * R2_.inv() * R1_ * K1.inv();
376
377 for (size_t k = 0; k < matches_info.matches.size(); ++k)
378 {
379 if (!matches_info.inliers_mask[k])
380 continue;
381
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);
388
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;
391 match_idx++;
392 }
393 }
394 }
395
396
calcJacobian(Mat & jac)397 void BundleAdjusterReproj::calcJacobian(Mat &jac)
398 {
399 jac.create(total_num_matches_ * 2, num_images_ * 7, CV_64F);
400 jac.setTo(0);
401
402 double val;
403 const double step = 1e-4;
404
405 for (int i = 0; i < num_images_; ++i)
406 {
407 if (refinement_mask_.at<uchar>(0, 0))
408 {
409 val = cam_params_.at<double>(i * 7, 0);
410 cam_params_.at<double>(i * 7, 0) = val - step;
411 calcError(err1_);
412 cam_params_.at<double>(i * 7, 0) = val + step;
413 calcError(err2_);
414 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7));
415 cam_params_.at<double>(i * 7, 0) = val;
416 }
417 if (refinement_mask_.at<uchar>(0, 2))
418 {
419 val = cam_params_.at<double>(i * 7 + 1, 0);
420 cam_params_.at<double>(i * 7 + 1, 0) = val - step;
421 calcError(err1_);
422 cam_params_.at<double>(i * 7 + 1, 0) = val + step;
423 calcError(err2_);
424 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 1));
425 cam_params_.at<double>(i * 7 + 1, 0) = val;
426 }
427 if (refinement_mask_.at<uchar>(1, 2))
428 {
429 val = cam_params_.at<double>(i * 7 + 2, 0);
430 cam_params_.at<double>(i * 7 + 2, 0) = val - step;
431 calcError(err1_);
432 cam_params_.at<double>(i * 7 + 2, 0) = val + step;
433 calcError(err2_);
434 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 2));
435 cam_params_.at<double>(i * 7 + 2, 0) = val;
436 }
437 if (refinement_mask_.at<uchar>(1, 1))
438 {
439 val = cam_params_.at<double>(i * 7 + 3, 0);
440 cam_params_.at<double>(i * 7 + 3, 0) = val - step;
441 calcError(err1_);
442 cam_params_.at<double>(i * 7 + 3, 0) = val + step;
443 calcError(err2_);
444 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + 3));
445 cam_params_.at<double>(i * 7 + 3, 0) = val;
446 }
447 for (int j = 4; j < 7; ++j)
448 {
449 val = cam_params_.at<double>(i * 7 + j, 0);
450 cam_params_.at<double>(i * 7 + j, 0) = val - step;
451 calcError(err1_);
452 cam_params_.at<double>(i * 7 + j, 0) = val + step;
453 calcError(err2_);
454 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 7 + j));
455 cam_params_.at<double>(i * 7 + j, 0) = val;
456 }
457 }
458 }
459
460
461 //////////////////////////////////////////////////////////////////////////////
462
setUpInitialCameraParams(const std::vector<CameraParams> & cameras)463 void BundleAdjusterRay::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
464 {
465 cam_params_.create(num_images_ * 4, 1, CV_64F);
466 SVD svd;
467 for (int i = 0; i < num_images_; ++i)
468 {
469 cam_params_.at<double>(i * 4, 0) = cameras[i].focal;
470
471 svd(cameras[i].R, SVD::FULL_UV);
472 Mat R = svd.u * svd.vt;
473 if (determinant(R) < 0)
474 R *= -1;
475
476 Mat rvec;
477 Rodrigues(R, rvec);
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);
482 }
483 }
484
485
obtainRefinedCameraParams(std::vector<CameraParams> & cameras) const486 void BundleAdjusterRay::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
487 {
488 for (int i = 0; i < num_images_; ++i)
489 {
490 cameras[i].focal = cam_params_.at<double>(i * 4, 0);
491
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);
497
498 Mat tmp;
499 cameras[i].R.convertTo(tmp, CV_32F);
500 cameras[i].R = tmp;
501 }
502 }
503
504
calcError(Mat & err)505 void BundleAdjusterRay::calcError(Mat &err)
506 {
507 err.create(total_num_matches_ * 3, 1, CV_64F);
508
509 int match_idx = 0;
510 for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
511 {
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);
516
517 double R1[9];
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_);
524
525 double R2[9];
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_);
531
532 const ImageFeatures& features1 = features_[i];
533 const ImageFeatures& features2 = features_[j];
534 const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
535
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;
539
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;
543
544 Mat_<double> H1 = R1_ * K1.inv();
545 Mat_<double> H2 = R2_ * K2.inv();
546
547 for (size_t k = 0; k < matches_info.matches.size(); ++k)
548 {
549 if (!matches_info.inliers_mask[k])
550 continue;
551
552 const DMatch& m = matches_info.matches[k];
553
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;
560
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;
567
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);
572
573 match_idx++;
574 }
575 }
576 }
577
578
calcJacobian(Mat & jac)579 void BundleAdjusterRay::calcJacobian(Mat &jac)
580 {
581 jac.create(total_num_matches_ * 3, num_images_ * 4, CV_64F);
582
583 double val;
584 const double step = 1e-3;
585
586 for (int i = 0; i < num_images_; ++i)
587 {
588 for (int j = 0; j < 4; ++j)
589 {
590 val = cam_params_.at<double>(i * 4 + j, 0);
591 cam_params_.at<double>(i * 4 + j, 0) = val - step;
592 calcError(err1_);
593 cam_params_.at<double>(i * 4 + j, 0) = val + step;
594 calcError(err2_);
595 calcDeriv(err1_, err2_, 2 * step, jac.col(i * 4 + j));
596 cam_params_.at<double>(i * 4 + j, 0) = val;
597 }
598 }
599 }
600
601
602 //////////////////////////////////////////////////////////////////////////////
603
waveCorrect(std::vector<Mat> & rmats,WaveCorrectKind kind)604 void waveCorrect(std::vector<Mat> &rmats, WaveCorrectKind kind)
605 {
606 LOGLN("Wave correcting...");
607 #if ENABLE_LOG
608 int64 t = getTickCount();
609 #endif
610 if (rmats.size() <= 1)
611 {
612 LOGLN("Wave correcting, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
613 return;
614 }
615
616 Mat moment = Mat::zeros(3, 3, CV_32F);
617 for (size_t i = 0; i < rmats.size(); ++i)
618 {
619 Mat col = rmats[i].col(0);
620 moment += col * col.t();
621 }
622 Mat eigen_vals, eigen_vecs;
623 eigen(moment, eigen_vals, eigen_vecs);
624
625 Mat rg1;
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();
630 else
631 CV_Error(CV_StsBadArg, "unsupported kind of wave correction");
632
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);
638
639 if( rg0_norm <= DBL_MIN )
640 {
641 return;
642 }
643
644 rg0 /= rg0_norm;
645
646 Mat rg2 = rg0.cross(rg1);
647
648 double conf = 0;
649 if (kind == WAVE_CORRECT_HORIZ)
650 {
651 for (size_t i = 0; i < rmats.size(); ++i)
652 conf += rg0.dot(rmats[i].col(0));
653 if (conf < 0)
654 {
655 rg0 *= -1;
656 rg1 *= -1;
657 }
658 }
659 else if (kind == WAVE_CORRECT_VERT)
660 {
661 for (size_t i = 0; i < rmats.size(); ++i)
662 conf -= rg1.dot(rmats[i].col(0));
663 if (conf < 0)
664 {
665 rg0 *= -1;
666 rg1 *= -1;
667 }
668 }
669
670 Mat R = Mat::zeros(3, 3, CV_32F);
671 Mat tmp = R.row(0);
672 Mat(rg0.t()).copyTo(tmp);
673 tmp = R.row(1);
674 Mat(rg1.t()).copyTo(tmp);
675 tmp = R.row(2);
676 Mat(rg2.t()).copyTo(tmp);
677
678 for (size_t i = 0; i < rmats.size(); ++i)
679 rmats[i] = R * rmats[i];
680
681 LOGLN("Wave correcting, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
682 }
683
684
685 //////////////////////////////////////////////////////////////////////////////
686
matchesGraphAsString(std::vector<String> & pathes,std::vector<MatchesInfo> & pairwise_matches,float conf_threshold)687 String matchesGraphAsString(std::vector<String> &pathes, std::vector<MatchesInfo> &pairwise_matches,
688 float conf_threshold)
689 {
690 std::stringstream str;
691 str << "graph matches_graph{\n";
692
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);
696
697 for (int i = 0; i < num_images; ++i)
698 {
699 for (int j = 0; j < num_images; ++j)
700 {
701 if (pairwise_matches[i*num_images + j].confidence < conf_threshold)
702 continue;
703 int comp1 = comps.findSetByElem(i);
704 int comp2 = comps.findSetByElem(j);
705 if (comp1 != comp2)
706 {
707 comps.mergeSets(comp1, comp2);
708 span_tree_edges.insert(std::make_pair(i, j));
709 }
710 }
711 }
712
713 for (std::set<std::pair<int,int> >::const_iterator itr = span_tree_edges.begin();
714 itr != span_tree_edges.end(); ++itr)
715 {
716 std::pair<int,int> edge = *itr;
717 if (span_tree_edges.find(edge) != span_tree_edges.end())
718 {
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);
723
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);
728
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";
734 }
735 }
736
737 for (size_t i = 0; i < comps.size.size(); ++i)
738 {
739 if (comps.size[comps.findSetByElem((int)i)] == 1)
740 {
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";
746 }
747 }
748
749 str << "}";
750 return str.str().c_str();
751 }
752
leaveBiggestComponent(std::vector<ImageFeatures> & features,std::vector<MatchesInfo> & pairwise_matches,float conf_threshold)753 std::vector<int> leaveBiggestComponent(std::vector<ImageFeatures> &features, std::vector<MatchesInfo> &pairwise_matches,
754 float conf_threshold)
755 {
756 const int num_images = static_cast<int>(features.size());
757
758 DisjointSets comps(num_images);
759 for (int i = 0; i < num_images; ++i)
760 {
761 for (int j = 0; j < num_images; ++j)
762 {
763 if (pairwise_matches[i*num_images + j].confidence < conf_threshold)
764 continue;
765 int comp1 = comps.findSetByElem(i);
766 int comp2 = comps.findSetByElem(j);
767 if (comp1 != comp2)
768 comps.mergeSets(comp1, comp2);
769 }
770 }
771
772 int max_comp = static_cast<int>(std::max_element(comps.size.begin(), comps.size.end()) - comps.size.begin());
773
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);
779 else
780 indices_removed.push_back(i);
781
782 std::vector<ImageFeatures> features_subset;
783 std::vector<MatchesInfo> pairwise_matches_subset;
784 for (size_t i = 0; i < indices.size(); ++i)
785 {
786 features_subset.push_back(features[indices[i]]);
787 for (size_t j = 0; j < indices.size(); ++j)
788 {
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);
792 }
793 }
794
795 if (static_cast<int>(features_subset.size()) == num_images)
796 return indices;
797
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);
802 LOGLN(").");
803 LOGLN("Try to decrease the match confidence threshold and/or check if you're stitching duplicates.");
804
805 features = features_subset;
806 pairwise_matches = pairwise_matches_subset;
807
808 return indices;
809 }
810
811
findMaxSpanningTree(int num_images,const std::vector<MatchesInfo> & pairwise_matches,Graph & span_tree,std::vector<int> & centers)812 void findMaxSpanningTree(int num_images, const std::vector<MatchesInfo> &pairwise_matches,
813 Graph &span_tree, std::vector<int> ¢ers)
814 {
815 Graph graph(num_images);
816 std::vector<GraphEdge> edges;
817
818 // Construct images graph and remember its edges
819 for (int i = 0; i < num_images; ++i)
820 {
821 for (int j = 0; j < num_images; ++j)
822 {
823 if (pairwise_matches[i * num_images + j].H.empty())
824 continue;
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));
828 }
829 }
830
831 DisjointSets comps(num_images);
832 span_tree.create(num_images);
833 std::vector<int> span_tree_powers(num_images, 0);
834
835 // Find maximum spanning tree
836 sort(edges.begin(), edges.end(), std::greater<GraphEdge>());
837 for (size_t i = 0; i < edges.size(); ++i)
838 {
839 int comp1 = comps.findSetByElem(edges[i].from);
840 int comp2 = comps.findSetByElem(edges[i].to);
841 if (comp1 != comp2)
842 {
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]++;
848 }
849 }
850
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);
856
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)
861 {
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]);
866 }
867
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];
873
874 // Find spanning tree centers
875 centers.clear();
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);
880 }
881
882 } // namespace detail
883 } // namespace cv
884