00001 #include "vpgl_rational_adjust_multipt.h"
00002
00003
00004 #include <vcl_cmath.h>
00005 #include <vcl_cassert.h>
00006 #include <vgl/vgl_point_3d.h>
00007 #include <vnl/vnl_numeric_traits.h>
00008 #include <vnl/algo/vnl_levenberg_marquardt.h>
00009 #include <vpgl/algo/vpgl_backproject.h>
00010 #include <vpgl/algo/vpgl_ray_intersect.h>
00011 #include <vpgl/algo/vpgl_rational_adjust_onept.h>
00012
00013 #include <vcl_limits.h>
00014
00015 double compute_projection_error(vcl_vector<vpgl_rational_camera<double> > const& cams,
00016 vcl_vector<vgl_point_2d<double> > const& corrs, vgl_point_3d<double>& intersection)
00017 {
00018 vcl_vector<vpgl_rational_camera<double> >::const_iterator cit = cams.begin();
00019 vcl_vector<vgl_point_2d<double> >::const_iterator rit = corrs.begin();
00020 double error = 0.0;
00021 for (; cit!=cams.end() && rit!=corrs.end(); ++cit, ++rit)
00022 {
00023 vgl_point_2d<double> uvp = (*cit).project(intersection);
00024 vgl_point_2d<double> uv = *rit;
00025 double err = vcl_sqrt(vcl_pow(uv.x()-uvp.x(), 2.0) + vcl_pow(uv.y()-uvp.y(), 2));
00026 error += err;
00027 }
00028 return error;
00029 }
00030
00031 double error_corr(vpgl_rational_camera<double> const& cam, vgl_point_2d<double> const& corr, vgl_point_3d<double> const& intersection)
00032 {
00033 vgl_point_2d<double> uvp = cam.project(intersection);
00034 return vcl_sqrt(vcl_pow(corr.x()-uvp.x(), 2.0) + vcl_pow(corr.y()-uvp.y(), 2));
00035 }
00036
00037
00038 double re_projection_error(vcl_vector<vpgl_rational_camera<double> > const& cams,
00039 vcl_vector<vcl_vector<vgl_point_2d<double> > > const& corrs,
00040 vcl_vector<vgl_point_3d<double> > const& intersections,
00041 vcl_vector<vgl_point_3d<double> >& finals)
00042 {
00043 double error = 100000.0;
00044
00045 finals.clear();
00046 for (unsigned int i = 0; i < corrs.size(); ++i) {
00047 vgl_point_3d<double> final;
00048 if (!vpgl_rational_adjust_onept::refine_intersection_pt(cams, corrs[i],intersections[i], final))
00049 return error;
00050 finals.push_back(final);
00051 }
00052
00053 error = 0;
00054 for (unsigned int i = 0; i < corrs.size(); ++i) {
00055 error += compute_projection_error(cams, corrs[i], finals[i]);
00056 }
00057 return error;
00058 }
00059
00060
00061 void re_projection_error(vcl_vector<vpgl_rational_camera<double> > const& cams,
00062 vcl_vector<vcl_vector<vgl_point_2d<double> > > const& corrs,
00063 vcl_vector<vgl_point_3d<double> > const& intersections,
00064 vcl_vector<vgl_point_3d<double> >& finals,
00065 vnl_vector<double>& errors)
00066 {
00067 double error = 100000.0;
00068 errors.fill(error);
00069
00070 finals.clear();
00071 for (unsigned int i = 0; i < corrs.size(); ++i) {
00072 vgl_point_3d<double> final;
00073 if (!vpgl_rational_adjust_onept::refine_intersection_pt(cams, corrs[i],intersections[i], final))
00074 return;
00075 finals.push_back(final);
00076 }
00077
00078 unsigned k = 0;
00079
00080 for (unsigned int i = 0; i < corrs.size(); ++i) {
00081 for (unsigned int j = 0; j < cams.size(); ++j) {
00082 errors[k] = error_corr(cams[j], corrs[i][j], intersections[i]);
00083 k++;
00084 }
00085 }
00086 }
00087
00088
00089 void print_perm(vcl_vector<unsigned>& params_indices)
00090 {
00091 for (unsigned int i = 0; i < params_indices.size(); ++i)
00092 vcl_cout << params_indices[i] << ' ';
00093 vcl_cout << vcl_endl;
00094 }
00095
00096
00097 bool increment_perm(vcl_vector<unsigned>& params_indices, unsigned size)
00098 {
00099 if (!params_indices.size())
00100 return true;
00101
00102 params_indices[params_indices.size()-1] += 1;
00103 if (params_indices[params_indices.size()-1] == size) {
00104 params_indices[params_indices.size()-1] = 0;
00105
00106 if (params_indices.size() < 2)
00107 return true;
00108
00109 int current_i = (int)params_indices.size()-2;
00110 while (current_i >= 0) {
00111 params_indices[current_i] += 1;
00112 if (params_indices[current_i] < size)
00113 break;
00114 if (current_i == 0)
00115 return true;
00116 params_indices[current_i] = 0;
00117 current_i -= 1;
00118 }
00119 }
00120 return false;
00121 }
00122
00123
00124 bool vpgl_rational_adjust_multiple_pts::
00125 adjust(vcl_vector<vpgl_rational_camera<double> > const& cams,
00126 vcl_vector<vcl_vector< vgl_point_2d<double> > > const& corrs,
00127 double radius, int n,
00128 vcl_vector<vgl_vector_2d<double> >& cam_translations,
00129 vcl_vector<vgl_point_3d<double> >& intersections)
00130 {
00131 cam_translations.clear();
00132 intersections.clear();
00133 intersections.resize(corrs.size());
00134 if (!cams.size() || !corrs.size() || cams.size() != corrs.size())
00135 return false;
00136 if (!corrs[0].size())
00137 return false;
00138 unsigned int cnt_corrs_for_each_cam = (unsigned)corrs[0].size();
00139 for (unsigned int i = 1; i < corrs.size(); ++i)
00140 if (corrs[i].size() != cnt_corrs_for_each_cam)
00141 return false;
00142
00143
00144 vcl_vector<vgl_point_2d<double> > temp(cams.size());
00145 vcl_vector<vcl_vector<vgl_point_2d<double> > > corrs_reformatted(cnt_corrs_for_each_cam, temp);
00146
00147 for (unsigned int i = 0; i < cnt_corrs_for_each_cam; ++i) {
00148 for (unsigned int j = 0; j < corrs.size(); ++j)
00149 corrs_reformatted[i][j] = corrs[j][i];
00150 }
00151
00152 vcl_vector<vgl_point_3d<double> > intersections_initial;
00153 for (unsigned int i = 0; i < corrs_reformatted.size(); ++i) {
00154 vgl_point_3d<double> pt;
00155 if (!vpgl_rational_adjust_onept::find_intersection_point(cams, corrs_reformatted[i], pt))
00156 return false;
00157 intersections_initial.push_back(pt);
00158 }
00159
00160
00161 int param_cnt = 2*(int)cams.size();
00162 double increment = radius/n;
00163 vcl_vector<double> param_values;
00164 param_values.push_back(0.0);
00165 for (int i = 1; i <= n; ++i) {
00166 param_values.push_back(i*increment);
00167 param_values.push_back(-i*increment);
00168 }
00169 for (unsigned int i = 0; i < param_values.size(); ++i)
00170 vcl_cout << param_values[i] << ' ';
00171 vcl_cout << '\n';
00172
00173
00174 vcl_vector<unsigned> params_indices(param_cnt, 0);
00175 int cnt = (int)vcl_pow((float)param_cnt, (float)param_values.size());
00176 vcl_cout << "will try: " << cnt << " param combinations: ";
00177 vcl_cout.flush();
00178 bool done = false;
00179 double big_value = 10000000.0;
00180 double min_error = big_value;
00181 vcl_vector<unsigned> params_indices_best(params_indices);
00182 while (!done) {
00183 vcl_cout << '.';
00184 vcl_cout.flush();
00185 vcl_vector<vpgl_rational_camera<double> > current_cams(cams);
00186
00187 for (unsigned int i = 0; i < current_cams.size(); ++i) {
00188 double u_off,v_off;
00189 current_cams[i].image_offset(u_off, v_off);
00190 current_cams[i].set_image_offset(u_off + param_values[params_indices[i*2]], v_off + param_values[params_indices[i*2+1]]);
00191 }
00192
00193
00194 vcl_vector<vgl_point_3d<double> > finals;
00195 double err = re_projection_error(current_cams, corrs_reformatted, intersections_initial, finals);
00196
00197 if (err < min_error) {
00198 min_error = err;
00199 params_indices_best = params_indices;
00200 intersections = finals;
00201 }
00202 done = increment_perm(params_indices, (unsigned)param_values.size());
00203 }
00204 if (min_error < big_value) {
00205 vcl_cout << " done! found global min! min error: " << min_error << '\n';
00206 vcl_vector<vpgl_rational_camera<double> > current_cams(cams);
00207
00208 vcl_cout << "translations for each camera:" << vcl_endl;
00209 for (unsigned int i = 0; i < current_cams.size(); ++i) {
00210 vgl_vector_2d<double> tr(param_values[params_indices_best[i*2]], param_values[params_indices_best[i*2+1]]);
00211 vcl_cout << tr << vcl_endl;
00212 cam_translations.push_back(tr);
00213 double u_off,v_off;
00214 current_cams[i].image_offset(u_off,v_off);
00215 current_cams[i].set_image_offset(u_off + param_values[params_indices_best[i*2]], v_off + param_values[params_indices_best[i*2+1]]);
00216 }
00217 }
00218 else {
00219 vcl_cout << " done! no global min!\n";
00220 return false;
00221 }
00222 return true;
00223 }
00224
00225 vpgl_cam_trans_search_lsqr::
00226 vpgl_cam_trans_search_lsqr(vcl_vector<vpgl_rational_camera<double> > const& cams,
00227 vcl_vector< vcl_vector<vgl_point_2d<double> > > const& image_pts,
00228 vcl_vector< vgl_point_3d<double> > const& initial_pts)
00229 : vnl_least_squares_function(2*(unsigned)cams.size(), (unsigned)(cams.size()*image_pts.size()), vnl_least_squares_function::no_gradient),
00230 initial_pts_(initial_pts),
00231 cameras_(cams),
00232 corrs_(image_pts)
00233 {}
00234
00235 void vpgl_cam_trans_search_lsqr::f(vnl_vector<double> const& translation,
00236 vnl_vector<double>& projection_errors)
00237 {
00238
00239 vcl_vector<vpgl_rational_camera<double> > current_cams(cameras_);
00240
00241 for (unsigned int i = 0; i < current_cams.size(); ++i) {
00242 double u_off,v_off;
00243 current_cams[i].image_offset(u_off, v_off);
00244 current_cams[i].set_image_offset(u_off + translation[i*2], v_off + translation[i*2+1]);
00245 }
00246
00247
00248 re_projection_error(current_cams, corrs_, initial_pts_, finals_, projection_errors);
00249 }
00250
00251 void vpgl_cam_trans_search_lsqr::get_finals(vcl_vector<vgl_point_3d<double> >& finals)
00252 {
00253 finals = finals_;
00254 }
00255
00256
00257 bool vpgl_rational_adjust_multiple_pts::
00258 adjust_lev_marq(vcl_vector<vpgl_rational_camera<double> > const& cams,
00259 vcl_vector<vcl_vector< vgl_point_2d<double> > > const& corrs,
00260 vcl_vector<vgl_vector_2d<double> >& cam_translations,
00261 vcl_vector<vgl_point_3d<double> >& intersections)
00262 {
00263 cam_translations.clear();
00264 intersections.clear();
00265 intersections.resize(corrs.size());
00266 if (!cams.size() || !corrs.size() || cams.size() != corrs.size())
00267 return false;
00268 if (!corrs[0].size())
00269 return false;
00270 unsigned int cnt_corrs_for_each_cam = (unsigned)corrs[0].size();
00271 for (unsigned int i = 1; i < corrs.size(); ++i)
00272 if (corrs[i].size() != cnt_corrs_for_each_cam)
00273 return false;
00274
00275
00276 vcl_vector<vgl_point_2d<double> > temp(cams.size());
00277 vcl_vector<vcl_vector<vgl_point_2d<double> > > corrs_reformatted(cnt_corrs_for_each_cam, temp);
00278
00279 for (unsigned int i = 0; i < cnt_corrs_for_each_cam; ++i) {
00280 for (unsigned int j = 0; j < corrs.size(); ++j)
00281 corrs_reformatted[i][j] = corrs[j][i];
00282 }
00283
00284 vcl_vector<vgl_point_3d<double> > intersections_initial;
00285 for (unsigned int i = 0; i < corrs_reformatted.size(); ++i) {
00286 vgl_point_3d<double> pt;
00287 if (!vpgl_rational_adjust_onept::find_intersection_point(cams, corrs_reformatted[i], pt))
00288 return false;
00289 intersections_initial.push_back(pt);
00290 }
00291
00292 for (unsigned int i = 0; i < corrs_reformatted.size(); ++i) {
00293 vgl_point_3d<double> final;
00294 if (!vpgl_rational_adjust_onept::refine_intersection_pt(cams, corrs_reformatted[i],intersections_initial[i], final))
00295 return false;
00296 intersections_initial[i] = final;
00297 }
00298 for (unsigned int i = 0; i < intersections_initial.size(); ++i)
00299 vcl_cout << "before adjustment initial 3D intersection point: " << intersections_initial[i] << vcl_endl;
00300
00301
00302 vpgl_cam_trans_search_lsqr transsf(cams, corrs_reformatted, intersections_initial);
00303 vnl_levenberg_marquardt levmarq(transsf);
00304 levmarq.set_verbose(true);
00305
00306
00307 levmarq.set_x_tolerance(1e-10);
00308
00309 levmarq.set_epsilon_function(0.01);
00310
00311
00312 levmarq.set_f_tolerance(1e-15);
00313
00314 levmarq.set_max_function_evals(10000);
00315 vnl_vector<double> translations(2*(unsigned)cams.size(), 0.0);
00316 vcl_cout << "Minimization x epsilon: " << levmarq.get_f_tolerance() << vcl_endl;
00317
00318
00319 levmarq.minimize(translations);
00320 levmarq.diagnose_outcome();
00321 transsf.get_finals(intersections);
00322 vcl_cout << "final translations:" << vcl_endl;
00323 for (unsigned int i = 0; i < cams.size(); ++i) {
00324 vgl_vector_2d<double> trans(translations[2*i], translations[2*i+1]);
00325 cam_translations.push_back(trans);
00326 vcl_cout << trans << '\n';
00327 }
00328 return true;
00329 }