PICCANTE  0.4
The hottest HDR imaging library!
homography_matrix.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_COMPUTER_VISION_HOMOGRAPHY_HPP
19 #define PIC_COMPUTER_VISION_HOMOGRAPHY_HPP
20 
21 #include <vector>
22 #include <random>
23 #include <stdlib.h>
24 
25 #include "../base.hpp"
26 
27 #include "../util/math.hpp"
28 #include "../util/eigen_util.hpp"
29 
30 #ifndef PIC_DISABLE_EIGEN
31 
32 #ifndef PIC_EIGEN_NOT_BUNDLED
33  #include "../externals/Eigen/Dense"
34  #include "../externals/Eigen/SVD"
35  #include "../externals/Eigen/Geometry"
36 #else
37  #include <Eigen/Dense>
38  #include <Eigen/SVD>
39  #include <Eigen/Geometry>
40 #endif
41 
42 #endif
43 
44 #include "../computer_vision/nelder_mead_opt_homography.hpp"
45 
46 namespace pic {
47 
48 #ifndef PIC_DISABLE_EIGEN
49 
56 PIC_INLINE Eigen::Matrix3d estimateHomography(std::vector< Eigen::Vector2f > &points0,
57  std::vector< Eigen::Vector2f > &points1)
58 {
59  Eigen::Matrix3d H;
60 
61  if((points0.size() != points1.size()) || (points0.size() < 4)) {
62  H.setZero();
63  return H;
64  }
65 
66  Eigen::Vector3f transform_0 = ComputeNormalizationTransform(points0);
67  Eigen::Vector3f transform_1 = ComputeNormalizationTransform(points1);
68 
69  Eigen::Matrix3d mat_0 = getShiftScaleMatrix(transform_0);
70  Eigen::Matrix3d mat_1 = getShiftScaleMatrix(transform_1);
71 
72  int n = int(points0.size());
73  Eigen::MatrixXd A(n * 2, 9);
74 
75  //set up the linear system
76  for(int i = 0; i < n; i++) {
77  //transform coordinates for increasing stability of the system
78  Eigen::Vector2f p0 = points0[i];
79  Eigen::Vector2f p1 = points1[i];
80 
81  p0[0] = (p0[0] - transform_0[0]) / transform_0[2];
82  p0[1] = (p0[1] - transform_0[1]) / transform_0[2];
83 
84  p1[0] = (p1[0] - transform_1[0]) / transform_1[2];
85  p1[1] = (p1[1] - transform_1[1]) / transform_1[2];
86 
87  int j = i * 2;
88  A(j, 0) = 0.0;
89  A(j, 1) = 0.0;
90  A(j, 2) = 0.0;
91  A(j, 3) = p0[0];
92  A(j, 4) = p0[1];
93  A(j, 5) = 1.0;
94  A(j, 6) = -p1[1] * p0[0];
95  A(j, 7) = -p1[1] * p0[1];
96  A(j, 8) = -p1[1];
97 
98  j++;
99 
100  A(j, 0) = p0[0];
101  A(j, 1) = p0[1];
102  A(j, 2) = 1.0;
103  A(j, 3) = 0.0;
104  A(j, 4) = 0.0;
105  A(j, 5) = 0.0;
106  A(j, 6) = -p1[0] * p0[0];
107  A(j, 7) = -p1[0] * p0[1];
108  A(j, 8) = -p1[0];
109  }
110 
111  //solve the linear system
112  Eigen::JacobiSVD< Eigen::MatrixXd > svd(A, Eigen::ComputeFullV);
113  Eigen::MatrixXd V = svd.matrixV();
114 
115  n = int(V.cols()) - 1;
116 
117  //assign and transpose
118  H(0, 0) = V(0, n);
119  H(0, 1) = V(1, n);
120  H(0, 2) = V(2, n);
121 
122  H(1, 0) = V(3, n);
123  H(1, 1) = V(4, n);
124  H(1, 2) = V(5, n);
125 
126  H(2, 0) = V(6, n);
127  H(2, 1) = V(7, n);
128  H(2, 2) = V(8, n);
129 
130  H = mat_1.inverse() * H * mat_0;
131  return H / H(2, 2);
132 }
133 
142 PIC_INLINE Eigen::Matrix3d estimateHomographyRansac(std::vector< Eigen::Vector2f > &points0,
143  std::vector< Eigen::Vector2f > &points1,
144  std::vector< unsigned int > &inliers,
145  unsigned int maxIterations = 100,
146  double threshold = 4.0,
147  unsigned int seed = 1)
148 {
149  if(points0.size() < 5) {
150  return estimateHomography(points0, points1);
151  }
152 
153  Eigen::Matrix3d H;
154  int nSubSet = 4;
155 
156  std::mt19937 m(seed);
157 
158  unsigned int n = int(points0.size());
159 
160  unsigned int *subSet = new unsigned int [nSubSet];
161 
162  inliers.clear();
163 
164  for(unsigned int i = 0; i < maxIterations; i++) {
165 
166  getRandomPermutation(m, subSet, nSubSet, n);
167 
168  std::vector< Eigen::Vector2f > sub_points0;
169  std::vector< Eigen::Vector2f > sub_points1;
170 
171  for(int j = 0; j < nSubSet; j++) {
172  sub_points0.push_back(points0[subSet[j]]);
173  sub_points1.push_back(points1[subSet[j]]);
174  }
175 
176  Eigen::Matrix3d tmpH = estimateHomography(sub_points0, sub_points1);
177 
178  //is it a good one?
179  std::vector< unsigned int > tmp_inliers;
180 
181  for(unsigned int j = 0; j < n; j++) {
182  Eigen::Vector3d point_hom = Eigen::Vector3d(points0[j][0], points0[j][1], 1.0);
183  Eigen::Vector3d pp = tmpH * point_hom;
184  pp /= pp[2];
185 
186  double dx = points1[j][0] - pp[0];
187  double dy = points1[j][1] - pp[1];
188  double squared_diff = (dx * dx) + (dy * dy);
189 
190  if(squared_diff < threshold) {
191  tmp_inliers.push_back(j);
192  }
193  }
194 
195  //get the inliers
196  if(tmp_inliers.size() > inliers.size()) {
197  H = tmpH;
198  inliers.clear();
199  inliers.assign(tmp_inliers.begin(), tmp_inliers.end());
200  }
201  }
202 
203  //improve estimate with inliers only
204  if(inliers.size() > 3) {
205  #ifdef PIC_DEBUG
206  printf("Better estimate using inliers only.\n");
207  #endif
208 
209  std::vector< Eigen::Vector2f > sub_points0;
210  std::vector< Eigen::Vector2f > sub_points1;
211 
212  for(unsigned int i = 0; i < inliers.size(); i++) {
213  sub_points0.push_back(points0[inliers[i]]);
214  sub_points1.push_back(points1[inliers[i]]);
215  }
216 
217  H = estimateHomography(sub_points0, sub_points1);
218  }
219 
220  return H;
221 }
222 
232  std::vector< Eigen::Vector2f > &points0,
233  std::vector< Eigen::Vector2f > &points1,
234  std::vector< unsigned int > &inliers,
235  unsigned int maxIterationsRansac = 10000,
236  double thresholdRansac = 2.5,
237  unsigned int seedRansac = 1,
238  unsigned int maxIterationsNonLinear = 10000,
239  float thresholdNonLinear = 1e-5f
240  ) {
241 
242  Eigen::Matrix3d H = estimateHomographyRansac(points0, points1, inliers,
243  maxIterationsRansac, thresholdRansac,
244  seedRansac);
245 
246  NelderMeadOptHomography nmoh(points0, points1, inliers);
247  float *H_array = getLinearArrayFromMatrix(H);
248  nmoh.run(H_array, 8, thresholdNonLinear, maxIterationsNonLinear, H_array);
249  H = getMatrix3dFromLinearArray(H_array);
250  return H;
251 }
252 
253 #endif // PIC_DISABLE_EIGEN
254 
255 } // end namespace pic
256 
257 #endif // PIC_COMPUTER_VISION_HOMOGRAPHY_HPP
PIC_INLINE Eigen::Matrix3d estimateHomography(std::vector< Eigen::Vector2f > &points0, std::vector< Eigen::Vector2f > &points1)
estimateHomography estimates an homography matrix H between image 1 to image 2
Definition: homography_matrix.hpp:56
float * run(float *x_start, unsigned int n, float epsilon=1e-4f, int max_iterations=1000, float *x=NULL)
run
Definition: nelder_mead_opt_homography.hpp:115
PIC_INLINE Eigen::Matrix3d getShiftScaleMatrix(Eigen::Vector3f &info)
getShiftScaleMatrix computes a shifting and scaling matrix
Definition: eigen_util.hpp:297
PIC_INLINE float * getLinearArrayFromMatrix(Eigen::Matrix3d &mat)
getLinearArray
Definition: eigen_util.hpp:404
PIC_INLINE Eigen::Matrix3d estimateHomographyWithNonLinearRefinement(std::vector< Eigen::Vector2f > &points0, std::vector< Eigen::Vector2f > &points1, std::vector< unsigned int > &inliers, unsigned int maxIterationsRansac=10000, double thresholdRansac=2.5, unsigned int seedRansac=1, unsigned int maxIterationsNonLinear=10000, float thresholdNonLinear=1e-5f)
estimateHomographyRansac computes the homography such that: points1 = H * points0 ...
Definition: homography_matrix.hpp:231
PIC_INLINE Eigen::Matrix3d estimateHomographyRansac(std::vector< Eigen::Vector2f > &points0, std::vector< Eigen::Vector2f > &points1, std::vector< unsigned int > &inliers, unsigned int maxIterations=100, double threshold=4.0, unsigned int seed=1)
estimateHomographyRansac computes the homography such that: points1 = H * points0 ...
Definition: homography_matrix.hpp:142
#define PIC_INLINE
Definition: base.hpp:33
Definition: bilateral_separation.hpp:25
PIC_INLINE Eigen::Vector3f ComputeNormalizationTransform(std::vector< Eigen::Vector2f > &points)
ComputeNormalizationTransform.
Definition: eigen_util.hpp:530
PIC_INLINE Eigen::Matrix3d getMatrix3dFromLinearArray(float *array)
getMatrix3dFromLinearArray
Definition: eigen_util.hpp:488
Definition: nelder_mead_opt_homography.hpp:36
PIC_INLINE void getRandomPermutation(std::mt19937 &m, unsigned int *perm, unsigned int nPerm, unsigned int n)
getRandomPermutation computes a random permutation.
Definition: math.hpp:434