49 ReconstructUpdateCallback(
51 void* callback_customdata) {
52 progress_update_callback_ = progress_update_callback;
53 callback_customdata_ = callback_customdata;
56 void invoke(
double progress,
const char* message) {
57 if (progress_update_callback_) {
58 progress_update_callback_(callback_customdata_, progress, message);
64 void* callback_customdata_;
67void libmv_solveRefineIntrinsics(
69 const int refine_intrinsics,
70 const int bundle_constraints,
72 void* callback_customdata,
76 int bundle_intrinsics = 0;
85#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \
87 if (refine_intrinsics & LIBMV_REFINE_##type##_DISTORTION_##coefficient) { \
88 bundle_intrinsics |= libmv::BUNDLE_##type##_##coefficient; \
100#undef SET_DISTORTION_FLAG_CHECKED
102 progress_update_callback(callback_customdata, 1.0,
"Refining solution");
111void finishReconstruction(
116 void* callback_customdata) {
121 progress_update_callback(callback_customdata, 1.0,
"Finishing solution");
123 libmv_reconstruction->
error =
124 EuclideanReprojectionError(tracks,
reconstruction, camera_intrinsics);
127bool selectTwoKeyframesBasedOnGRICAndVariance(
129 Tracks& normalized_tracks,
137 normalized_tracks, camera_intrinsics, keyframes);
139 if (keyframes.size() < 2) {
140 LG <<
"Not enough keyframes detected by GRIC";
142 }
else if (keyframes.size() == 2) {
143 keyframe1 = keyframes[0];
144 keyframe2 = keyframes[1];
156 int previous_keyframe = keyframes[0];
157 double best_error = std::numeric_limits<double>::max();
158 for (
int i = 1; i < keyframes.size(); i++) {
160 int current_keyframe = keyframes[i];
165 Tracks keyframe_tracks(keyframe_markers);
172 double current_error =
173 EuclideanReprojectionError(tracks,
reconstruction, camera_intrinsics);
175 LG <<
"Error between " << previous_keyframe <<
" and " << current_keyframe
176 <<
": " << current_error;
178 if (current_error < best_error) {
179 best_error = current_error;
180 keyframe1 = previous_keyframe;
181 keyframe2 = current_keyframe;
184 previous_keyframe = current_keyframe;
193 libmv::Vec3 projected = camera.R * point.X + camera.t;
194 projected /= projected(2);
198 projected(0), projected(1), &reprojected_marker.
x, &reprojected_marker.
y);
200 reprojected_marker.
image = camera.image;
201 reprojected_marker.
track = point.track;
202 return reprojected_marker;
205void libmv_getNormalizedTracks(
const Tracks& tracks,
207 Tracks* normalized_tracks) {
209 for (
int i = 0; i <
markers.size(); ++i) {
212 marker.
x, marker.
y, &marker.
x, &marker.
y);
213 normalized_tracks->
Insert(
225 void* callback_customdata) {
233 ReconstructUpdateCallback update_callback =
234 ReconstructUpdateCallback(progress_update_callback, callback_customdata);
238 camera_intrinsics = libmv_reconstruction->
intrinsics =
243 libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks);
246 int keyframe1 = libmv_reconstruction_options->
keyframe1,
247 keyframe2 = libmv_reconstruction_options->
keyframe2;
250 LG <<
"Using automatic keyframe selection";
252 update_callback.invoke(0,
"Selecting keyframes");
254 if (selectTwoKeyframesBasedOnGRICAndVariance(tracks,
260 libmv_reconstruction_options->
keyframe1 = keyframe1;
261 libmv_reconstruction_options->
keyframe2 = keyframe2;
266 LG <<
"frames to init from: " << keyframe1 <<
" " << keyframe2;
271 LG <<
"number of markers for init: " << keyframe_markers.size();
273 if (keyframe_markers.size() < 16) {
274 LG <<
"No enough markers to initialize from";
275 libmv_reconstruction->
is_valid =
false;
276 return libmv_reconstruction;
279 update_callback.invoke(0,
"Initial reconstruction");
281 if (!EuclideanReconstructTwoFrames(keyframe_markers, &
reconstruction)) {
282 LG <<
"Failed to initialize reconstruction";
283 libmv_reconstruction->
is_valid =
false;
284 return libmv_reconstruction;
288 EuclideanCompleteReconstruction(
293 libmv_solveRefineIntrinsics(tracks,
296 progress_update_callback,
306 finishReconstruction(tracks,
308 libmv_reconstruction,
309 progress_update_callback,
310 callback_customdata);
312 libmv_reconstruction->
is_valid =
true;
321 void* callback_customdata) {
329 ReconstructUpdateCallback update_callback =
330 ReconstructUpdateCallback(progress_update_callback, callback_customdata);
334 camera_intrinsics = libmv_reconstruction->
intrinsics =
339 libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks);
342 ModalSolver(normalized_tracks, &
reconstruction, &update_callback);
345 EuclideanBundleCommonIntrinsics(normalized_tracks,
353 libmv_solveRefineIntrinsics(tracks,
356 progress_update_callback,
363 finishReconstruction(tracks,
365 libmv_reconstruction,
366 progress_update_callback,
367 callback_customdata);
369 libmv_reconstruction->
is_valid =
true;
374 return libmv_reconstruction->
is_valid;
390 pos[0] = point->
X[0];
391 pos[1] = point->X[2];
392 pos[2] = point->X[1];
406 int num_reprojected = 0;
407 double total_error = 0.0;
409 for (
int i = 0; i <
markers.size(); ++i) {
410 double weight =
markers[i].weight;
416 if (!camera || !point || weight == 0.0) {
422 Marker reprojected_marker =
423 libmv_projectMarker(*point, *camera, *intrinsics);
424 double ex = (reprojected_marker.
x -
markers[i].x) * weight;
425 double ey = (reprojected_marker.
y -
markers[i].y) * weight;
427 total_error +=
sqrt(ex * ex + ey * ey);
430 return total_error / num_reprojected;
441 int num_reprojected = 0;
442 double total_error = 0.0;
448 for (
int i = 0; i <
markers.size(); ++i) {
458 Marker reprojected_marker =
459 libmv_projectMarker(*point, *camera, *intrinsics);
463 total_error +=
sqrt(ex * ex + ey * ey);
466 return total_error / num_reprojected;
478 for (
int j = 0; j < 3; ++j) {
479 for (
int k = 0; k < 3; ++k) {
489 mat[j][
l] = -camera->R(j, k);
491 mat[j][
l] = camera->R(j, k);
497 libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
499 mat[3][0] = optical_center(0);
500 mat[3][1] = optical_center(2);
501 mat[3][2] = optical_center(1);
513 return libmv_reconstruction->
error;
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
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.
const vector< Marker > & markers
CameraIntrinsics * libmv_cameraIntrinsicsCreateFromOptions(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
struct libmv_CameraIntrinsics libmv_CameraIntrinsics
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)
double libmv_reprojectionErrorForImage(const libmv_Reconstruction *libmv_reconstruction, int image)
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_CameraIntrinsics * libmv_reconstructionExtractIntrinsics(libmv_Reconstruction *libmv_reconstruction)
int libmv_reprojectionPointForTrack(const libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
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)
#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
const ProjectiveReconstruction & reconstruction
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)
void EuclideanCompleteReconstruction(const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback)
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
void EuclideanBundleCommonIntrinsics(const Tracks &tracks, const int bundle_intrinsics, const int bundle_constraints, EuclideanReconstruction *reconstruction, CameraIntrinsics *intrinsics, BundleEvaluation *evaluation)
double EuclideanReprojectionError(const Tracks &image_tracks, const EuclideanReconstruction &reconstruction, const CameraIntrinsics &intrinsics)
CameraIntrinsics * intrinsics
EuclideanReconstruction reconstruction
#define LIBMV_OBJECT_NEW(type,...)
#define LIBMV_OBJECT_DELETE(what, type)