2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2011 Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation,
24 * ***** END GPL LICENSE BLOCK *****
27 /* define this to generate PNG images with content of search areas
28 tracking between which failed */
31 /* define this to generate PNG images with content of search areas
32 on every itteration of tracking */
35 #include "libmv-capi.h"
37 #include "third_party/gflags/gflags/gflags.h"
38 #include "glog/logging.h"
39 #include "libmv/logging/logging.h"
41 #include "Math/v3d_optimization.h"
43 #include "libmv/numeric/numeric.h"
45 #include "libmv/tracking/esm_region_tracker.h"
46 #include "libmv/tracking/brute_region_tracker.h"
47 #include "libmv/tracking/hybrid_region_tracker.h"
48 #include "libmv/tracking/klt_region_tracker.h"
49 #include "libmv/tracking/trklt_region_tracker.h"
50 #include "libmv/tracking/lmicklt_region_tracker.h"
51 #include "libmv/tracking/pyramid_region_tracker.h"
52 #include "libmv/tracking/track_region.h"
54 #include "libmv/simple_pipeline/callbacks.h"
55 #include "libmv/simple_pipeline/tracks.h"
56 #include "libmv/simple_pipeline/initialize_reconstruction.h"
57 #include "libmv/simple_pipeline/bundle.h"
58 #include "libmv/simple_pipeline/detect.h"
59 #include "libmv/simple_pipeline/pipeline.h"
60 #include "libmv/simple_pipeline/camera_intrinsics.h"
61 #include "libmv/simple_pipeline/rigid_registration.h"
62 #include "libmv/simple_pipeline/modal_solver.h"
67 #if defined(DUMP_FAILURE) || defined (DUMP_ALWAYS)
72 # define snprintf _snprintf
75 typedef struct libmv_Reconstruction {
76 libmv::EuclideanReconstruction reconstruction;
78 /* used for per-track average error calculation after reconstruction */
80 libmv::CameraIntrinsics intrinsics;
83 } libmv_Reconstruction;
85 typedef struct libmv_Features {
87 libmv::Feature *features;
90 /* ************ Logging ************ */
92 void libmv_initLogging(const char *argv0)
94 google::InitGoogleLogging(argv0);
95 google::SetCommandLineOption("logtostderr", "1");
96 google::SetCommandLineOption("v", "0");
97 google::SetCommandLineOption("stderrthreshold", "7");
98 google::SetCommandLineOption("minloglevel", "7");
99 V3D::optimizerVerbosenessLevel = 0;
102 void libmv_startDebugLogging(void)
104 google::SetCommandLineOption("logtostderr", "1");
105 google::SetCommandLineOption("v", "2");
106 google::SetCommandLineOption("stderrthreshold", "1");
107 google::SetCommandLineOption("minloglevel", "0");
108 V3D::optimizerVerbosenessLevel = 1;
111 void libmv_setLoggingVerbosity(int verbosity)
114 snprintf(val, sizeof(val), "%d", verbosity);
116 google::SetCommandLineOption("v", val);
117 V3D::optimizerVerbosenessLevel = verbosity;
120 /* ************ RegionTracker ************ */
122 libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation)
124 libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
125 esm_region_tracker->half_window_size = half_window_size;
126 esm_region_tracker->max_iterations = max_iterations;
127 esm_region_tracker->min_determinant = 1e-4;
128 esm_region_tracker->minimum_correlation = minimum_correlation;
130 libmv::PyramidRegionTracker *pyramid_region_tracker =
131 new libmv::PyramidRegionTracker(esm_region_tracker, pyramid_level);
133 return (libmv_RegionTracker *)pyramid_region_tracker;
136 libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation)
138 libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
139 esm_region_tracker->half_window_size = half_window_size;
140 esm_region_tracker->max_iterations = max_iterations;
141 esm_region_tracker->min_determinant = 1e-4;
142 esm_region_tracker->minimum_correlation = minimum_correlation;
144 libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
145 brute_region_tracker->half_window_size = half_window_size;
147 /* do not use correlation check for brute checker itself,
148 * this check will happen in esm tracker */
149 brute_region_tracker->minimum_correlation = 0.0;
151 libmv::HybridRegionTracker *hybrid_region_tracker =
152 new libmv::HybridRegionTracker(brute_region_tracker, esm_region_tracker);
154 return (libmv_RegionTracker *)hybrid_region_tracker;
157 libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation)
159 libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
160 brute_region_tracker->half_window_size = half_window_size;
161 brute_region_tracker->minimum_correlation = minimum_correlation;
163 return (libmv_RegionTracker *)brute_region_tracker;
166 static void floatBufToImage(const float *buf, int width, int height, int channels, libmv::FloatImage *image)
170 image->Resize(height, width, channels);
172 for (y = 0; y < height; y++) {
173 for (x = 0; x < width; x++) {
174 for (k = 0; k < channels; k++) {
175 (*image)(y, x, k) = buf[a++];
181 static void imageToFloatBuf(const libmv::FloatImage *image, int channels, float *buf)
185 for (y = 0; y < image->Height(); y++) {
186 for (x = 0; x < image->Width(); x++) {
187 for (k = 0; k < channels; k++) {
188 buf[a++] = (*image)(y, x, k);
194 #if defined(DUMP_FAILURE) || defined (DUMP_ALWAYS)
195 void savePNGImage(png_bytep *row_pointers, int width, int height, int depth, int color_type, char *file_name)
199 FILE *fp = fopen(file_name, "wb");
204 /* Initialize stuff */
205 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
206 info_ptr = png_create_info_struct(png_ptr);
208 if (setjmp(png_jmpbuf(png_ptr))) {
213 png_init_io(png_ptr, fp);
216 if (setjmp(png_jmpbuf(png_ptr))) {
221 png_set_IHDR(png_ptr, info_ptr, width, height,
222 depth, color_type, PNG_INTERLACE_NONE,
223 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
225 png_write_info(png_ptr, info_ptr);
228 if (setjmp(png_jmpbuf(png_ptr))) {
233 png_write_image(png_ptr, row_pointers);
236 if (setjmp(png_jmpbuf(png_ptr))) {
241 png_write_end(png_ptr, NULL);
246 static void saveImage(const char *prefix, libmv::FloatImage image, int x0, int y0)
249 png_bytep *row_pointers;
251 row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*image.Height());
253 for (y = 0; y < image.Height(); y++) {
254 row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*image.Width());
256 for (x = 0; x < image.Width(); x++) {
257 if (x0 == x && image.Height() - y0 - 1 == y) {
258 row_pointers[y][x*4+0]= 255;
259 row_pointers[y][x*4+1]= 0;
260 row_pointers[y][x*4+2]= 0;
261 row_pointers[y][x*4+3]= 255;
264 float pixel = image(image.Height() - y - 1, x, 0);
265 row_pointers[y][x*4+0]= pixel*255;
266 row_pointers[y][x*4+1]= pixel*255;
267 row_pointers[y][x*4+2]= pixel*255;
268 row_pointers[y][x*4+3]= 255;
276 snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
277 savePNGImage(row_pointers, image.Width(), image.Height(), 8, PNG_COLOR_TYPE_RGBA, buf);
280 for (y = 0; y < image.Height(); y++) {
281 free(row_pointers[y]);
286 static void saveBytesImage(const char *prefix, unsigned char *data, int width, int height)
289 png_bytep *row_pointers;
291 row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*height);
293 for (y = 0; y < height; y++) {
294 row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*width);
296 for (x = 0; x < width; x++) {
297 char pixel = data[width*y+x];
298 row_pointers[y][x*4+0]= pixel;
299 row_pointers[y][x*4+1]= pixel;
300 row_pointers[y][x*4+2]= pixel;
301 row_pointers[y][x*4+3]= 255;
308 snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
309 savePNGImage(row_pointers, width, height, 8, PNG_COLOR_TYPE_RGBA, buf);
312 for (y = 0; y < height; y++) {
313 free(row_pointers[y]);
319 int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
320 int width, int height, double x1, double y1, double *x2, double *y2)
322 libmv::RegionTracker *region_tracker = (libmv::RegionTracker *)libmv_tracker;
323 libmv::FloatImage old_patch, new_patch;
325 floatBufToImage(ima1, width, height, 1, &old_patch);
326 floatBufToImage(ima2, width, height, 1, &new_patch);
328 #if !defined(DUMP_FAILURE) && !defined(DUMP_ALWAYS)
329 return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
332 /* double sx2 = *x2, sy2 = *y2; */
333 int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
335 #if defined(DUMP_ALWAYS)
340 saveImage("old_patch", old_patch, x1, y1);
341 saveImage("new_patch", new_patch, *x2, *y2);
349 void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker)
351 libmv::RegionTracker *region_tracker= (libmv::RegionTracker *)libmv_tracker;
353 delete region_tracker;
356 /* ************ Planar tracker ************ */
358 /* TrackRegion (new planar tracker) */
359 int libmv_trackRegion(const struct libmv_trackRegionOptions *options,
360 const float *image1, int image1_width, int image1_height,
361 const float *image2, int image2_width, int image2_height,
362 const double *x1, const double *y1,
363 struct libmv_trackRegionResult *result,
364 double *x2, double *y2)
366 double xx1[5], yy1[5];
367 double xx2[5], yy2[5];
368 bool tracking_result = false;
370 /* Convert to doubles for the libmv api. The four corners and the center. */
371 for (int i = 0; i < 5; ++i) {
378 libmv::TrackRegionOptions track_region_options;
379 libmv::FloatImage image1_mask;
381 switch (options->motion_model) {
382 #define LIBMV_CONVERT(the_model) \
383 case libmv::TrackRegionOptions::the_model: \
384 track_region_options.mode = libmv::TrackRegionOptions::the_model; \
386 LIBMV_CONVERT(TRANSLATION)
387 LIBMV_CONVERT(TRANSLATION_ROTATION)
388 LIBMV_CONVERT(TRANSLATION_SCALE)
389 LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE)
390 LIBMV_CONVERT(AFFINE)
391 LIBMV_CONVERT(HOMOGRAPHY)
395 track_region_options.minimum_correlation = options->minimum_correlation;
396 track_region_options.max_iterations = options->num_iterations;
397 track_region_options.sigma = options->sigma;
398 track_region_options.num_extra_points = 1;
399 track_region_options.image1_mask = NULL;
400 track_region_options.use_brute_initialization = options->use_brute;
401 track_region_options.use_normalized_intensities = options->use_normalization;
403 if (options->image1_mask) {
404 floatBufToImage(options->image1_mask, image1_width, image1_height, 1, &image1_mask);
406 track_region_options.image1_mask = &image1_mask;
409 /* Convert from raw float buffers to libmv's FloatImage. */
410 libmv::FloatImage old_patch, new_patch;
411 floatBufToImage(image1, image1_width, image1_height, 1, &old_patch);
412 floatBufToImage(image2, image2_width, image2_height, 1, &new_patch);
414 libmv::TrackRegionResult track_region_result;
415 libmv::TrackRegion(old_patch, new_patch, xx1, yy1, track_region_options, xx2, yy2, &track_region_result);
417 /* Convert to floats for the blender api. */
418 for (int i = 0; i < 5; ++i) {
423 /* TODO(keir): Update the termination string with failure details. */
424 if (track_region_result.termination == libmv::TrackRegionResult::PARAMETER_TOLERANCE ||
425 track_region_result.termination == libmv::TrackRegionResult::FUNCTION_TOLERANCE ||
426 track_region_result.termination == libmv::TrackRegionResult::GRADIENT_TOLERANCE ||
427 track_region_result.termination == libmv::TrackRegionResult::NO_CONVERGENCE)
429 tracking_result = true;
432 #if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS)
433 #if defined(DUMP_ALWAYS)
436 if (!tracking_result) {
438 saveImage("old_patch", old_patch, x1[4], y1[4]);
439 saveImage("new_patch", new_patch, x2[4], y2[4]);
443 return tracking_result;
446 void libmv_samplePlanarPatch(const float *image, int width, int height,
447 int channels, const double *xs, const double *ys,
448 int num_samples_x, int num_samples_y,
449 const float *mask, float *patch,
450 double *warped_position_x, double *warped_position_y)
452 libmv::FloatImage libmv_image, libmv_patch, libmv_mask;
453 libmv::FloatImage *libmv_mask_for_sample = NULL;
455 floatBufToImage(image, width, height, channels, &libmv_image);
458 floatBufToImage(mask, width, height, 1, &libmv_mask);
460 libmv_mask_for_sample = &libmv_mask;
463 libmv::SamplePlanarPatch(libmv_image, xs, ys, num_samples_x, num_samples_y,
464 libmv_mask_for_sample, &libmv_patch,
465 warped_position_x, warped_position_y);
467 imageToFloatBuf(&libmv_patch, channels, patch);
470 /* ************ Tracks ************ */
472 libmv_Tracks *libmv_tracksNew(void)
474 libmv::Tracks *libmv_tracks = new libmv::Tracks();
476 return (libmv_Tracks *)libmv_tracks;
479 void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y)
481 ((libmv::Tracks*)libmv_tracks)->Insert(image, track, x, y);
484 void libmv_tracksDestroy(libmv_Tracks *libmv_tracks)
486 delete (libmv::Tracks*)libmv_tracks;
489 /* ************ Reconstruction solver ************ */
491 class ReconstructUpdateCallback : public libmv::ProgressUpdateCallback {
493 ReconstructUpdateCallback(reconstruct_progress_update_cb progress_update_callback,
494 void *callback_customdata)
496 progress_update_callback_ = progress_update_callback;
497 callback_customdata_ = callback_customdata;
500 void invoke(double progress, const char *message)
502 if(progress_update_callback_) {
503 progress_update_callback_(callback_customdata_, progress, message);
507 reconstruct_progress_update_cb progress_update_callback_;
508 void *callback_customdata_;
511 int libmv_refineParametersAreValid(int parameters) {
512 return (parameters == (LIBMV_REFINE_FOCAL_LENGTH)) ||
513 (parameters == (LIBMV_REFINE_FOCAL_LENGTH |
514 LIBMV_REFINE_PRINCIPAL_POINT)) ||
515 (parameters == (LIBMV_REFINE_FOCAL_LENGTH |
516 LIBMV_REFINE_PRINCIPAL_POINT |
517 LIBMV_REFINE_RADIAL_DISTORTION_K1 |
518 LIBMV_REFINE_RADIAL_DISTORTION_K2)) ||
519 (parameters == (LIBMV_REFINE_FOCAL_LENGTH |
520 LIBMV_REFINE_RADIAL_DISTORTION_K1 |
521 LIBMV_REFINE_RADIAL_DISTORTION_K2)) ||
522 (parameters == (LIBMV_REFINE_FOCAL_LENGTH |
523 LIBMV_REFINE_RADIAL_DISTORTION_K1));
526 void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics,
527 libmv::EuclideanReconstruction *reconstruction, int refine_intrinsics,
528 reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
530 /* only a few combinations are supported but trust the caller */
531 int libmv_refine_flags = 0;
533 if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
534 libmv_refine_flags |= libmv::BUNDLE_FOCAL_LENGTH;
536 if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
537 libmv_refine_flags |= libmv::BUNDLE_PRINCIPAL_POINT;
539 if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) {
540 libmv_refine_flags |= libmv::BUNDLE_RADIAL_K1;
542 if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
543 libmv_refine_flags |= libmv::BUNDLE_RADIAL_K2;
546 progress_update_callback(callback_customdata, 1.0, "Refining solution");
548 libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags,
549 reconstruction, intrinsics);
552 libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
553 int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
554 reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
556 /* Invert the camera intrinsics. */
557 libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
558 libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
559 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
560 libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
562 ReconstructUpdateCallback update_callback =
563 ReconstructUpdateCallback(progress_update_callback, callback_customdata);
565 intrinsics->SetFocalLength(focal_length, focal_length);
566 intrinsics->SetPrincipalPoint(principal_x, principal_y);
567 intrinsics->SetRadialDistortion(k1, k2, k3);
569 for (int i = 0; i < markers.size(); ++i) {
570 intrinsics->InvertIntrinsics(markers[i].x,
576 libmv::Tracks normalized_tracks(markers);
578 LG << "frames to init from: " << keyframe1 << " " << keyframe2;
579 libmv::vector<libmv::Marker> keyframe_markers =
580 normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
581 LG << "number of markers for init: " << keyframe_markers.size();
583 update_callback.invoke(0, "Initial reconstruction");
585 libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction);
586 libmv::EuclideanBundle(normalized_tracks, reconstruction);
587 libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction, &update_callback);
589 if (refine_intrinsics) {
590 libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction,
591 refine_intrinsics, progress_update_callback, callback_customdata);
594 progress_update_callback(callback_customdata, 1.0, "Finishing solution");
595 libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
596 libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
598 return (libmv_Reconstruction *)libmv_reconstruction;
601 struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length,
602 double principal_x, double principal_y, double k1, double k2, double k3,
603 reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
605 /* Invert the camera intrinsics. */
606 libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
607 libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
608 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
609 libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
611 ReconstructUpdateCallback update_callback =
612 ReconstructUpdateCallback(progress_update_callback, callback_customdata);
614 intrinsics->SetFocalLength(focal_length, focal_length);
615 intrinsics->SetPrincipalPoint(principal_x, principal_y);
616 intrinsics->SetRadialDistortion(k1, k2, k3);
618 for (int i = 0; i < markers.size(); ++i) {
619 intrinsics->InvertIntrinsics(markers[i].x,
625 libmv::Tracks normalized_tracks(markers);
627 libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback);
629 progress_update_callback(callback_customdata, 1.0, "Finishing solution");
630 libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
631 libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
633 return (libmv_Reconstruction *)libmv_reconstruction;
636 int libmv_reporojectionPointForTrack(libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
638 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
639 libmv::EuclideanPoint *point = reconstruction->PointForTrack(track);
642 pos[0] = point->X[0];
643 pos[1] = point->X[2];
644 pos[2] = point->X[1];
652 static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point, const libmv::EuclideanCamera &camera,
653 const libmv::CameraIntrinsics &intrinsics) {
654 libmv::Vec3 projected = camera.R * point.X + camera.t;
655 projected /= projected(2);
657 libmv::Marker reprojected_marker;
658 intrinsics.ApplyIntrinsics(projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
660 reprojected_marker.image = camera.image;
661 reprojected_marker.track = point.track;
663 return reprojected_marker;
666 double libmv_reporojectionErrorForTrack(libmv_Reconstruction *libmv_reconstruction, int track)
668 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
669 libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
670 libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersForTrack(track);
672 int num_reprojected = 0;
673 double total_error = 0.0;
675 for (int i = 0; i < markers.size(); ++i) {
676 const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
677 const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
679 if (!camera || !point) {
685 libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
686 double ex = reprojected_marker.x - markers[i].x;
687 double ey = reprojected_marker.y - markers[i].y;
689 total_error += sqrt(ex*ex + ey*ey);
692 return total_error / num_reprojected;
695 double libmv_reporojectionErrorForImage(libmv_Reconstruction *libmv_reconstruction, int image)
697 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
698 libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
699 libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
700 const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
701 int num_reprojected = 0;
702 double total_error = 0.0;
707 for (int i = 0; i < markers.size(); ++i) {
708 const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
716 libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
717 double ex = reprojected_marker.x - markers[i].x;
718 double ey = reprojected_marker.y - markers[i].y;
720 total_error += sqrt(ex*ex + ey*ey);
723 return total_error / num_reprojected;
726 int libmv_reporojectionCameraForImage(libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4])
728 libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
729 libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
732 for (int j = 0; j < 3; ++j) {
733 for (int k = 0; k < 3; ++k) {
737 else if (k == 2) l = 1;
739 if (j == 2) mat[j][l] = -camera->R(j,k);
740 else mat[j][l] = camera->R(j,k);
745 libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
747 mat[3][0] = optical_center(0);
748 mat[3][1] = optical_center(2);
749 mat[3][2] = optical_center(1);
759 double libmv_reprojectionError(libmv_Reconstruction *libmv_reconstruction)
761 return libmv_reconstruction->error;
764 void libmv_destroyReconstruction(libmv_Reconstruction *libmv_reconstruction)
766 delete libmv_reconstruction;
769 /* ************ feature detector ************ */
771 struct libmv_Features *libmv_detectFeaturesFAST(unsigned char *data, int width, int height, int stride,
772 int margin, int min_trackness, int min_distance)
774 libmv::Feature *features = NULL;
775 std::vector<libmv::Feature> v;
776 libmv_Features *libmv_features = new libmv_Features();
780 data += margin*stride+margin;
785 v = libmv::DetectFAST(data, width, height, stride, min_trackness, min_distance);
790 features= new libmv::Feature[count];
792 for(std::vector<libmv::Feature>::iterator it = v.begin(); it != v.end(); it++) {
797 libmv_features->features = features;
798 libmv_features->count = count;
799 libmv_features->margin = margin;
801 return (libmv_Features *)libmv_features;
804 struct libmv_Features *libmv_detectFeaturesMORAVEC(unsigned char *data, int width, int height, int stride,
805 int margin, int count, int min_distance)
807 libmv::Feature *features = NULL;
808 libmv_Features *libmv_features = new libmv_Features;
812 data += margin*stride+margin;
817 features = new libmv::Feature[count];
818 libmv::DetectMORAVEC(data, stride, width, height, features, &count, min_distance, NULL);
821 libmv_features->count = count;
822 libmv_features->margin = margin;
823 libmv_features->features = features;
825 return libmv_features;
828 int libmv_countFeatures(struct libmv_Features *libmv_features)
830 return libmv_features->count;
833 void libmv_getFeature(struct libmv_Features *libmv_features, int number, double *x, double *y, double *score, double *size)
835 libmv::Feature feature= libmv_features->features[number];
837 *x = feature.x + libmv_features->margin;
838 *y = feature.y + libmv_features->margin;
839 *score = feature.score;
840 *size = feature.size;
843 void libmv_destroyFeatures(struct libmv_Features *libmv_features)
845 if(libmv_features->features)
846 delete [] libmv_features->features;
848 delete libmv_features;
851 /* ************ camera intrinsics ************ */
853 struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction) {
854 return (struct libmv_CameraIntrinsics *)&libmv_Reconstruction->intrinsics;
857 struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
858 double k1, double k2, double k3, int width, int height)
860 libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics();
862 intrinsics->SetFocalLength(focal_length, focal_length);
863 intrinsics->SetPrincipalPoint(principal_x, principal_y);
864 intrinsics->SetRadialDistortion(k1, k2, k3);
865 intrinsics->SetImageSize(width, height);
867 return (struct libmv_CameraIntrinsics *) intrinsics;
870 struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics)
872 libmv::CameraIntrinsics *orig_intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
873 libmv::CameraIntrinsics *new_intrinsics= new libmv::CameraIntrinsics(*orig_intrinsics);
875 return (struct libmv_CameraIntrinsics *) new_intrinsics;
878 void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics)
880 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
885 void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
886 double principal_x, double principal_y, double k1, double k2, double k3, int width, int height)
888 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
890 if (intrinsics->focal_length() != focal_length)
891 intrinsics->SetFocalLength(focal_length, focal_length);
893 if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
894 intrinsics->SetFocalLength(focal_length, focal_length);
896 if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
897 intrinsics->SetRadialDistortion(k1, k2, k3);
899 if (intrinsics->image_width() != width || intrinsics->image_height() != height)
900 intrinsics->SetImageSize(width, height);
903 void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length,
904 double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height) {
905 libmv::CameraIntrinsics *intrinsics= (libmv::CameraIntrinsics *) libmvIntrinsics;
906 *focal_length = intrinsics->focal_length();
907 *principal_x = intrinsics->principal_point_x();
908 *principal_y = intrinsics->principal_point_y();
909 *k1 = intrinsics->k1();
910 *k2 = intrinsics->k2();
913 void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
914 unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
916 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
918 intrinsics->Undistort(src, dst, width, height, overscan, channels);
921 void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
922 float *src, float *dst, int width, int height, float overscan, int channels)
924 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
926 intrinsics->Undistort(src, dst, width, height, overscan, channels);
929 void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
930 unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
932 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
933 intrinsics->Distort(src, dst, width, height, overscan, channels);
936 void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
937 float *src, float *dst, int width, int height, float overscan, int channels)
939 libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
941 intrinsics->Distort(src, dst, width, height, overscan, channels);
944 /* ************ distortion ************ */
946 void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
947 unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
949 libmv::CameraIntrinsics intrinsics;
951 intrinsics.SetFocalLength(focal_length, focal_length);
952 intrinsics.SetPrincipalPoint(principal_x, principal_y);
953 intrinsics.SetRadialDistortion(k1, k2, k3);
955 intrinsics.Undistort(src, dst, width, height, overscan, channels);
958 void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
959 float *src, float *dst, int width, int height, float overscan, int channels)
961 libmv::CameraIntrinsics intrinsics;
963 intrinsics.SetFocalLength(focal_length, focal_length);
964 intrinsics.SetPrincipalPoint(principal_x, principal_y);
965 intrinsics.SetRadialDistortion(k1, k2, k3);
967 intrinsics.Undistort(src, dst, width, height, overscan, channels);
970 void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
971 unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
973 libmv::CameraIntrinsics intrinsics;
975 intrinsics.SetFocalLength(focal_length, focal_length);
976 intrinsics.SetPrincipalPoint(principal_x, principal_y);
977 intrinsics.SetRadialDistortion(k1, k2, k3);
979 intrinsics.Distort(src, dst, width, height, overscan, channels);
982 void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
983 float *src, float *dst, int width, int height, float overscan, int channels)
985 libmv::CameraIntrinsics intrinsics;
987 intrinsics.SetFocalLength(focal_length, focal_length);
988 intrinsics.SetPrincipalPoint(principal_x, principal_y);
989 intrinsics.SetRadialDistortion(k1, k2, k3);
991 intrinsics.Distort(src, dst, width, height, overscan, channels);
994 /* ************ utils ************ */
996 void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
997 double x, double y, double *x1, double *y1)
999 libmv::CameraIntrinsics intrinsics;
1001 intrinsics.SetFocalLength(focal_length, focal_length);
1002 intrinsics.SetPrincipalPoint(principal_x, principal_y);
1003 intrinsics.SetRadialDistortion(k1, k2, k3);
1006 /* do a lens undistortion if focal length is non-zero only */
1008 intrinsics.ApplyIntrinsics(x, y, x1, y1);
1012 void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
1013 double x, double y, double *x1, double *y1)
1015 libmv::CameraIntrinsics intrinsics;
1017 intrinsics.SetFocalLength(focal_length, focal_length);
1018 intrinsics.SetPrincipalPoint(principal_x, principal_y);
1019 intrinsics.SetRadialDistortion(k1, k2, k3);
1022 /* do a lens distortion if focal length is non-zero only */
1024 intrinsics.InvertIntrinsics(x, y, x1, y1);
1028 /* ************ point clouds ************ */
1030 void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4])
1032 for (int j = 0; j < 3; ++j)
1033 for (int k = 0; k < 3; ++k)
1034 M[j][k] = R(k, j) * S(j);
1036 for (int i = 0; i < 3; ++i) {
1041 M[0][3] = M[1][3] = M[2][3] = 0;
1047 void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points,
1048 int use_scale, int use_translation, double M[4][4])
1053 libmv::vector<libmv::Vec3> reference_points_vector, points_vector;
1055 for (int i = 0; i < total_points; i++) {
1056 reference_points_vector.push_back(libmv::Vec3(reference_points[i][0],
1057 reference_points[i][1],
1058 reference_points[i][2]));
1060 points_vector.push_back(libmv::Vec3(points[i][0],
1065 if (use_scale && use_translation) {
1066 libmv::RigidRegistration(reference_points_vector, points_vector, R, S, t);
1068 else if (use_translation) {
1069 S = libmv::Vec3(1.0, 1.0, 1.0);
1070 libmv::RigidRegistration(reference_points_vector, points_vector, R, t);
1073 S = libmv::Vec3(1.0, 1.0, 1.0);
1074 t = libmv::Vec3::Zero();
1075 libmv::RigidRegistration(reference_points_vector, points_vector, R);
1078 libmvTransformToMat4(R, S, t, M);