• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &centers)
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