Blender  V2.93
intern/reconstruction.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 #include "intern/reconstruction.h"
22 #include "intern/tracks.h"
23 #include "intern/utildefines.h"
24 
25 #include "libmv/logging/logging.h"
33 
39 using libmv::Marker;
41 
47 using libmv::Tracks;
48 
51 
52  /* Used for per-track average error calculation after reconstruction */
55 
56  double error;
57  bool is_valid;
58 };
59 
60 namespace {
61 
62 class ReconstructUpdateCallback : public ProgressUpdateCallback {
63  public:
64  ReconstructUpdateCallback(
65  reconstruct_progress_update_cb progress_update_callback,
66  void* callback_customdata) {
67  progress_update_callback_ = progress_update_callback;
68  callback_customdata_ = callback_customdata;
69  }
70 
71  void invoke(double progress, const char* message) {
72  if (progress_update_callback_) {
73  progress_update_callback_(callback_customdata_, progress, message);
74  }
75  }
76 
77  protected:
78  reconstruct_progress_update_cb progress_update_callback_;
79  void* callback_customdata_;
80 };
81 
82 void libmv_solveRefineIntrinsics(
83  const Tracks& tracks,
84  const int refine_intrinsics,
85  const int bundle_constraints,
86  reconstruct_progress_update_cb progress_update_callback,
87  void* callback_customdata,
89  CameraIntrinsics* intrinsics) {
90  /* only a few combinations are supported but trust the caller/ */
91  int bundle_intrinsics = 0;
92 
93  if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
94  bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH;
95  }
96  if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
97  bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
98  }
99 
100 #define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \
101  do { \
102  if (refine_intrinsics & LIBMV_REFINE_##type##_DISTORTION_##coefficient) { \
103  bundle_intrinsics |= libmv::BUNDLE_##type##_##coefficient; \
104  } \
105  } while (0)
106 
107  SET_DISTORTION_FLAG_CHECKED(RADIAL, K1);
108  SET_DISTORTION_FLAG_CHECKED(RADIAL, K2);
109  SET_DISTORTION_FLAG_CHECKED(RADIAL, K3);
110  SET_DISTORTION_FLAG_CHECKED(RADIAL, K4);
111 
114 
115 #undef SET_DISTORTION_FLAG_CHECKED
116 
117  progress_update_callback(callback_customdata, 1.0, "Refining solution");
118 
120  bundle_intrinsics,
121  bundle_constraints,
123  intrinsics);
124 }
125 
126 void finishReconstruction(
127  const Tracks& tracks,
128  const CameraIntrinsics& camera_intrinsics,
129  libmv_Reconstruction* libmv_reconstruction,
130  reconstruct_progress_update_cb progress_update_callback,
131  void* callback_customdata) {
133  libmv_reconstruction->reconstruction;
134 
135  /* Reprojection error calculation. */
136  progress_update_callback(callback_customdata, 1.0, "Finishing solution");
137  libmv_reconstruction->tracks = tracks;
138  libmv_reconstruction->error =
139  EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
140 }
141 
142 bool selectTwoKeyframesBasedOnGRICAndVariance(
143  Tracks& tracks,
144  Tracks& normalized_tracks,
145  CameraIntrinsics& camera_intrinsics,
146  int& keyframe1,
147  int& keyframe2) {
148  libmv::vector<int> keyframes;
149 
150  /* Get list of all keyframe candidates first. */
152  normalized_tracks, camera_intrinsics, keyframes);
153 
154  if (keyframes.size() < 2) {
155  LG << "Not enough keyframes detected by GRIC";
156  return false;
157  } else if (keyframes.size() == 2) {
158  keyframe1 = keyframes[0];
159  keyframe2 = keyframes[1];
160  return true;
161  }
162 
163  /* Now choose two keyframes with minimal reprojection error after initial
164  * reconstruction choose keyframes with the least reprojection error after
165  * solving from two candidate keyframes.
166  *
167  * In fact, currently libmv returns single pair only, so this code will
168  * not actually run. But in the future this could change, so let's stay
169  * prepared.
170  */
171  int previous_keyframe = keyframes[0];
172  double best_error = std::numeric_limits<double>::max();
173  for (int i = 1; i < keyframes.size(); i++) {
175  int current_keyframe = keyframes[i];
176  libmv::vector<Marker> keyframe_markers =
177  normalized_tracks.MarkersForTracksInBothImages(previous_keyframe,
178  current_keyframe);
179 
180  Tracks keyframe_tracks(keyframe_markers);
181 
182  /* get a solution from two keyframes only */
183  EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
184  EuclideanBundle(keyframe_tracks, &reconstruction);
186 
187  double current_error =
188  EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
189 
190  LG << "Error between " << previous_keyframe << " and " << current_keyframe
191  << ": " << current_error;
192 
193  if (current_error < best_error) {
194  best_error = current_error;
195  keyframe1 = previous_keyframe;
196  keyframe2 = current_keyframe;
197  }
198 
199  previous_keyframe = current_keyframe;
200  }
201 
202  return true;
203 }
204 
205 Marker libmv_projectMarker(const EuclideanPoint& point,
206  const EuclideanCamera& camera,
207  const CameraIntrinsics& intrinsics) {
208  libmv::Vec3 projected = camera.R * point.X + camera.t;
209  projected /= projected(2);
210 
211  libmv::Marker reprojected_marker;
212  intrinsics.ApplyIntrinsics(
213  projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
214 
215  reprojected_marker.image = camera.image;
216  reprojected_marker.track = point.track;
217  return reprojected_marker;
218 }
219 
220 void libmv_getNormalizedTracks(const Tracks& tracks,
221  const CameraIntrinsics& camera_intrinsics,
222  Tracks* normalized_tracks) {
223  libmv::vector<Marker> markers = tracks.AllMarkers();
224  for (int i = 0; i < markers.size(); ++i) {
225  Marker& marker = markers[i];
226  camera_intrinsics.InvertIntrinsics(
227  marker.x, marker.y, &marker.x, &marker.y);
228  normalized_tracks->Insert(
229  marker.image, marker.track, marker.x, marker.y, marker.weight);
230  }
231 }
232 
233 } // namespace
234 
236  const libmv_Tracks* libmv_tracks,
237  const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
238  libmv_ReconstructionOptions* libmv_reconstruction_options,
239  reconstruct_progress_update_cb progress_update_callback,
240  void* callback_customdata) {
241  libmv_Reconstruction* libmv_reconstruction =
243 
244  Tracks& tracks = *((Tracks*)libmv_tracks);
246  libmv_reconstruction->reconstruction;
247 
248  ReconstructUpdateCallback update_callback =
249  ReconstructUpdateCallback(progress_update_callback, callback_customdata);
250 
251  /* Retrieve reconstruction options from C-API to libmv API. */
252  CameraIntrinsics* camera_intrinsics;
253  camera_intrinsics = libmv_reconstruction->intrinsics =
254  libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
255 
256  /* Invert the camera intrinsics/ */
257  Tracks normalized_tracks;
258  libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks);
259 
260  /* keyframe selection. */
261  int keyframe1 = libmv_reconstruction_options->keyframe1,
262  keyframe2 = libmv_reconstruction_options->keyframe2;
263 
264  if (libmv_reconstruction_options->select_keyframes) {
265  LG << "Using automatic keyframe selection";
266 
267  update_callback.invoke(0, "Selecting keyframes");
268 
269  if (selectTwoKeyframesBasedOnGRICAndVariance(tracks,
270  normalized_tracks,
271  *camera_intrinsics,
272  keyframe1,
273  keyframe2)) {
274  /* so keyframes in the interface would be updated */
275  libmv_reconstruction_options->keyframe1 = keyframe1;
276  libmv_reconstruction_options->keyframe2 = keyframe2;
277  }
278  }
279 
280  /* Actual reconstruction. */
281  LG << "frames to init from: " << keyframe1 << " " << keyframe2;
282 
283  libmv::vector<Marker> keyframe_markers =
284  normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
285 
286  LG << "number of markers for init: " << keyframe_markers.size();
287 
288  if (keyframe_markers.size() < 16) {
289  LG << "No enough markers to initialize from";
290  libmv_reconstruction->is_valid = false;
291  return libmv_reconstruction;
292  }
293 
294  update_callback.invoke(0, "Initial reconstruction");
295 
296  if (!EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction)) {
297  LG << "Failed to initialize reconstruction";
298  libmv_reconstruction->is_valid = false;
299  return libmv_reconstruction;
300  }
301 
302  EuclideanBundle(normalized_tracks, &reconstruction);
304  normalized_tracks, &reconstruction, &update_callback);
305 
306  /* Refinement. */
307  if (libmv_reconstruction_options->refine_intrinsics) {
308  libmv_solveRefineIntrinsics(tracks,
309  libmv_reconstruction_options->refine_intrinsics,
311  progress_update_callback,
312  callback_customdata,
314  camera_intrinsics);
315  }
316 
317  /* Set reconstruction scale to unity. */
319 
320  /* Finish reconstruction. */
321  finishReconstruction(tracks,
322  *camera_intrinsics,
323  libmv_reconstruction,
324  progress_update_callback,
325  callback_customdata);
326 
327  libmv_reconstruction->is_valid = true;
328  return (libmv_Reconstruction*)libmv_reconstruction;
329 }
330 
332  const libmv_Tracks* libmv_tracks,
333  const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
334  const libmv_ReconstructionOptions* libmv_reconstruction_options,
335  reconstruct_progress_update_cb progress_update_callback,
336  void* callback_customdata) {
337  libmv_Reconstruction* libmv_reconstruction =
339 
340  Tracks& tracks = *((Tracks*)libmv_tracks);
342  libmv_reconstruction->reconstruction;
343 
344  ReconstructUpdateCallback update_callback =
345  ReconstructUpdateCallback(progress_update_callback, callback_customdata);
346 
347  /* Retrieve reconstruction options from C-API to libmv API. */
348  CameraIntrinsics* camera_intrinsics;
349  camera_intrinsics = libmv_reconstruction->intrinsics =
350  libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
351 
352  /* Invert the camera intrinsics. */
353  Tracks normalized_tracks;
354  libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks);
355 
356  /* Actual reconstruction. */
357  ModalSolver(normalized_tracks, &reconstruction, &update_callback);
358 
359  PolynomialCameraIntrinsics empty_intrinsics;
360  EuclideanBundleCommonIntrinsics(normalized_tracks,
364  &empty_intrinsics);
365 
366  /* Refinement. */
367  if (libmv_reconstruction_options->refine_intrinsics) {
368  libmv_solveRefineIntrinsics(tracks,
369  libmv_reconstruction_options->refine_intrinsics,
371  progress_update_callback,
372  callback_customdata,
374  camera_intrinsics);
375  }
376 
377  /* Finish reconstruction. */
378  finishReconstruction(tracks,
379  *camera_intrinsics,
380  libmv_reconstruction,
381  progress_update_callback,
382  callback_customdata);
383 
384  libmv_reconstruction->is_valid = true;
385  return (libmv_Reconstruction*)libmv_reconstruction;
386 }
387 
389  return libmv_reconstruction->is_valid;
390 }
391 
393  LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics);
394  LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction);
395 }
396 
398  const libmv_Reconstruction* libmv_reconstruction,
399  int track,
400  double pos[3]) {
402  &libmv_reconstruction->reconstruction;
403  const EuclideanPoint* point = reconstruction->PointForTrack(track);
404  if (point) {
405  pos[0] = point->X[0];
406  pos[1] = point->X[2];
407  pos[2] = point->X[1];
408  return 1;
409  }
410  return 0;
411 }
412 
414  const libmv_Reconstruction* libmv_reconstruction, int track) {
416  &libmv_reconstruction->reconstruction;
417  const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics;
419  libmv_reconstruction->tracks.MarkersForTrack(track);
420 
421  int num_reprojected = 0;
422  double total_error = 0.0;
423 
424  for (int i = 0; i < markers.size(); ++i) {
425  double weight = markers[i].weight;
426  const EuclideanCamera* camera =
427  reconstruction->CameraForImage(markers[i].image);
428  const EuclideanPoint* point =
429  reconstruction->PointForTrack(markers[i].track);
430 
431  if (!camera || !point || weight == 0.0) {
432  continue;
433  }
434 
435  num_reprojected++;
436 
437  Marker reprojected_marker =
438  libmv_projectMarker(*point, *camera, *intrinsics);
439  double ex = (reprojected_marker.x - markers[i].x) * weight;
440  double ey = (reprojected_marker.y - markers[i].y) * weight;
441 
442  total_error += sqrt(ex * ex + ey * ey);
443  }
444 
445  return total_error / num_reprojected;
446 }
447 
449  const libmv_Reconstruction* libmv_reconstruction, int image) {
451  &libmv_reconstruction->reconstruction;
452  const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics;
454  libmv_reconstruction->tracks.MarkersInImage(image);
455  const EuclideanCamera* camera = reconstruction->CameraForImage(image);
456  int num_reprojected = 0;
457  double total_error = 0.0;
458 
459  if (!camera) {
460  return 0.0;
461  }
462 
463  for (int i = 0; i < markers.size(); ++i) {
464  const EuclideanPoint* point =
465  reconstruction->PointForTrack(markers[i].track);
466 
467  if (!point) {
468  continue;
469  }
470 
471  num_reprojected++;
472 
473  Marker reprojected_marker =
474  libmv_projectMarker(*point, *camera, *intrinsics);
475  double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight;
476  double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight;
477 
478  total_error += sqrt(ex * ex + ey * ey);
479  }
480 
481  return total_error / num_reprojected;
482 }
483 
485  const libmv_Reconstruction* libmv_reconstruction,
486  int image,
487  double mat[4][4]) {
489  &libmv_reconstruction->reconstruction;
490  const EuclideanCamera* camera = reconstruction->CameraForImage(image);
491 
492  if (camera) {
493  for (int j = 0; j < 3; ++j) {
494  for (int k = 0; k < 3; ++k) {
495  int l = k;
496 
497  if (k == 1) {
498  l = 2;
499  } else if (k == 2) {
500  l = 1;
501  }
502 
503  if (j == 2) {
504  mat[j][l] = -camera->R(j, k);
505  } else {
506  mat[j][l] = camera->R(j, k);
507  }
508  }
509  mat[j][3] = 0.0;
510  }
511 
512  libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
513 
514  mat[3][0] = optical_center(0);
515  mat[3][1] = optical_center(2);
516  mat[3][2] = optical_center(1);
517 
518  mat[3][3] = 1.0;
519 
520  return 1;
521  }
522 
523  return 0;
524 }
525 
527  const libmv_Reconstruction* libmv_reconstruction) {
528  return libmv_reconstruction->error;
529 }
530 
532  libmv_Reconstruction* libmv_reconstruction) {
533  return (libmv_CameraIntrinsics*)libmv_reconstruction->intrinsics;
534 }
sqrt(x)+1/max(0
ATTR_WARN_UNUSED_RESULT const BMLoop * l
virtual void ApplyIntrinsics(double normalized_x, double normalized_y, double *image_x, double *image_y) const =0
virtual void InvertIntrinsics(double image_x, double image_y, double *normalized_x, double *normalized_y) const =0
virtual void invoke(double progress, const char *message)=0
vector< Marker > MarkersInImage(int image) const
Returns all the markers visible in image.
vector< Marker > MarkersForTracksInBothImages(int image1, int image2) const
void Insert(int image, int track, double x, double y, double weight=1.0)
vector< Marker > MarkersForTrack(int track) const
Returns all the markers belonging to a track.
uint pos
const vector< Marker > & markers
CameraIntrinsics * libmv_cameraIntrinsicsCreateFromOptions(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
struct libmv_CameraIntrinsics libmv_CameraIntrinsics
libmv_Reconstruction * libmv_solveReconstruction(const libmv_Tracks *libmv_tracks, const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, libmv_ReconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
double libmv_reprojectionErrorForImage(const libmv_Reconstruction *libmv_reconstruction, int image)
libmv_CameraIntrinsics * libmv_reconstructionExtractIntrinsics(libmv_Reconstruction *libmv_reconstruction)
double libmv_reprojectionError(const libmv_Reconstruction *libmv_reconstruction)
void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction)
int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction)
int libmv_reprojectionCameraForImage(const libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4])
libmv_Reconstruction * libmv_solveModal(const libmv_Tracks *libmv_tracks, const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, const libmv_ReconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
int libmv_reprojectionPointForTrack(const libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
#define SET_DISTORTION_FLAG_CHECKED(type, coefficient)
double libmv_reprojectionErrorForTrack(const libmv_Reconstruction *libmv_reconstruction, int track)
void(* reconstruct_progress_update_cb)(void *customdata, double progress, const char *message)
@ LIBMV_REFINE_FOCAL_LENGTH
@ LIBMV_REFINE_PRINCIPAL_POINT
struct libmv_Tracks libmv_Tracks
Definition: intern/tracks.h:27
const ProjectiveReconstruction & reconstruction
Definition: intersect.cc:198
#define LG
@ BUNDLE_NO_TRANSLATION
Definition: bundle.h:118
@ BUNDLE_NO_CONSTRAINTS
Definition: bundle.h:117
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
Definition: vector.h:39
void ModalSolver(const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback)
@ BUNDLE_FOCAL_LENGTH
Definition: bundle.h:102
@ BUNDLE_NO_INTRINSICS
Definition: bundle.h:100
@ BUNDLE_PRINCIPAL_POINT
Definition: bundle.h:103
void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, const CameraIntrinsics &intrinsics, vector< int > &keyframes)
bool EuclideanReconstructTwoFrames(const vector< Marker > &markers, EuclideanReconstruction *reconstruction)
void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction)
void EuclideanBundle(const Tracks &tracks, EuclideanReconstruction *reconstruction)
Definition: bundle.cc:650
void EuclideanCompleteReconstruction(const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback)
Eigen::Vector3d Vec3
Definition: numeric.h:106
void EuclideanBundleCommonIntrinsics(const Tracks &tracks, const int bundle_intrinsics, const int bundle_constraints, EuclideanReconstruction *reconstruction, CameraIntrinsics *intrinsics, BundleEvaluation *evaluation)
Definition: bundle.cc:661
double EuclideanReprojectionError(const Tracks &image_tracks, const EuclideanReconstruction &reconstruction, const CameraIntrinsics &intrinsics)
@ TANGENTIAL
Definition: polyfill_2d.c:128
CameraIntrinsics * intrinsics
EuclideanReconstruction reconstruction
ListBase tracks
Definition: tracking.c:75
float max
#define LIBMV_OBJECT_NEW(type,...)
Definition: utildefines.h:42
#define LIBMV_OBJECT_DELETE(what, type)
Definition: utildefines.h:45