diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/bundle.cc svn/extern/libmv/libmv/simple_pipeline/bundle.cc
--- trunk/extern/libmv/libmv/simple_pipeline/bundle.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/bundle.cc	2013-09-18 10:21:28.000000000 +0100
@@ -21,8 +21,10 @@
 #include "libmv/simple_pipeline/bundle.h"
 
 #include <map>
+#include <cmath>
 
 #include "ceres/ceres.h"
+#include "ceres/iteration_callback.h"
 #include "ceres/rotation.h"
 #include "libmv/base/vector.h"
 #include "libmv/logging/logging.h"
@@ -54,14 +56,42 @@
 
 namespace {
 
+// Convert a constrained focal length into an uncontrained bundle parameter for
+// passing to Ceres.
+template <typename T>
+T ConstrainFocalLength(const T focal_length,
+                       const double min_focal,
+                       const double max_focal) {
+  using std::asin;
+  return asin(-T(1) + (((focal_length - T(min_focal))
+                    / (T(max_focal) - T(min_focal)))
+                    * T(2.0)));
+}
+
+// Convert an unconstrained bundle parameter received from Ceres back to the
+// corresponding constrained focal length.
+template <typename T>
+T UnconstrainFocalLength(const T bundled_focal,
+                         const double min_focal,
+                         const double max_focal) {
+  using std::sin;
+  return T(min_focal) + (T(max_focal) - T(min_focal))
+                      * (T(1) + sin(bundled_focal))
+                      / T(2.0);
+}
+
 // Cost functor which computes reprojection error of 3D point X
 // on camera defined by angle-axis rotation and it's translation
 // (which are in the same block due to optimization reasons).
 //
 // This functor uses a radial distortion model.
 struct OpenCVReprojectionError {
-  OpenCVReprojectionError(const double observed_x, const double observed_y)
-      : observed_x(observed_x), observed_y(observed_y) {}
+  OpenCVReprojectionError(const double observed_x, const double observed_y,
+                          const double focal_length_min = 0.0,
+                          const double focal_length_max = 0.0)
+      : observed_x(observed_x), observed_y(observed_y),
+        focal_length_min(focal_length_min),
+        focal_length_max(focal_length_max) {}
 
   template <typename T>
   bool operator()(const T* const intrinsics,
@@ -98,11 +128,17 @@
 
     T predicted_x, predicted_y;
 
+    T unconstrained_focal = focal_length;
+    if (focal_length_min != 0.0 || focal_length_max != 0.0) {
+      unconstrained_focal = UnconstrainFocalLength(
+          focal_length, focal_length_min, focal_length_max);
+    }
+
     // Apply distortion to the normalized points to get (xd, yd).
     // TODO(keir): Do early bailouts for zero distortion; these are expensive
     // jet operations.
-    ApplyRadialDistortionCameraIntrinsics(focal_length,
-                                          focal_length,
+    ApplyRadialDistortionCameraIntrinsics(unconstrained_focal,
+                                          unconstrained_focal,
                                           principal_point_x,
                                           principal_point_y,
                                           k1, k2, k3,
@@ -119,6 +155,8 @@
 
   const double observed_x;
   const double observed_y;
+  const double focal_length_min;
+  const double focal_length_max;
 };
 
 // Print a message to the log which camera intrinsics are gonna to be optimixed.
@@ -148,34 +186,66 @@
 }
 
 // Pack intrinsics from object to an array for easier
-// and faster minimization.
-void PackIntrinisicsIntoArray(const CameraIntrinsics &intrinsics,
-                              double ceres_intrinsics[8]) {
-  ceres_intrinsics[OFFSET_FOCAL_LENGTH]       = intrinsics.focal_length();
-  ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X]  = intrinsics.principal_point_x();
-  ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]  = intrinsics.principal_point_y();
-  ceres_intrinsics[OFFSET_K1]                 = intrinsics.k1();
-  ceres_intrinsics[OFFSET_K2]                 = intrinsics.k2();
-  ceres_intrinsics[OFFSET_K3]                 = intrinsics.k3();
-  ceres_intrinsics[OFFSET_P1]                 = intrinsics.p1();
-  ceres_intrinsics[OFFSET_P2]                 = intrinsics.p2();
-}
-
-// Unpack intrinsics back from an array to an object.
-void UnpackIntrinsicsFromArray(const double ceres_intrinsics[8],
-                                 CameraIntrinsics *intrinsics) {
-    intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH],
-                               ceres_intrinsics[OFFSET_FOCAL_LENGTH]);
-
-    intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X],
-                                  ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]);
-
-    intrinsics->SetRadialDistortion(ceres_intrinsics[OFFSET_K1],
-                                    ceres_intrinsics[OFFSET_K2],
-                                    ceres_intrinsics[OFFSET_K3]);
+// and faster minimization, constraining the focal length
+// according to the given BundleOptions.
+vector<Vec8> PackIntrinsics(const std::vector<CameraIntrinsics> &intrinsics,
+                            const BundleOptions &bundle_options) {
+  int num_intrinsics = intrinsics.size();
+  vector<Vec8> ceres_intrinsics(num_intrinsics);
+
+  for (int i = 0; i < num_intrinsics; ++i) {
+    if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
+      ceres_intrinsics[i][OFFSET_FOCAL_LENGTH] = ConstrainFocalLength(
+          intrinsics[i].focal_length(),
+          bundle_options.focal_length_min,
+          bundle_options.focal_length_max);
+    } else {
+      ceres_intrinsics[i][OFFSET_FOCAL_LENGTH] = intrinsics[i].focal_length();
+    }
+    ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_X]  = intrinsics[i].principal_point_x();
+    ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_Y]  = intrinsics[i].principal_point_y();
+    ceres_intrinsics[i][OFFSET_K1]                 = intrinsics[i].k1();
+    ceres_intrinsics[i][OFFSET_K2]                 = intrinsics[i].k2();
+    ceres_intrinsics[i][OFFSET_K3]                 = intrinsics[i].k3();
+    ceres_intrinsics[i][OFFSET_P1]                 = intrinsics[i].p1();
+    ceres_intrinsics[i][OFFSET_P2]                 = intrinsics[i].p2();
+  }
+
+  return ceres_intrinsics;
+}
+
+// Unpack intrinsics back from an array to an object, converting
+// unconstrained bundle parameter to constrained focal length.
+std::vector<CameraIntrinsics> UnpackIntrinsics(
+    const vector<Vec8> &ceres_intrinsics,
+    const BundleOptions &bundle_options) {
+  int num_intrinsics = ceres_intrinsics.size();
+  std::vector<CameraIntrinsics> intrinsics(num_intrinsics);
+
+  for (int i = 0; i < num_intrinsics; ++i) {
+    if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
+      double focal_length = UnconstrainFocalLength(
+          ceres_intrinsics[i][OFFSET_FOCAL_LENGTH],
+          bundle_options.focal_length_min,
+          bundle_options.focal_length_max);
+      intrinsics[i].SetFocalLength(focal_length, focal_length);
+    } else {
+      intrinsics[i].SetFocalLength(ceres_intrinsics[i][OFFSET_FOCAL_LENGTH],
+                                   ceres_intrinsics[i][OFFSET_FOCAL_LENGTH]);
+    }
+
+    intrinsics[i].SetPrincipalPoint(ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_X],
+                                    ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_Y]);
+
+    intrinsics[i].SetRadialDistortion(ceres_intrinsics[i][OFFSET_K1],
+                                      ceres_intrinsics[i][OFFSET_K2],
+                                      ceres_intrinsics[i][OFFSET_K3]);
+
+    intrinsics[i].SetTangentialDistortion(ceres_intrinsics[i][OFFSET_P1],
+                                          ceres_intrinsics[i][OFFSET_P2]);
+  }
 
-    intrinsics->SetTangentialDistortion(ceres_intrinsics[OFFSET_P1],
-                                        ceres_intrinsics[OFFSET_P2]);
+  return intrinsics;
 }
 
 // Get a vector of camera's rotations denoted by angle axis
@@ -183,45 +253,45 @@
 //
 // Element with index i matches to a rotation+translation for
 // camera at image i.
-vector<Vec6> PackCamerasRotationAndTranslation(
+vector<Vec6> PackViewsRotationAndTranslation(
     const Tracks &tracks,
     const EuclideanReconstruction &reconstruction) {
-  vector<Vec6> all_cameras_R_t;
+  vector<Vec6> all_views_R_t;
   int max_image = tracks.MaxImage();
 
-  all_cameras_R_t.resize(max_image + 1);
+  all_views_R_t.resize(max_image + 1);
 
   for (int i = 0; i <= max_image; i++) {
-    const EuclideanCamera *camera = reconstruction.CameraForImage(i);
+    const EuclideanView *view = reconstruction.ViewForImage(i);
 
-    if (!camera) {
+    if (!view) {
       continue;
     }
 
-    ceres::RotationMatrixToAngleAxis(&camera->R(0, 0),
-                                     &all_cameras_R_t[i](0));
-    all_cameras_R_t[i].tail<3>() = camera->t;
+    ceres::RotationMatrixToAngleAxis(&view->R(0, 0),
+                                     &all_views_R_t[i](0));
+    all_views_R_t[i].tail<3>() = view->t;
   }
-  return all_cameras_R_t;
+  return all_views_R_t;
 }
 
 // Convert cameras rotations fro mangle axis back to rotation matrix.
-void UnpackCamerasRotationAndTranslation(
+void UnpackViewsRotationAndTranslation(
     const Tracks &tracks,
-    const vector<Vec6> &all_cameras_R_t,
+    const vector<Vec6> &all_views_R_t,
     EuclideanReconstruction *reconstruction) {
   int max_image = tracks.MaxImage();
 
   for (int i = 0; i <= max_image; i++) {
-    EuclideanCamera *camera = reconstruction->CameraForImage(i);
+    EuclideanView *view = reconstruction->ViewForImage(i);
 
-    if (!camera) {
+    if (!view) {
       continue;
     }
 
-    ceres::AngleAxisToRotationMatrix(&all_cameras_R_t[i](0),
-                                     &camera->R(0, 0));
-    camera->t = all_cameras_R_t[i].tail<3>();
+    ceres::AngleAxisToRotationMatrix(&all_views_R_t[i](0),
+                                     &view->R(0, 0));
+    view->t = all_views_R_t[i].tail<3>();
   }
 }
 
@@ -280,8 +350,8 @@
       int max_image = tracks.MaxImage();
       bool is_first_camera = true;
       for (int i = 0; i <= max_image; i++) {
-        const EuclideanCamera *camera = reconstruction->CameraForImage(i);
-        if (camera) {
+        const EuclideanView *view = reconstruction->ViewForImage(i);
+        if (view) {
           double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
 
           // All cameras are variable now.
@@ -312,42 +382,68 @@
 
 }  // namespace
 
+BundleOptions::BundleOptions() :
+  bundle_intrinsics(BUNDLE_NO_INTRINSICS),
+  constraints(BUNDLE_NO_CONSTRAINTS),
+  focal_length_min(0.0),
+  focal_length_max(0.0),
+  iteration_callback(NULL) {
+}
+
 void EuclideanBundle(const Tracks &tracks,
                      EuclideanReconstruction *reconstruction) {
-  CameraIntrinsics intrinsics;
+  BundleOptions bundle_options;
+
+  std::vector<CameraIntrinsics> empty_intrinsics;
   EuclideanBundleCommonIntrinsics(tracks,
-                                  BUNDLE_NO_INTRINSICS,
-                                  BUNDLE_NO_CONSTRAINTS,
+                                  bundle_options,
                                   reconstruction,
-                                  &intrinsics,
-                                  NULL);
+                                  empty_intrinsics);
 }
 
+void EuclideanBundleModal(const Tracks &tracks,
+                          EuclideanReconstruction *reconstruction) {
+  BundleOptions bundle_options;
+  bundle_options.constraints = libmv::BUNDLE_NO_TRANSLATION;
+
+  std::vector<CameraIntrinsics> empty_intrinsics;
+  EuclideanBundleCommonIntrinsics(tracks,
+                                  bundle_options,
+                                  reconstruction,
+                                  empty_intrinsics);
+}
+ 
 void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
-                                     const int bundle_intrinsics,
-                                     const int bundle_constraints,
+                                     const BundleOptions &bundle_options,
                                      EuclideanReconstruction *reconstruction,
-                                     CameraIntrinsics *intrinsics,
+                                     std::vector<CameraIntrinsics> &intrinsics,
                                      BundleEvaluation *evaluation) {
-  LG << "Original intrinsics: " << *intrinsics;
+  const int bundle_intrinsics = bundle_options.bundle_intrinsics;
+  const int bundle_constraints = bundle_options.constraints;
+
+  //LG << "Original intrinsics: " << *intrinsics;
   vector<Marker> markers = tracks.AllMarkers();
 
+  int num_cameras = tracks.MaxCamera() + 1;
+  if (intrinsics.size() < num_cameras) {
+    intrinsics.resize(num_cameras);
+  }
+
   ceres::Problem::Options problem_options;
   ceres::Problem problem(problem_options);
 
   // Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
   // intrinsics into a single block and rely on local parameterizations to
   // control which intrinsics are allowed to vary.
-  double ceres_intrinsics[8];
-  PackIntrinisicsIntoArray(*intrinsics, ceres_intrinsics);
+  vector<Vec8> ceres_intrinsics = PackIntrinsics(intrinsics, bundle_options);
 
-  // Convert cameras rotations to angle axis and merge with translation
+  // Convert views rotations to angle axis and merge with translation
   // into single parameter block for maximal minimization speed.
   //
   // Block for minimization has got the following structure:
   //   <3 elements for angle-axis> <3 elements for translation>
-  vector<Vec6> all_cameras_R_t =
-    PackCamerasRotationAndTranslation(tracks, *reconstruction);
+  vector<Vec6> all_views_R_t =
+    PackViewsRotationAndTranslation(tracks, *reconstruction);
 
   // Parameterization used to restrict camera motion for modal solvers.
   ceres::SubsetParameterization *constant_translation_parameterization = NULL;
@@ -365,37 +461,46 @@
 
   // Add residual blocks to the problem.
   int num_residuals = 0;
-  bool have_locked_camera = false;
+  bool have_locked_view = false;
   for (int i = 0; i < markers.size(); ++i) {
     const Marker &marker = markers[i];
-    EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
+    EuclideanView *view = reconstruction->ViewForImage(marker.image);
     EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
-    if (camera == NULL || point == NULL) {
+    if (view == NULL || point == NULL) {
       continue;
     }
 
+    int camera = view->camera;
+
     // Rotation of camera denoted in angle axis followed with
     // camera translaiton.
-    double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
+    double *current_view_R_t = &all_views_R_t[view->image](0);
 
+    OpenCVReprojectionError *cost_function;
+    if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
+      cost_function = new OpenCVReprojectionError(
+          marker.x, marker.y,
+          bundle_options.focal_length_min,
+          bundle_options.focal_length_max);
+    } else {
+      cost_function = new OpenCVReprojectionError(marker.x, marker.y);
+    }
+                                                  
     problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
-        OpenCVReprojectionError, 2, 8, 6, 3>(
-            new OpenCVReprojectionError(
-                marker.x,
-                marker.y)),
+        OpenCVReprojectionError, 2, 8, 6, 3>(cost_function),
         NULL,
-        ceres_intrinsics,
-        current_camera_R_t,
+        &ceres_intrinsics[camera](0),
+        current_view_R_t,
         &point->X(0));
 
     // We lock the first camera to better deal with scene orientation ambiguity.
-    if (!have_locked_camera) {
-      problem.SetParameterBlockConstant(current_camera_R_t);
-      have_locked_camera = true;
+    if (!have_locked_view) {
+      problem.SetParameterBlockConstant(current_view_R_t);
+      have_locked_view = true;
     }
 
     if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
-      problem.SetParameterization(current_camera_R_t,
+      problem.SetParameterization(current_view_R_t,
                                   constant_translation_parameterization);
     }
 
@@ -413,7 +518,7 @@
   if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
     // No camera intrinsics are being refined,
     // set the whole parameter block as constant for best performance.
-    problem.SetParameterBlockConstant(ceres_intrinsics);
+    problem.SetParameterBlockConstant(&ceres_intrinsics[0](0));
   } else {
     // Set the camera intrinsics that are not to be bundled as
     // constant using some macro trickery.
@@ -438,7 +543,11 @@
     ceres::SubsetParameterization *subset_parameterization =
       new ceres::SubsetParameterization(8, constant_intrinsics);
 
-    problem.SetParameterization(ceres_intrinsics, subset_parameterization);
+    problem.SetParameterization(&ceres_intrinsics[0](0), subset_parameterization);
+  }
+
+  for (int i = 1; i < ceres_intrinsics.size(); ++i) {
+    problem.SetParameterBlockConstant(&ceres_intrinsics[i](0));
   }
 
   // Configure the solver.
@@ -448,6 +557,9 @@
   options.linear_solver_type = ceres::ITERATIVE_SCHUR;
   options.use_inner_iterations = true;
   options.max_num_iterations = 100;
+  if (bundle_options.iteration_callback != NULL) {
+    options.callbacks.push_back(bundle_options.iteration_callback);
+  }
 
 #ifdef _OPENMP
   options.num_threads = omp_get_max_threads();
@@ -461,18 +573,20 @@
   LG << "Final report:\n" << summary.FullReport();
 
   // Copy rotations and translations back.
-  UnpackCamerasRotationAndTranslation(tracks,
-                                      all_cameras_R_t,
-                                      reconstruction);
+  UnpackViewsRotationAndTranslation(tracks,
+                                    all_views_R_t,
+                                    reconstruction);
 
   // Copy intrinsics back.
-  if (bundle_intrinsics != BUNDLE_NO_INTRINSICS)
-    UnpackIntrinsicsFromArray(ceres_intrinsics, intrinsics);
+  if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) {
+    intrinsics = UnpackIntrinsics(ceres_intrinsics,
+                                  bundle_options);
+  }
 
-  LG << "Final intrinsics: " << *intrinsics;
+  //LG << "Final intrinsics: " << *intrinsics;
 
   if (evaluation) {
-    EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t,
+    EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_views_R_t,
                                       &problem, evaluation);
   }
 }
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/bundle.h svn/extern/libmv/libmv/simple_pipeline/bundle.h
--- trunk/extern/libmv/libmv/simple_pipeline/bundle.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/bundle.h	2013-09-18 01:41:53.000000000 +0100
@@ -21,6 +21,10 @@
 #ifndef LIBMV_SIMPLE_PIPELINE_BUNDLE_H
 #define LIBMV_SIMPLE_PIPELINE_BUNDLE_H
 
+#include <vector>
+
+#include "ceres/types.h"
+#include "ceres/iteration_callback.h"
 #include "libmv/numeric/numeric.h"
 
 namespace libmv {
@@ -78,6 +82,27 @@
 /*!
     Refine camera poses and 3D coordinates using bundle adjustment.
 
+    This routine adjusts all cameras and points in \a *reconstruction. This
+    assumes a full observation for reconstructed tracks; this implies that if
+    there is a reconstructed 3D point (a bundle) for a track, then all markers
+    for that track will be included in the minimization. \a tracks should
+    contain markers used in the initial reconstruction.
+
+    The cameras and bundles (3D points), except the camera positions, are
+    refined in-place.
+
+    \note This assumes an outlier-free set of markers.
+    \note This assumes a calibrated reconstruction, e.g. the markers are
+          already corrected for camera intrinsics and radial distortion.
+
+    \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames
+*/
+void EuclideanBundleModal(const Tracks &tracks,
+                          EuclideanReconstruction *reconstruction);
+
+/*!
+    Refine camera poses and 3D coordinates using bundle adjustment.
+
     This routine adjusts all cameras positions, points, and the camera
     intrinsics (assumed common across all images) in \a *reconstruction. This
     assumes a full observation for reconstructed tracks; this implies that if
@@ -91,7 +116,7 @@
     For example it is useful to keep camera translations constant
     when bundling tripod motions.
 
-    If evaluaiton is not null, different evaluation statistics is filled in
+    If evaluation is not null, different evaluation statistics is filled in
     there, plus all the requested additional information (like jacobian) is
     also calculating there. Also see comments for BundleEvaluation.
 
@@ -110,15 +135,36 @@
   BUNDLE_TANGENTIAL_P2 = 32,
   BUNDLE_TANGENTIAL = 48,
 };
+
 enum BundleConstraints {
   BUNDLE_NO_CONSTRAINTS = 0,
   BUNDLE_NO_TRANSLATION = 1,
+  BUNDLE_CONSTRAIN_FOCAL_LENGTH = 2
+};
+
+struct BundleOptions {
+  BundleOptions();
+
+  // Bitfield denoting the camera intrinsics to adjust during
+  // bundling. Use BundleIntrinsics flags.
+  short bundle_intrinsics;
+
+  // Bitfield denoting the constraints to place on bundle parameters.
+  // Use BundleConstraints flags.
+  int constraints;
+
+  // Minimum and maximum constraints for the focal length. To be useful,
+  // BUNDLE_CONSTRAIN_FOCAL_LENGTH flag must be set on constraints.
+  double focal_length_min, focal_length_max;
+
+  // Callback which is called after each iteration of the solver.
+  ceres::IterationCallback *iteration_callback;
 };
+
 void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
-                                     const int bundle_intrinsics,
-                                     const int bundle_constraints,
+                                     const BundleOptions &bundle_options,
                                      EuclideanReconstruction *reconstruction,
-                                     CameraIntrinsics *intrinsics,
+                                     std::vector<CameraIntrinsics> &intrinsics,
                                      BundleEvaluation *evaluation = NULL);
 
 /*!
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc svn/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
--- trunk/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc	2013-09-14 11:24:31.000000000 +0100
@@ -32,15 +32,18 @@
 namespace libmv {
 namespace {
 
-void GetImagesInMarkers(const vector<Marker> &markers,
-                        int *image1, int *image2) {
+void GetImagesAndCamerasInMarkers(const vector<Marker> &markers,
+                                  int *image1, int *image2,
+                                  int *camera1, int *camera2) {
   if (markers.size() < 2) {
     return;
   }
   *image1 = markers[0].image;
+  *camera1 = markers[0].camera;
   for (int i = 1; i < markers.size(); ++i) {
     if (markers[i].image != *image1) {
       *image2 = markers[i].image;
+      *camera2 = markers[i].camera;
       return;
     }
   }
@@ -58,7 +61,8 @@
   }
 
   int image1, image2;
-  GetImagesInMarkers(markers, &image1, &image2);
+  int camera1, camera2;
+  GetImagesAndCamerasInMarkers(markers, &image1, &image2, &camera1, &camera2);
 
   Mat x1, x2;
   CoordinatesForMarkersInImage(markers, image1, &x1);
@@ -85,8 +89,8 @@
   }
 
   // Image 1 gets the reference frame, image 2 gets the relative motion.
-  reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero());
-  reconstruction->InsertCamera(image2, R, t);
+  reconstruction->InsertView(image1, Mat3::Identity(), Vec3::Zero(), camera1);
+  reconstruction->InsertView(image2, R, t, camera2);
 
   LG << "From two frame reconstruction got:\nR:\n" << R
      << "\nt:" << t.transpose();
@@ -146,7 +150,8 @@
   }
 
   int image1, image2;
-  GetImagesInMarkers(markers, &image1, &image2);
+  int camera1, camera2;
+  GetImagesAndCamerasInMarkers(markers, &image1, &image2, &camera1, &camera2);
 
   Mat x1, x2;
   CoordinatesForMarkersInImage(markers, image1, &x1);
@@ -186,8 +191,8 @@
   Mat34 P2;
   ProjectionsFromFundamental(F, &P1, &P2);
 
-  reconstruction->InsertCamera(image1, P1);
-  reconstruction->InsertCamera(image2, P2);
+  reconstruction->InsertView(image1, P1, camera1);
+  reconstruction->InsertView(image2, P2, camera2);
 
   LG << "From two frame reconstruction got P2:\n" << P2;
   return true;
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h svn/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
--- trunk/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h	2013-09-14 11:24:31.000000000 +0100
@@ -34,8 +34,8 @@
     two frames.
 
     \a markers should contain all \l Marker markers \endlink belonging to
-    tracks visible in both frames. The pose estimation of the camera for
-    these frames will be inserted into \a *reconstruction.
+    tracks visible in both frames from the same camera. The pose estimation of
+    the camera for these frames will be inserted into \a *reconstruction.
 
     \note The two frames need to have both enough parallax and enough common tracks
           for accurate reconstruction. At least 8 tracks are suggested.
@@ -55,8 +55,8 @@
     two frames.
 
     \a markers should contain all \l Marker markers \endlink belonging to
-    tracks visible in both frames. An estimate of the projection matrices for
-    the two frames will get added to the reconstruction.
+    tracks visible in both frames from the same camera. An estimate of the
+    projection matrices for the two frames will get added to the reconstruction.
 
     \note The two frames need to have both enough parallax and enough common tracks
           for accurate reconstruction. At least 8 tracks are suggested.
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/intersect.cc svn/extern/libmv/libmv/simple_pipeline/intersect.cc
--- trunk/extern/libmv/libmv/simple_pipeline/intersect.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/intersect.cc	2013-09-14 11:24:31.000000000 +0100
@@ -39,8 +39,8 @@
 class EuclideanIntersectCostFunctor {
  public:
   EuclideanIntersectCostFunctor(const Marker &marker,
-                                const EuclideanCamera &camera)
-      : marker_(marker), camera_(camera) {}
+                                const EuclideanView &view)
+      : marker_(marker), view_(view) {}
 
   template<typename T>
   bool operator()(const T *X, T *residuals) const {
@@ -48,8 +48,8 @@
     typedef Eigen::Matrix<T, 3, 1> Vec3;
 
     Vec3 x(X);
-    Mat3 R(camera_.R.cast<T>());
-    Vec3 t(camera_.t.cast<T>());
+    Mat3 R(view_.R.cast<T>());
+    Vec3 t(view_.t.cast<T>());
 
     Vec3 projected = R * x + t;
     projected /= projected(2);
@@ -61,7 +61,7 @@
   }
 
   const Marker &marker_;
-  const EuclideanCamera &camera_;
+  const EuclideanView &view_;
 };
 
 }  // namespace
@@ -78,8 +78,8 @@
   vector<Mat34> cameras;
   Mat34 P;
   for (int i = 0; i < markers.size(); ++i) {
-    EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
-    P_From_KRt(K, camera->R, camera->t, &P);
+    EuclideanView *view = reconstruction->ViewForImage(markers[i].image);
+    P_From_KRt(K, view->R, view->t, &P);
     cameras.push_back(P);
   }
 
@@ -102,14 +102,14 @@
 
   for (int i = 0; i < markers.size(); ++i) {
     const Marker &marker = markers[i];
-    const EuclideanCamera &camera =
-        *reconstruction->CameraForImage(marker.image);
+    const EuclideanView &view =
+        *reconstruction->ViewForImage(marker.image);
 
     problem.AddResidualBlock(
         new ceres::AutoDiffCostFunction<
             EuclideanIntersectCostFunctor,
             2, /* num_residuals */
-            3>(new EuclideanIntersectCostFunctor(marker, camera)),
+            3>(new EuclideanIntersectCostFunctor(marker, view)),
         NULL,
         &X(0));
   }
@@ -130,9 +130,9 @@
 
   // Try projecting the point; make sure it's in front of everyone.
   for (int i = 0; i < cameras.size(); ++i) {
-    const EuclideanCamera &camera =
-        *reconstruction->CameraForImage(markers[i].image);
-    Vec3 x = camera.R * X + camera.t;
+    const EuclideanView &view =
+        *reconstruction->ViewForImage(markers[i].image);
+    Vec3 x = view.R * X + view.t;
     if (x(2) < 0) {
       LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
                  << ": " << x.transpose();
@@ -163,9 +163,9 @@
     Vec residuals(2 * markers.size());
     residuals.setZero();
     for (int i = 0; i < markers.size(); ++i) {
-      const ProjectiveCamera &camera =
-          *reconstruction.CameraForImage(markers[i].image);
-      Vec3 projected = camera.P * X;
+      const ProjectiveView &view =
+          *reconstruction.ViewForImage(markers[i].image);
+      Vec3 projected = view.P * X;
       projected /= projected(2);
       residuals[2*i + 0] = projected(0) - markers[i].x;
       residuals[2*i + 1] = projected(1) - markers[i].y;
@@ -187,8 +187,8 @@
   // Get the cameras to use for the intersection.
   vector<Mat34> cameras;
   for (int i = 0; i < markers.size(); ++i) {
-    ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image);
-    cameras.push_back(camera->P);
+    ProjectiveView *view = reconstruction->ViewForImage(markers[i].image);
+    cameras.push_back(view->P);
   }
 
   // Stack the 2D coordinates together as required by NViewTriangulate.
@@ -214,9 +214,9 @@
 
   // Try projecting the point; make sure it's in front of everyone.
   for (int i = 0; i < cameras.size(); ++i) {
-    const ProjectiveCamera &camera =
-        *reconstruction->CameraForImage(markers[i].image);
-    Vec3 x = camera.P * X;
+    const ProjectiveView &view =
+        *reconstruction->ViewForImage(markers[i].image);
+    Vec3 x = view.P * X;
     if (x(2) < 0) {
       LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
                  << ": " << x.transpose();
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc svn/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc
--- trunk/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc	2013-09-18 10:21:40.000000000 +0100
@@ -20,6 +20,8 @@
 
 #include "libmv/simple_pipeline/keyframe_selection.h"
 
+#include <vector>
+
 #include "libmv/numeric/numeric.h"
 #include "ceres/ceres.h"
 #include "libmv/logging/logging.h"
@@ -97,7 +99,7 @@
 };
 
 void ComputeHomographyFromCorrespondences(const Mat &x1, const Mat &x2,
-                                          CameraIntrinsics &intrinsics,
+                                          const CameraIntrinsics &intrinsics,
                                           Mat3 *H) {
   // Algebraic homography estimation, happens with normalized coordinates
   Homography2DFromCorrespondencesLinear(x1, x2, H, 1e-12);
@@ -172,7 +174,7 @@
 };
 
 void ComputeFundamentalFromCorrespondences(const Mat &x1, const Mat &x2,
-                                           CameraIntrinsics &intrinsics,
+                                           const CameraIntrinsics &intrinsics,
                                            Mat3 *F) {
   // Algebraic fundamental estimation, happens with normalized coordinates
   NormalizedEightPointSolver(x1, x2, F);
@@ -288,15 +290,20 @@
 }
 }  // namespace
 
-void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
-                                           CameraIntrinsics &intrinsics,
-                                           vector<int> &keyframes) {
+void SelectKeyframesBasedOnGRICAndVariance(
+    const Tracks &tracks,
+    const std::vector<CameraIntrinsics> &intrinsics,
+    int camera,
+    vector<int> &keyframes) {
   // Mirza Tahir Ahmed, Matthew N. Dailey
   // Robust key frame extraction for 3D reconstruction from video streams
   //
   // http://www.cs.ait.ac.th/~mdailey/papers/Tahir-KeyFrame.pdf
 
-  int max_image = tracks.MaxImage();
+  Tracks camera_tracks(tracks.MarkersForCamera(camera));
+  const CameraIntrinsics &camera_intrinsics = intrinsics[camera];
+
+  int max_image = camera_tracks.MaxImage();
   int next_keyframe = 1;
   int number_keyframes = 0;
 
@@ -308,7 +315,7 @@
   const double Tmin = 0.8;
   const double Tmax = 1.0;
 
-  Mat3 N = IntrinsicsNormalizationMatrix(intrinsics);
+  Mat3 N = IntrinsicsNormalizationMatrix(camera_intrinsics);
   Mat3 N_inverse = N.inverse();
 
   double Sc_best = std::numeric_limits<double>::max();
@@ -328,11 +335,11 @@
          candidate_image++) {
       // Conjunction of all markers from both keyframes
       vector<Marker> all_markers =
-        tracks.MarkersInBothImages(current_keyframe, candidate_image);
+        camera_tracks.MarkersInBothImages(current_keyframe, candidate_image);
 
       // Match keypoints between frames current_keyframe and candidate_image
       vector<Marker> tracked_markers =
-        tracks.MarkersForTracksInBothImages(current_keyframe, candidate_image);
+        camera_tracks.MarkersForTracksInBothImages(current_keyframe, candidate_image);
 
       // Correspondences in normalized space
       Mat x1, x2;
@@ -360,8 +367,8 @@
         continue;
 
       Mat3 H, F;
-      ComputeHomographyFromCorrespondences(x1, x2, intrinsics, &H);
-      ComputeFundamentalFromCorrespondences(x1, x2, intrinsics, &F);
+      ComputeHomographyFromCorrespondences(x1, x2, camera_intrinsics, &H);
+      ComputeFundamentalFromCorrespondences(x1, x2, camera_intrinsics, &F);
 
       // TODO(sergey): STEP 2: Discard outlier matches
 
@@ -373,9 +380,9 @@
       F_e.resize(x1.cols());
       for (int i = 0; i < x1.cols(); i++) {
         Vec2 current_x1 =
-          NorrmalizedToPixelSpace(Vec2(x1(0, i), x1(1, i)), intrinsics);
+          NorrmalizedToPixelSpace(Vec2(x1(0, i), x1(1, i)), camera_intrinsics);
         Vec2 current_x2 =
-          NorrmalizedToPixelSpace(Vec2(x2(0, i), x2(1, i)), intrinsics);
+          NorrmalizedToPixelSpace(Vec2(x2(0, i), x2(1, i)), camera_intrinsics);
 
         H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2);
         F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2);
@@ -442,10 +449,11 @@
          << "\nt:" << t.transpose();
 
       // First camera is identity, second one is relative to it
-      reconstruction.InsertCamera(current_keyframe,
-                                  Mat3::Identity(),
-                                  Vec3::Zero());
-      reconstruction.InsertCamera(candidate_image, R, t);
+      reconstruction.InsertView(current_keyframe,
+                                Mat3::Identity(),
+                                Vec3::Zero(),
+                                camera);
+      reconstruction.InsertView(candidate_image, R, t, camera);
 
       // Reconstruct 3D points
       int intersects_total = 0, intersects_success = 0;
@@ -494,15 +502,15 @@
       success_intersects_factor_best = success_intersects_factor;
 
       Tracks two_frames_tracks(tracked_markers);
-      CameraIntrinsics empty_intrinsics;
+      std::vector<CameraIntrinsics> empty_intrinsics;
       BundleEvaluation evaluation;
       evaluation.evaluate_jacobian = true;
 
+      BundleOptions bundle_options;
       EuclideanBundleCommonIntrinsics(two_frames_tracks,
-                                      BUNDLE_NO_INTRINSICS,
-                                      BUNDLE_NO_CONSTRAINTS,
+                                      bundle_options,
                                       &reconstruction,
-                                      &empty_intrinsics,
+                                      empty_intrinsics,
                                       &evaluation);
 
       Mat &jacobian = evaluation.jacobian;
@@ -579,4 +587,11 @@
   }
 }
 
+void SelectKeyframesBasedOnGRICAndVariance(
+    const Tracks &tracks,
+    const std::vector<CameraIntrinsics> &intrinsics,
+    vector<int> &keyframes) {
+  SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, 0, keyframes);
+}
+
 }  // namespace libmv
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/keyframe_selection.h svn/extern/libmv/libmv/simple_pipeline/keyframe_selection.h
--- trunk/extern/libmv/libmv/simple_pipeline/keyframe_selection.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/keyframe_selection.h	2013-09-14 11:24:31.000000000 +0100
@@ -21,31 +21,42 @@
 #ifndef LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
 #define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
 
+#include <vector>
+
 #include "libmv/base/vector.h"
 #include "libmv/simple_pipeline/tracks.h"
 #include "libmv/simple_pipeline/camera_intrinsics.h"
 
 namespace libmv {
 
-// Get list of all images which are good enough to be as keyframes from
-// camera reconstruction. Based on GRIC criteria and uses Pollefeys'
-// approach for correspondence ratio constraint.
+// Get list of all images from given camera which are good enough to be as
+// keyframes for camera reconstruction. Based on GRIC criteria and uses
+// Pollefeys' approach for correspondence ratio constraint.
 //
-// As an additional, additional criteria based on reconstruction
-// variance is used. This means if correspondence and GRIC criteria
-// are passed, two-frames reconstruction using candidate keyframes
-// happens. After reconstruction variance of 3D points is calculating
-// and if expected error estimation is too large, keyframe candidate
-// is rejecting.
+// Additional criteria based on reconstruction variance are used. This means if
+// correspondence and GRIC criteria are passed, two-frame reconstruction using
+// candidate keyframes happens. After reconstruction, the variance of 3D points
+// is calculated and, if the expected error estimation is too large, the keyframe
+// candidate is rejected.
 //
 // \param tracks contains all tracked correspondences between frames
 //        expected to be undistorted and normalized
 // \param intrinsics is camera intrinsics
 // \param keyframes will contain all images number which are considered
 //        good to be used for reconstruction
-void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
-                                           CameraIntrinsics &intrinsics,
-                                           vector<int> &keyframes);
+//
+// TODO(sftrabbit): Use algorithm that finds images of high variance from
+//                  multiple cameras.
+void SelectKeyframesBasedOnGRICAndVariance(
+    const Tracks &tracks,
+    const std::vector<CameraIntrinsics> &intrinsics,
+    int camera,
+    vector<int> &keyframes);
+
+void SelectKeyframesBasedOnGRICAndVariance(
+    const Tracks &tracks,
+    const std::vector<CameraIntrinsics> &intrinsics,
+    vector<int> &keyframes);
 
 }  // namespace libmv
 
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/modal_solver.cc svn/extern/libmv/libmv/simple_pipeline/modal_solver.cc
--- trunk/extern/libmv/libmv/simple_pipeline/modal_solver.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/modal_solver.cc	2013-09-14 11:24:31.000000000 +0100
@@ -99,8 +99,11 @@
 void ModalSolver(const Tracks &tracks,
                  EuclideanReconstruction *reconstruction,
                  ProgressUpdateCallback *update_callback) {
-  int max_image = tracks.MaxImage();
-  int max_track = tracks.MaxTrack();
+  static const int kModalCamera = 0;
+  Tracks camera_tracks(tracks.MarkersForCamera(kModalCamera));
+
+  int max_image = camera_tracks.MaxImage();
+  int max_track = camera_tracks.MaxTrack();
 
   LG << "Max image: " << max_image;
   LG << "Max track: " << max_track;
@@ -111,12 +114,12 @@
   ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
 
   for (int image = 0; image <= max_image; ++image) {
-    vector<Marker> all_markers = tracks.MarkersInImage(image);
+    vector<Marker> image_markers = camera_tracks.MarkersInImage(image);
 
     ModalSolverLogProress(update_callback, (float) image / max_image);
 
     // Skip empty images without doing anything.
-    if (all_markers.size() == 0) {
+    if (image_markers.size() == 0) {
       LG << "Skipping image: " << image;
       continue;
     }
@@ -124,13 +127,12 @@
     // STEP 1: Estimate rotation analytically.
     Mat3 current_R;
     ceres::QuaternionToRotation(&quaternion(0), &current_R(0, 0));
-
     // Construct point cloud for current and previous images,
     // using markers appear at current image for which we know
     // 3D positions.
     Mat x1, x2;
-    for (int i = 0; i < all_markers.size(); ++i) {
-      Marker &marker = all_markers[i];
+    for (int i = 0; i < image_markers.size(); ++i) {
+      Marker &marker = image_markers[i];
       EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
       if (point) {
         Vec3 X;
@@ -176,8 +178,8 @@
         new ceres::QuaternionParameterization;
 
     int num_residuals = 0;
-    for (int i = 0; i < all_markers.size(); ++i) {
-      Marker &marker = all_markers[i];
+    for (int i = 0; i < image_markers.size(); ++i) {
+      Marker &marker = image_markers[i];
       EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
 
       if (point) {
@@ -218,7 +220,7 @@
     // Convert quaternion to rotation matrix.
     Mat3 R;
     ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
-    reconstruction->InsertCamera(image, R, Vec3::Zero());
+    reconstruction->InsertView(image, R, Vec3::Zero(), kModalCamera);
 
     // STEP 3: reproject all new markers appeared at image
 
@@ -226,7 +228,7 @@
     // and reproject them on sphere to obtain 3D position/
     for (int track = 0; track <= max_track; ++track) {
       if (!reconstruction->PointForTrack(track)) {
-        Marker marker = tracks.MarkerInImageForTrack(image, track);
+        Marker marker = camera_tracks.MarkerInImageForTrack(image, track);
 
         if (marker.image == image) {
           // New track appeared on this image,
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/modal_solver.h svn/extern/libmv/libmv/simple_pipeline/modal_solver.h
--- trunk/extern/libmv/libmv/simple_pipeline/modal_solver.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/modal_solver.h	2013-09-14 11:24:31.000000000 +0100
@@ -29,15 +29,16 @@
 
 /*!
     This solver solves such camera motion as tripod rotation, reconstructing
-    only camera motion itself. Bundles are not reconstructing properly, they're
-    just getting projected onto sphere.
+    only camera motion itself. Bundles are not reconstructing properly; they're
+    projected onto sphere.
 
-    Markers from tracks object would be used for recosntruction, and algorithm
-    assumes thir's positions are undistorted already and they're in nnormalized
-    space.
+    Markers from tracks object are used for reconstruction. The algorithm
+    assumes their positions are undistorted already and that they're in
+    normalized space.
 
-    Reconstructed cameras and projected bundles would be added to reconstruction
-    object.
+    Reconstructed cameras and projected bundles are added to the given
+    reconstruction object. Only camera 0 is reconstructed, using only the
+    markers associated with camera 0.
 */
 void ModalSolver(const Tracks &tracks,
                  EuclideanReconstruction *reconstruction,
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/pipeline.cc svn/extern/libmv/libmv/simple_pipeline/pipeline.cc
--- trunk/extern/libmv/libmv/simple_pipeline/pipeline.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/pipeline.cc	2013-09-14 12:02:39.000000000 +0100
@@ -43,7 +43,7 @@
 // template bloat and making interface changes much easier.
 struct EuclideanPipelineRoutines {
   typedef EuclideanReconstruction Reconstruction;
-  typedef EuclideanCamera Camera;
+  typedef EuclideanView View;
   typedef EuclideanPoint Point;
 
   static void Bundle(const Tracks &tracks,
@@ -63,9 +63,9 @@
   }
 
   static Marker ProjectMarker(const EuclideanPoint &point,
-                              const EuclideanCamera &camera,
+                              const EuclideanView &view,
                               const CameraIntrinsics &intrinsics) {
-    Vec3 projected = camera.R * point.X + camera.t;
+    Vec3 projected = view.R * point.X + view.t;
     projected /= projected(2);
 
     Marker reprojected_marker;
@@ -74,7 +74,7 @@
                                &reprojected_marker.x,
                                &reprojected_marker.y);
 
-    reprojected_marker.image = camera.image;
+    reprojected_marker.image = view.image;
     reprojected_marker.track = point.track;
     return reprojected_marker;
   }
@@ -82,7 +82,7 @@
 
 struct ProjectivePipelineRoutines {
   typedef ProjectiveReconstruction Reconstruction;
-  typedef ProjectiveCamera Camera;
+  typedef ProjectiveView View;
   typedef ProjectivePoint Point;
 
   static void Bundle(const Tracks &tracks,
@@ -105,9 +105,9 @@
   }
 
   static Marker ProjectMarker(const ProjectivePoint &point,
-                              const ProjectiveCamera &camera,
+                              const ProjectiveView &view,
                               const CameraIntrinsics &intrinsics) {
-    Vec3 projected = camera.P * point.X;
+    Vec3 projected = view.P * point.X;
     projected /= projected(2);
 
     Marker reprojected_marker;
@@ -116,7 +116,7 @@
                                &reprojected_marker.x,
                                &reprojected_marker.y);
 
-    reprojected_marker.image = camera.image;
+    reprojected_marker.image = view.image;
     reprojected_marker.track = point.track;
     return reprojected_marker;
   }
@@ -169,7 +169,7 @@
 
       vector<Marker> reconstructed_markers;
       for (int i = 0; i < all_markers.size(); ++i) {
-        if (reconstruction->CameraForImage(all_markers[i].image)) {
+        if (reconstruction->ViewForImage(all_markers[i].image)) {
           reconstructed_markers.push_back(all_markers[i]);
         }
       }
@@ -199,7 +199,7 @@
     // Do all possible resections.
     num_resects = 0;
     for (int image = 0; image <= max_image; ++image) {
-      if (reconstruction->CameraForImage(image)) {
+      if (reconstruction->ViewForImage(image)) {
         LG << "Skipping frame: " << image;
         continue;
       }
@@ -239,7 +239,7 @@
   // One last pass...
   num_resects = 0;
   for (int image = 0; image <= max_image; ++image) {
-    if (reconstruction->CameraForImage(image)) {
+    if (reconstruction->ViewForImage(image)) {
       LG << "Skipping frame: " << image;
       continue;
     }
@@ -275,24 +275,24 @@
 double InternalReprojectionError(
         const Tracks &image_tracks,
         const typename PipelineRoutines::Reconstruction &reconstruction,
-        const CameraIntrinsics &intrinsics) {
+        const std::vector<CameraIntrinsics> &intrinsics) {
   int num_skipped = 0;
   int num_reprojected = 0;
   double total_error = 0.0;
   vector<Marker> markers = image_tracks.AllMarkers();
   for (int i = 0; i < markers.size(); ++i) {
-    const typename PipelineRoutines::Camera *camera =
-        reconstruction.CameraForImage(markers[i].image);
+    const typename PipelineRoutines::View *view =
+        reconstruction.ViewForImage(markers[i].image);
     const typename PipelineRoutines::Point *point =
         reconstruction.PointForTrack(markers[i].track);
-    if (!camera || !point) {
+    if (!view || !point) {
       num_skipped++;
       continue;
     }
     num_reprojected++;
 
     Marker reprojected_marker =
-        PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
+        PipelineRoutines::ProjectMarker(*point, *view, intrinsics[markers[i].camera]);
     double ex = reprojected_marker.x - markers[i].x;
     double ey = reprojected_marker.y - markers[i].y;
 
@@ -326,16 +326,15 @@
 
 double EuclideanReprojectionError(const Tracks &image_tracks,
                                   const EuclideanReconstruction &reconstruction,
-                                  const CameraIntrinsics &intrinsics) {
+                                  const std::vector<CameraIntrinsics> &intrinsics) {
   return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
                                                               reconstruction,
                                                               intrinsics);
 }
 
-double ProjectiveReprojectionError(
-    const Tracks &image_tracks,
-    const ProjectiveReconstruction &reconstruction,
-    const CameraIntrinsics &intrinsics) {
+double ProjectiveReprojectionError(const Tracks &image_tracks,
+                                   const ProjectiveReconstruction &reconstruction,
+                                   const std::vector<CameraIntrinsics> &intrinsics) {
   return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
                                                                reconstruction,
                                                                intrinsics);
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/pipeline.h svn/extern/libmv/libmv/simple_pipeline/pipeline.h
--- trunk/extern/libmv/libmv/simple_pipeline/pipeline.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/pipeline.h	2013-09-14 11:24:31.000000000 +0100
@@ -21,6 +21,8 @@
 #ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
 #define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
 
+#include <vector>
+
 #include "libmv/simple_pipeline/callbacks.h"
 #include "libmv/simple_pipeline/tracks.h"
 #include "libmv/simple_pipeline/reconstruction.h"
@@ -90,12 +92,11 @@
 
 double EuclideanReprojectionError(const Tracks &image_tracks,
                                   const EuclideanReconstruction &reconstruction,
-                                  const CameraIntrinsics &intrinsics);
+                                  const std::vector<CameraIntrinsics> &intrinsics);
 
-double ProjectiveReprojectionError(
-    const Tracks &image_tracks,
-    const ProjectiveReconstruction &reconstruction,
-    const CameraIntrinsics &intrinsics);
+double ProjectiveReprojectionError(const Tracks &image_tracks,
+                                   const ProjectiveReconstruction &reconstruction,
+                                   const std::vector<CameraIntrinsics> &intrinsics);
 
 void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
                                const CameraIntrinsics &camera_intrinsics,
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/reconstruction.cc svn/extern/libmv/libmv/simple_pipeline/reconstruction.cc
--- trunk/extern/libmv/libmv/simple_pipeline/reconstruction.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/reconstruction.cc	2013-09-14 11:59:33.000000000 +0100
@@ -18,6 +18,8 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
+#include <vector>
+
 #include "libmv/simple_pipeline/reconstruction.h"
 #include "libmv/numeric/numeric.h"
 #include "libmv/logging/logging.h"
@@ -27,29 +29,32 @@
 EuclideanReconstruction::EuclideanReconstruction() {}
 EuclideanReconstruction::EuclideanReconstruction(
     const EuclideanReconstruction &other) {
-  cameras_ = other.cameras_;
+  views_ = other.views_;
   points_ = other.points_;
 }
 
 EuclideanReconstruction &EuclideanReconstruction::operator=(
     const EuclideanReconstruction &other) {
   if (&other != this) {
-    cameras_ = other.cameras_;
+    views_ = other.views_;
     points_ = other.points_;
   }
   return *this;
 }
 
-void EuclideanReconstruction::InsertCamera(int image,
-                                           const Mat3 &R,
-                                           const Vec3 &t) {
-  LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t;
-  if (image >= cameras_.size()) {
-    cameras_.resize(image + 1);
-  }
-  cameras_[image].image = image;
-  cameras_[image].R = R;
-  cameras_[image].t = t;
+void EuclideanReconstruction::InsertView(int image,
+                                         const Mat3 &R,
+                                         const Vec3 &t,
+                                         int camera) {
+  LG << "InsertView camera " << camera << ", image " << image
+     << ":\nR:\n"<< R << "\nt:\n" << t;
+  if (image >= views_.size()) {
+    views_.resize(image + 1);
+  }
+  views_[image].image = image;
+  views_[image].R = R;
+  views_[image].t = t;
+  views_[image].camera = camera;
 }
 
 void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
@@ -61,32 +66,43 @@
   points_[track].X = X;
 }
 
-EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) {
-  return const_cast<EuclideanCamera *>(
+EuclideanView *EuclideanReconstruction::ViewForImage(int image) {
+  return const_cast<EuclideanView *>(
       static_cast<const EuclideanReconstruction *>(
-          this)->CameraForImage(image));
+          this)->ViewForImage(image));
 }
 
-const EuclideanCamera *EuclideanReconstruction::CameraForImage(
-    int image) const {
-  if (image < 0 || image >= cameras_.size()) {
+const EuclideanView *EuclideanReconstruction::ViewForImage(int image) const {
+  if (image < 0 || image >= views_.size()) {
     return NULL;
   }
-  const EuclideanCamera *camera = &cameras_[image];
-  if (camera->image == -1) {
+  const EuclideanView *view = &views_[image];
+  if (view->camera == -1 || view->image == -1) {
     return NULL;
   }
-  return camera;
+  return view;
+}
+
+vector<EuclideanView> EuclideanReconstruction::AllViews(
+    ) const {
+  vector<EuclideanView> views;
+  for (int i = 0; i < views_.size(); ++i) {
+    if (views_[i].camera != -1 && views_[i].image != -1) {
+      views.push_back(views_[i]);
+    }
+  }
+  return views;
 }
 
-vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const {
-  vector<EuclideanCamera> cameras;
-  for (int i = 0; i < cameras_.size(); ++i) {
-    if (cameras_[i].image != -1) {
-      cameras.push_back(cameras_[i]);
+vector<EuclideanView> EuclideanReconstruction::AllViewsForCamera(
+    int camera) const {
+  vector<EuclideanView> views;
+  for (int i = 0; i < views_.size(); ++i) {
+    if (views_[i].image != -1 && views_[i].camera == camera) {
+      views.push_back(views_[i]);
     }
   }
-  return cameras;
+  return views;
 }
 
 EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
@@ -115,14 +131,17 @@
   return points;
 }
 
-void ProjectiveReconstruction::InsertCamera(int image,
-                                           const Mat34 &P) {
-  LG << "InsertCamera " << image << ":\nP:\n"<< P;
-  if (image >= cameras_.size()) {
-    cameras_.resize(image + 1);
-  }
-  cameras_[image].image = image;
-  cameras_[image].P = P;
+void ProjectiveReconstruction::InsertView(int image,
+                                          const Mat34 &P,
+                                          int camera) {
+  LG << "InsertView camera " << camera << ", image " << image
+     << ":\nP:\n"<< P;
+  if (image >= views_.size()) {
+    views_.resize(image + 1);
+  }
+  views_[image].image = image;
+  views_[image].P = P;
+  views_[image].camera = camera;
 }
 
 void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
@@ -134,32 +153,42 @@
   points_[track].X = X;
 }
 
-ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) {
-  return const_cast<ProjectiveCamera *>(
+ProjectiveView *ProjectiveReconstruction::ViewForImage(int image) {
+  return const_cast<ProjectiveView *>(
       static_cast<const ProjectiveReconstruction *>(
-          this)->CameraForImage(image));
+          this)->ViewForImage(image));
 }
 
-const ProjectiveCamera *ProjectiveReconstruction::CameraForImage(
-    int image) const {
-  if (image < 0 || image >= cameras_.size()) {
+const ProjectiveView *ProjectiveReconstruction::ViewForImage(int image) const {
+  if (image < 0 || image >= views_.size()) {
     return NULL;
   }
-  const ProjectiveCamera *camera = &cameras_[image];
-  if (camera->image == -1) {
+  const ProjectiveView *view = &views_[image];
+  if (view->camera == -1 || view->image == -1) {
     return NULL;
   }
-  return camera;
+  return view;
+}
+
+vector<ProjectiveView> ProjectiveReconstruction::AllViews() const {
+  vector<ProjectiveView> views;
+  for (int i = 0; i < views_.size(); ++i) {
+    if (views_[i].camera != 1 && views_[i].image != -1) {
+      views.push_back(views_[i]);
+    }
+  }
+  return views;
 }
 
-vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const {
-  vector<ProjectiveCamera> cameras;
-  for (int i = 0; i < cameras_.size(); ++i) {
-    if (cameras_[i].image != -1) {
-      cameras.push_back(cameras_[i]);
+vector<ProjectiveView> ProjectiveReconstruction::AllViewsForCamera(
+    int camera) const {
+  vector<ProjectiveView> views;
+  for (int i = 0; i < views_.size(); ++i) {
+    if (views_[i].image != -1 && views_[i].camera == camera) {
+      views.push_back(views_[i]);
     }
   }
-  return cameras;
+  return views;
 }
 
 ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/reconstruction.h svn/extern/libmv/libmv/simple_pipeline/reconstruction.h
--- trunk/extern/libmv/libmv/simple_pipeline/reconstruction.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/reconstruction.h	2013-09-14 11:24:31.000000000 +0100
@@ -21,6 +21,8 @@
 #ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
 #define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
 
+#include <vector>
+
 #include "libmv/base/vector.h"
 #include "libmv/numeric/numeric.h"
 
@@ -38,21 +40,28 @@
 };
 
 /*!
-    A EuclideanCamera is the location and rotation of the camera viewing \a image.
+    A EuclideanView is the location and orientation of a camera viewing an
+    \a image. A EuclideanView may be associated with a particular \a camera for
+    a multicamera reconstruction. All EuclideanViews for the same \a camera
+    represent the motion of a particular video camera across all of its
+    corresponding images.
 
-    \a image identify which image from \l Tracks this camera represents.
-    \a R is a 3x3 matrix representing the rotation of the camera.
+    \a image identify which image from \l Tracks this view represents.
+    \a R is a 3x3 matrix representing the rotation of the view.
     \a t is a translation vector representing its positions.
+    \a camera identify which camera from \l Tracks this view is associated with.
 
     \sa Reconstruction
 */
-struct EuclideanCamera {
-  EuclideanCamera() : image(-1) {}
-  EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {}
+struct EuclideanView {
+  EuclideanView() : image(-1), camera(0) {}
+  EuclideanView(const EuclideanView &v)
+      : image(v.image), R(v.R), t(v.t), camera(v.camera) {}
 
   int image;
   Mat3 R;
   Vec3 t;
+  int camera;
 };
 
 /*!
@@ -71,16 +80,16 @@
 };
 
 /*!
-    The EuclideanReconstruction class stores \link EuclideanCamera cameras
+    The EuclideanReconstruction class stores \link EuclideanView views
     \endlink and \link EuclideanPoint points \endlink.
 
     The EuclideanReconstruction container is intended as the store of 3D
     reconstruction data to be used with the MultiView API.
 
-    The container has lookups to query a \a EuclideanCamera from an \a image or
-    a \a EuclideanPoint from a \a track.
+    The container has lookups to query a \a EuclideanView for an \a image, or a
+    \a EuclideanPoint from a \a track.
 
-    \sa Camera, Point
+    \sa View, Point
 */
 class EuclideanReconstruction {
  public:
@@ -93,16 +102,20 @@
   EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
 
   /*!
-      Insert a camera into the set. If there is already a camera for the given
-      \a image, the existing camera is replaced. If there is no camera for the
-      given \a image, a new one is added.
+      Insert a view into the set. If there is already a view for the given
+      \a image, the existing view is replaced. If there is no view for the given
+      \a image, a new one is added. A view may be associated with a \a camera
+      in a multicamera reconstruction.
 
-      \a image is the key used to retrieve the cameras with the other methods
-      in this class.
+      \a image and \a camera are the keys used to retrieve the views with the
+      other methods in this class.
 
-      \note You should use the same \a image identifier as in \l Tracks.
+      \note You should use the same \a camera and \a image identifiers as in
+            \l Tracks.
+      \note All markers for a single \a image should have the same \a camera
+            identifiers.
   */
-  void InsertCamera(int image, const Mat3 &R, const Vec3 &t);
+  void InsertView(int image, const Mat3 &R, const Vec3 &t, int camera = 0);
 
   /*!
       Insert a point into the reconstruction. If there is already a point for
@@ -116,12 +129,15 @@
   */
   void InsertPoint(int track, const Vec3 &X);
 
-  /// Returns a pointer to the camera corresponding to \a image.
-  EuclideanCamera *CameraForImage(int image);
-  const EuclideanCamera *CameraForImage(int image) const;
+  /// Returns a pointer to the view corresponding to \a image.
+  EuclideanView *ViewForImage(int image);
+  const EuclideanView *ViewForImage(int image) const;
+
+  /// Returns all views for all images.
+  vector<EuclideanView> AllViews() const;
 
-  /// Returns all cameras.
-  vector<EuclideanCamera> AllCameras() const;
+  /// Returns all views for a particular \a camera.
+  vector<EuclideanView> AllViewsForCamera(int camera) const;
 
   /// Returns a pointer to the point corresponding to \a track.
   EuclideanPoint *PointForTrack(int track);
@@ -131,24 +147,31 @@
   vector<EuclideanPoint> AllPoints() const;
 
  private:
-  vector<EuclideanCamera> cameras_;
+  vector<EuclideanView> views_;
   vector<EuclideanPoint> points_;
 };
 
 /*!
-    A ProjectiveCamera is the projection matrix for the camera of \a image.
+    A ProjectiveView is the projection matrix for the view of an \a image. A
+    ProjectiveView may be associated with a particular \a camera for a
+    multicamera reconstruction. All ProjectiveViews for the same \a camera
+    represent the motion of a particular video camera across all of its
+    corresponding images.
 
-    \a image identify which image from \l Tracks this camera represents.
+    \a image identify which image from \l Tracks this view represents.
     \a P is the 3x4 projection matrix.
+    \a camera identify which camera from \l Tracks this view is associated with.
 
     \sa ProjectiveReconstruction
 */
-struct ProjectiveCamera {
-  ProjectiveCamera() : image(-1) {}
-  ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {}
+struct ProjectiveView {
+  ProjectiveView() : image(-1), camera(0) {}
+  ProjectiveView(const ProjectiveView &v)
+      : image(v.image), P(v.P), camera(v.camera) {}
 
   int image;
   Mat34 P;
+  int camera;
 };
 
 /*!
@@ -167,30 +190,34 @@
 };
 
 /*!
-    The ProjectiveReconstruction class stores \link ProjectiveCamera cameras
+    The ProjectiveReconstruction class stores \link ProjectiveView views
     \endlink and \link ProjectivePoint points \endlink.
 
     The ProjectiveReconstruction container is intended as the store of 3D
     reconstruction data to be used with the MultiView API.
 
-    The container has lookups to query a \a ProjectiveCamera from an \a image or
+    The container has lookups to query a \a ProjectiveView for an \a image, or
     a \a ProjectivePoint from a \a track.
 
-    \sa Camera, Point
+    \sa View, Point
 */
 class ProjectiveReconstruction {
  public:
   /*!
-      Insert a camera into the set. If there is already a camera for the given
-      \a image, the existing camera is replaced. If there is no camera for the
-      given \a image, a new one is added.
+      Insert a view into the set. If there is already a view for the given
+      \a image, the existing view is replaced. If there is no view for the given
+      \a image, a new one is added. A view may be associated with a \a camera
+      in a multicamera reconstruction.
 
-      \a image is the key used to retrieve the cameras with the other methods
-      in this class.
+      \a image and \a camera are the keys used to retrieve the views with the
+      other methods in this class.
 
-      \note You should use the same \a image identifier as in \l Tracks.
+      \note You should use the same \a camera and \a image identifiers as in
+            \l Tracks.
+      \note All markers for a single \a image should have the same \a camera
+            identifiers.
   */
-  void InsertCamera(int image, const Mat34 &P);
+  void InsertView(int image, const Mat34 &P, int camera = 0);
 
   /*!
       Insert a point into the reconstruction. If there is already a point for
@@ -204,12 +231,15 @@
   */
   void InsertPoint(int track, const Vec4 &X);
 
-  /// Returns a pointer to the camera corresponding to \a image.
-  ProjectiveCamera *CameraForImage(int image);
-  const ProjectiveCamera *CameraForImage(int image) const;
+  /// Returns a pointer to the view corresponding to \a image.
+  ProjectiveView *ViewForImage(int image);
+  const ProjectiveView *ViewForImage(int image) const;
+
+  /// Returns all views.
+  vector<ProjectiveView> AllViews() const;
 
-  /// Returns all cameras.
-  vector<ProjectiveCamera> AllCameras() const;
+  /// Returns all views for a particular \a camera.
+  vector<ProjectiveView> AllViewsForCamera(int camera) const;
 
   /// Returns a pointer to the point corresponding to \a track.
   ProjectivePoint *PointForTrack(int track);
@@ -219,7 +249,7 @@
   vector<ProjectivePoint> AllPoints() const;
 
  private:
-  vector<ProjectiveCamera> cameras_;
+  vector<ProjectiveView> views_;
   vector<ProjectivePoint> points_;
 };
 
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc svn/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
--- trunk/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc	2013-09-14 12:00:11.000000000 +0100
@@ -24,37 +24,37 @@
 namespace libmv {
 
 void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) {
-  vector<EuclideanCamera> all_cameras = reconstruction->AllCameras();
+  vector<EuclideanView> all_views = reconstruction->AllViews();
   vector<EuclideanPoint> all_points = reconstruction->AllPoints();
 
-  // Calculate center of the mass of all cameras.
-  Vec3 cameras_mass_center = Vec3::Zero();
-  for (int i = 0; i < all_cameras.size(); ++i) {
-    cameras_mass_center += all_cameras[i].t;
+  // Calculate center of the mass of all views.
+  Vec3 views_mass_center = Vec3::Zero();
+  for (int i = 0; i < all_views.size(); ++i) {
+    views_mass_center += all_views[i].t;
   }
-  cameras_mass_center /= all_cameras.size();
+  views_mass_center /= all_views.size();
 
-  // Find the most distant camera from the mass center.
+  // Find the most distant view from the mass center.
   double max_distance = 0.0;
-  for (int i = 0; i < all_cameras.size(); ++i) {
-    double distance = (all_cameras[i].t - cameras_mass_center).squaredNorm();
+  for (int i = 0; i < all_views.size(); ++i) {
+    double distance = (all_views[i].t - views_mass_center).squaredNorm();
     if (distance > max_distance) {
       max_distance = distance;
     }
   }
 
   if (max_distance == 0.0) {
-    LG << "Cameras position variance is too small, can not rescale";
+    LG << "Views position variance is too small, can not rescale";
     return;
   }
 
   double scale_factor = 1.0 / sqrt(max_distance);
 
-  // Rescale cameras positions.
-  for (int i = 0; i < all_cameras.size(); ++i) {
-    int image = all_cameras[i].image;
-    EuclideanCamera *camera = reconstruction->CameraForImage(image);
-    camera->t = camera->t * scale_factor;
+  // Rescale views positions.
+  for (int i = 0; i < all_views.size(); ++i) {
+    int image = all_views[i].image;
+    EuclideanView *view = reconstruction->ViewForImage(image);
+    view->t = view->t * scale_factor;
   }
 
   // Rescale points positions.
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/resect.cc svn/extern/libmv/libmv/simple_pipeline/resect.cc
--- trunk/extern/libmv/libmv/simple_pipeline/resect.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/resect.cc	2013-09-14 11:24:31.000000000 +0100
@@ -183,7 +183,7 @@
 
   LG << "Resection for image " << markers[0].image << " got:\n"
      << "R:\n" << R << "\nt:\n" << t;
-  reconstruction->InsertCamera(markers[0].image, R, t);
+  reconstruction->InsertView(markers[0].image, R, t, markers[0].camera);
   return true;
 }
 
@@ -273,7 +273,7 @@
 
   LG << "Resection for image " << markers[0].image << " got:\n"
      << "P:\n" << P;
-  reconstruction->InsertCamera(markers[0].image, P);
+  reconstruction->InsertView(markers[0].image, P, markers[0].camera);
   return true;
 }
 }  // namespace libmv
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/tracks.cc svn/extern/libmv/libmv/simple_pipeline/tracks.cc
--- trunk/extern/libmv/libmv/simple_pipeline/tracks.cc	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/tracks.cc	2013-09-14 11:24:31.000000000 +0100
@@ -23,6 +23,7 @@
 #include <algorithm>
 #include <vector>
 #include <iterator>
+#include <cstdio>
 
 #include "libmv/numeric/numeric.h"
 
@@ -34,7 +35,7 @@
 
 Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
 
-void Tracks::Insert(int image, int track, double x, double y) {
+void Tracks::Insert(int image, int track, double x, double y, int camera) {
   // TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
   // adding a smarter data structure like a set<>.
   for (int i = 0; i < markers_.size(); ++i) {
@@ -45,7 +46,7 @@
       return;
     }
   }
-  Marker marker = { image, track, x, y };
+  Marker marker = { image, track, x, y, camera };
   markers_.push_back(marker);
 }
 
@@ -73,12 +74,23 @@
   return markers;
 }
 
+vector<Marker> Tracks::MarkersForCamera(int camera) const {
+  vector<Marker> markers;
+  for (int i = 0; i < markers_.size(); ++i) {
+    if (camera == markers_[i].camera) {
+      markers.push_back(markers_[i]);
+    }
+  }
+  return markers;
+}
+
 vector<Marker> Tracks::MarkersInBothImages(int image1, int image2) const {
   vector<Marker> markers;
   for (int i = 0; i < markers_.size(); ++i) {
     int image = markers_[i].image;
-    if (image == image1 || image == image2)
+    if (image == image1 || image == image2) {
       markers.push_back(markers_[i]);
+    }
   }
   return markers;
 }
@@ -118,14 +130,25 @@
 
 Marker Tracks::MarkerInImageForTrack(int image, int track) const {
   for (int i = 0; i < markers_.size(); ++i) {
-    if (markers_[i].image == image && markers_[i].track == track) {
+    if (markers_[i].image == image &&
+        markers_[i].track == track) {
       return markers_[i];
     }
   }
-  Marker null = { -1, -1, -1, -1 };
+  Marker null = { -1, -1, -1, -1, -1 };
   return null;
 }
 
+void Tracks::RemoveMarkersInImage(int image) {
+  int size = 0;
+  for (int i = 0; i < markers_.size(); ++i) {
+    if (markers_[i].image != image) {
+      markers_[size++] = markers_[i];
+    }
+  }
+  markers_.resize(size);
+}
+
 void Tracks::RemoveMarkersForTrack(int track) {
   int size = 0;
   for (int i = 0; i < markers_.size(); ++i) {
@@ -136,16 +159,36 @@
   markers_.resize(size);
 }
 
+void Tracks::RemoveMarkersForCamera(int camera) {
+  int size = 0;
+  for (int i = 0; i < markers_.size(); ++i) {
+    if (markers_[i].camera != camera) {
+      markers_[size++] = markers_[i];
+    }
+  }
+  markers_.resize(size);
+}
+
 void Tracks::RemoveMarker(int image, int track) {
   int size = 0;
   for (int i = 0; i < markers_.size(); ++i) {
-    if (markers_[i].image != image || markers_[i].track != track) {
+    if (markers_[i].image != image ||
+        markers_[i].track != track) {
       markers_[size++] = markers_[i];
     }
   }
   markers_.resize(size);
 }
 
+int Tracks::CameraFromImage(int image) const {
+  for (int i = 0; i < markers_.size(); ++i) {
+    if (markers_[i].image == image) {
+      return markers_[i].camera;
+    }
+  }
+  return -1;
+}
+
 int Tracks::MaxImage() const {
   // TODO(MatthiasF): maintain a max_image_ member (updated on Insert)
   int max_image = 0;
@@ -164,6 +207,15 @@
   return max_track;
 }
 
+int Tracks::MaxCamera() const {
+  // TODO(MatthiasF): maintain a max_camera_ member (updated on Insert)
+  int max_camera = 0;
+  for (int i = 0; i < markers_.size(); ++i) {
+    max_camera = std::max(markers_[i].camera, max_camera);
+  }
+  return max_camera;
+}
+
 int Tracks::NumMarkers() const {
   return markers_.size();
 }
@@ -174,7 +226,7 @@
   vector<Vec2> coords;
   for (int i = 0; i < markers.size(); ++i) {
     const Marker &marker = markers[i];
-    if (markers[i].image == image) {
+    if (marker.image == image) {
       coords.push_back(Vec2(marker.x, marker.y));
     }
   }
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv/simple_pipeline/tracks.h svn/extern/libmv/libmv/simple_pipeline/tracks.h
--- trunk/extern/libmv/libmv/simple_pipeline/tracks.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv/simple_pipeline/tracks.h	2013-09-14 11:24:31.000000000 +0100
@@ -30,8 +30,11 @@
     A Marker is the 2D location of a tracked point in an image.
 
     \a x, \a y is the position of the marker in pixels from the top left corner
-    in the image identified by \a image. All markers for to the same target
-    form a track identified by a common \a track number.
+    of the image identified by \a image. All markers for the same target form a
+    track identified by a common \a track number. All markers for a single
+    \a image can be associated with a particular camera identified by \a camera.
+    Markers for a particular track but with different \a camera numbers
+    correspond to the same target filmed from an alternate viewpoint.
 
     \note Markers are typically aggregated with the help of the \l Tracks class.
 
@@ -41,6 +44,7 @@
   int image;
   int track;
   double x, y;
+  int camera;
 };
 
 /*!
@@ -67,29 +71,36 @@
   /*!
       Inserts a marker into the set. If there is already a marker for the given
       \a image and \a track, the existing marker is replaced. If there is no
-      marker for the given \a image and \a track, a new one is added.
+      marker for the given \a image and \a track, a new one is added. The marker
+      can be associated with a \a camera for use with multicamera reconsturction.
 
-      \a image and \a track are the keys used to retrieve the markers with the
-      other methods in this class.
+      \a camera, \a image and \a track are the keys used to retrieve the markers
+      with the other methods in this class.
 
       \note To get an identifier for a new track, use \l MaxTrack() + 1.
+      \note All markers for a single \a image should belong to the same
+            \a camera.
   */
-  void Insert(int image, int track, double x, double y);
+  void Insert(int image, int track, double x, double y, int camera = 0);
 
   /// Returns all the markers.
   vector<Marker> AllMarkers() const;
 
+  /// Returns all the markers visible in an \a image.
+  vector<Marker> MarkersInImage(int image) const;
+
   /// Returns all the markers belonging to a track.
   vector<Marker> MarkersForTrack(int track) const;
 
-  /// Returns all the markers visible in \a image.
-  vector<Marker> MarkersInImage(int image) const;
+  /// Returns all the markers visible from a \a camera.
+  vector<Marker> MarkersForCamera(int camera) const;
 
   /// Returns all the markers visible in \a image1 and \a image2.
   vector<Marker> MarkersInBothImages(int image1, int image2) const;
 
   /*!
-      Returns the markers in \a image1 and \a image2 which have a common track.
+      Returns the markers in \a image1 and \a image2 (both from \a camera) which
+      have a common track.
 
       This is not the same as the union of the markers in \a image1 and \a
       image2; each marker is for a track that appears in both images.
@@ -99,18 +110,30 @@
   /// Returns the marker in \a image belonging to \a track.
   Marker MarkerInImageForTrack(int image, int track) const;
 
+  /// Removes all the markers belonging to \a image.
+  void RemoveMarkersInImage(int image);
+
   /// Removes all the markers belonging to \a track.
   void RemoveMarkersForTrack(int track);
 
-  /// Removes the marker in \a image belonging to \a track.
+  /// Removes all the markers belonging to \a camera.
+  void RemoveMarkersForCamera(int camera);
+
+  /// Removes the marker in \a image of \a camera belonging to \a track.
   void RemoveMarker(int image, int track);
 
+  /// Returns the camera that \a image belongs to.
+  int CameraFromImage(int image) const;
+
   /// Returns the maximum image identifier used.
   int MaxImage() const;
 
   /// Returns the maximum track identifier used.
   int MaxTrack() const;
 
+  /// Returns the maximum camera identifier used.
+  int MaxCamera() const;
+
   /// Returns the number of markers.
   int NumMarkers() const;
 
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv-capi.cc svn/extern/libmv/libmv-capi.cc
--- trunk/extern/libmv/libmv-capi.cc	2013-09-22 13:27:12.000000000 +0100
+++ svn/extern/libmv/libmv-capi.cc	2013-09-18 01:40:52.000000000 +0100
@@ -36,6 +36,8 @@
 
 #include "libmv-capi.h"
 
+#include <vector>
+
 #include <cstdlib>
 #include <cassert>
 
@@ -69,7 +71,7 @@
 
 	/* used for per-track average error calculation after reconstruction */
 	libmv::Tracks tracks;
-	libmv::CameraIntrinsics intrinsics;
+	std::vector<libmv::CameraIntrinsics> intrinsics;
 
 	double error;
 };
@@ -398,13 +400,24 @@
 	delete (libmv::Tracks*) libmv_tracks;
 }
 
-void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y)
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y, int camera)
 {
-	((libmv::Tracks*) libmv_tracks)->Insert(image, track, x, y);
+	((libmv::Tracks*)libmv_tracks)->Insert(image, track, x, y, camera);
 }
 
 /* ************ Reconstruction ************ */
 
+class LoggingCallback : public ceres::IterationCallback {
+ public:
+  ~LoggingCallback() {}
+
+  ceres::CallbackReturnType operator()(const ceres::IterationSummary &summary) {
+    LG << "Iteration #" << summary.iteration
+       << ": " << summary.cost;
+    return ceres::SOLVER_CONTINUE;
+  }
+};
+
 class ReconstructUpdateCallback : public libmv::ProgressUpdateCallback {
 public:
 	ReconstructUpdateCallback(reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
@@ -424,39 +437,6 @@
 	void *callback_customdata_;
 };
 
-static void libmv_solveRefineIntrinsics(const libmv::Tracks &tracks,
-                                        const int refine_intrinsics,
-                                        const int bundle_constraints,
-                                        reconstruct_progress_update_cb progress_update_callback,
-                                        void *callback_customdata,
-                                        libmv::EuclideanReconstruction *reconstruction,
-                                        libmv::CameraIntrinsics *intrinsics)
-{
-	/* only a few combinations are supported but trust the caller */
-	int bundle_intrinsics = 0;
-
-	if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
-		bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH;
-	}
-	if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
-		bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
-	}
-	if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) {
-		bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1;
-	}
-	if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
-		bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2;
-	}
-
-	progress_update_callback(callback_customdata, 1.0, "Refining solution");
-
-	libmv::EuclideanBundleCommonIntrinsics(tracks,
-	                                       bundle_intrinsics,
-	                                       bundle_constraints,
-	                                       reconstruction,
-	                                       intrinsics);
-}
-
 static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
                                         libmv::CameraIntrinsics *camera_intrinsics)
 {
@@ -474,81 +454,80 @@
 	                                camera_intrinsics_options->image_height);
 }
 
-static libmv::Tracks getNormalizedTracks(const libmv::Tracks &tracks, const libmv::CameraIntrinsics &camera_intrinsics)
+static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions camera_intrinsics_options[],
+                                        int num_cameras,
+                                        std::vector<libmv::CameraIntrinsics> &camera_intrinsics)
+{
+	for (int i = 0; i < num_cameras; ++i) {
+		camera_intrinsics.push_back(libmv::CameraIntrinsics());
+	  cameraIntrinsicsFromOptions(camera_intrinsics_options, &camera_intrinsics[i]);
+	}
+}
+
+static libmv::Tracks getNormalizedTracks(const libmv::Tracks &tracks,
+                                         const std::vector<libmv::CameraIntrinsics> &camera_intrinsics)
 {
 	libmv::vector<libmv::Marker> markers = tracks.AllMarkers();
 
 	for (int i = 0; i < markers.size(); ++i) {
-		camera_intrinsics.InvertIntrinsics(markers[i].x, markers[i].y,
+    int camera = markers[i].camera;
+		camera_intrinsics[camera].InvertIntrinsics(markers[i].x, markers[i].y,
 			&(markers[i].x), &(markers[i].y));
 	}
 
 	return libmv::Tracks(markers);
 }
 
-static void finishReconstruction(const libmv::Tracks &tracks, const libmv::CameraIntrinsics &camera_intrinsics,
-                                 struct libmv_Reconstruction *libmv_reconstruction,
-                                 reconstruct_progress_update_cb progress_update_callback,
-                                 void *callback_customdata)
-{
-	libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
-
-	/* reprojection error calculation */
-	progress_update_callback(callback_customdata, 1.0, "Finishing solution");
-	libmv_reconstruction->tracks = tracks;
-	libmv_reconstruction->error = libmv::EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
-}
-
-static bool selectTwoKeyframesBasedOnGRICAndVariance(
-                          libmv::Tracks &tracks,
-                          libmv::Tracks &normalized_tracks,
-                          libmv::CameraIntrinsics &camera_intrinsics,
-                          libmv::ReconstructionOptions &reconstruction_options,
-                          int &keyframe1,
-                          int &keyframe2)
+static bool selectTwoInitialImages(
+		libmv::Tracks &tracks,
+		libmv::Tracks &normalized_tracks,
+		std::vector<libmv::CameraIntrinsics> &camera_intrinsics,
+		libmv::ReconstructionOptions &reconstruction_options,
+		int &image1,
+		int &image2)
 {
-	libmv::vector<int> keyframes;
+	libmv::vector<int> images;
 
-	/* Get list of all keyframe candidates first. */
+	/* Get list of all image candidates first. */
 	SelectKeyframesBasedOnGRICAndVariance(normalized_tracks,
-	                                      camera_intrinsics,
-	                                      keyframes);
+	                                   camera_intrinsics,
+	                                   images);
 
-	if (keyframes.size() < 2) {
+	if (images.size() < 2) {
 		LG << "Not enough keyframes detected by GRIC";
 		return false;
 	}
-	else if (keyframes.size() == 2) {
-		keyframe1 = keyframes[0];
-		keyframe2 = keyframes[1];
+	else if (images.size() == 2) {
+		image1 = images[0];
+		image2 = images[1];
 		return true;
 	}
 
-	/* Now choose two keyframes with minimal reprojection error after initial
-	 * reconstruction choose keyframes with the least reprojection error after
-	 * solving from two candidate keyframes.
+	/* Now choose two images with minimal reprojection error after initial
+	 * reconstruction choose images with the least reprojection error after
+	 * solving from two candidate images.
 	 *
 	 * In fact, currently libmv returns single pair only, so this code will
 	 * not actually run. But in the future this could change, so let's stay
 	 * prepared.
 	 */
-	int previous_keyframe = keyframes[0];
+	int previous_image = images[0];
 	double best_error = std::numeric_limits<double>::max();
-	for (int i = 1; i < keyframes.size(); i++) {
+	for (int i = 1; i < images.size(); i++) {
 		libmv::EuclideanReconstruction reconstruction;
-		int current_keyframe = keyframes[i];
+		int current_image = images[i];
 
-		libmv::vector<libmv::Marker> keyframe_markers =
-			normalized_tracks.MarkersForTracksInBothImages(previous_keyframe,
-			                                               current_keyframe);
+		libmv::vector<libmv::Marker> image_markers =
+			normalized_tracks.MarkersForTracksInBothImages(previous_image,
+			                                               current_image);
 
-		libmv::Tracks keyframe_tracks(keyframe_markers);
+		libmv::Tracks image_tracks(image_markers);
 
-		/* get a solution from two keyframes only */
-		libmv::EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
-		libmv::EuclideanBundle(keyframe_tracks, &reconstruction);
+		/* get a solution from two images only */
+		libmv::EuclideanReconstructTwoFrames(image_markers, &reconstruction);
+		libmv::EuclideanBundle(image_tracks, &reconstruction);
 		libmv::EuclideanCompleteReconstruction(reconstruction_options,
-		                                       keyframe_tracks,
+		                                       image_tracks,
 		                                       &reconstruction, NULL);
 
 		double current_error =
@@ -556,39 +535,88 @@
 			                                  reconstruction,
 			                                  camera_intrinsics);
 
-		LG << "Error between " << previous_keyframe
-		   << " and " << current_keyframe
+		LG << "Error between " << previous_image
+		   << " and " << current_image
 		   << ": " << current_error;
 
 		if (current_error < best_error) {
 			best_error = current_error;
-			keyframe1 = previous_keyframe;
-			keyframe2 = current_keyframe;
+			image1 = previous_image;
+			image2 = current_image;
 		}
 
-		previous_keyframe = current_keyframe;
+		previous_image = current_image;
 	}
 
 	return true;
 }
 
-struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks *libmv_tracks,
-		const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+static libmv::BundleOptions refinementOptionsFromReconstructionOptions(
+		const libmv_ReconstructionOptions &reconstruction_options)
+{
+	/* only a few combinations are supported but trust the caller */
+	libmv::BundleOptions bundle_options;
+
+	const int motion_flag = reconstruction_options.motion_flag;
+	const int refine_intrinsics = reconstruction_options.refine_intrinsics;
+	const int constrain_intrinsics = reconstruction_options.constrain_intrinsics;
+
+	if (motion_flag & LIBMV_TRACKING_MOTION_MODAL) {
+		bundle_options.constraints |= libmv::BUNDLE_NO_TRANSLATION;
+	}
+
+	if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
+		bundle_options.bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH;
+		if (constrain_intrinsics & LIBMV_CONSTRAIN_FOCAL_LENGTH) {
+			bundle_options.constraints |= libmv::BUNDLE_CONSTRAIN_FOCAL_LENGTH;
+			bundle_options.focal_length_min = reconstruction_options.focal_length_min;
+			bundle_options.focal_length_max = reconstruction_options.focal_length_max;
+		}
+	}
+	if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
+		bundle_options.bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
+	}
+	if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) {
+		bundle_options.bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1;
+	}
+	if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
+		bundle_options.bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2;
+	}
+
+	return bundle_options;
+}
+
+static void finishReconstruction(const libmv::Tracks &tracks, const std::vector<libmv::CameraIntrinsics> &camera_intrinsics,
+                                 libmv_Reconstruction *libmv_reconstruction,
+                                 reconstruct_progress_update_cb progress_update_callback,
+                                 void *callback_customdata)
+{
+	libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
+
+	/* reprojection error calculation */
+	progress_update_callback(callback_customdata, 1.0, "Finishing solution");
+	libmv_reconstruction->tracks = tracks;
+	libmv_reconstruction->error = libmv::EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
+}
+
+libmv_Reconstruction *libmv_solve(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)
 {
 	struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+	libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
+	std::vector<libmv::CameraIntrinsics> &camera_intrinsics = libmv_reconstruction->intrinsics;
 
 	libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks);
-	libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
-	libmv::CameraIntrinsics &camera_intrinsics = libmv_reconstruction->intrinsics;
+	int num_cameras = tracks.MaxCamera() + 1;
 
-	ReconstructUpdateCallback update_callback =
-		ReconstructUpdateCallback(progress_update_callback, callback_customdata);
+	ReconstructUpdateCallback update_callback(progress_update_callback,
+	                                          callback_customdata);
 
-	/* Retrieve reconstruction options from C-API to libmv API */
-	cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, &camera_intrinsics);
+	/* Convert options from C-API to libmv API */
+	cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, num_cameras, camera_intrinsics);
 
 	libmv::ReconstructionOptions reconstruction_options;
 	reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold;
@@ -597,104 +625,70 @@
 	/* Invert the camera intrinsics */
 	libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
 
-	/* keyframe selection */
-	int keyframe1 = libmv_reconstruction_options->keyframe1,
-	    keyframe2 = libmv_reconstruction_options->keyframe2;
+	if (libmv_reconstruction_options->motion_flag & LIBMV_TRACKING_MOTION_MODAL &&
+	    num_cameras == 1) {
+		/* Perform modal solving */
+		libmv::ModalSolver(normalized_tracks, &reconstruction, &update_callback);
+		
+		/* Perform bundle adjustment */
+		libmv::EuclideanBundleModal(tracks,
+		                            &reconstruction);
+	}
+	else {
+		/* Image selection */
+		int &image1 = libmv_reconstruction_options->keyframe1,
+		    &image2 = libmv_reconstruction_options->keyframe2;
+
+		if (libmv_reconstruction_options->select_keyframes) {
+			LG << "Using automatic image selection";
+
+			update_callback.invoke(0, "Selecting images");
+
+			selectTwoInitialImages(tracks,
+			                       normalized_tracks,
+			                       camera_intrinsics,
+			                       reconstruction_options,
+			                       image1,
+			                       image2);
+		}
 
-	if (libmv_reconstruction_options->select_keyframes) {
-		LG << "Using automatic keyframe selection";
+		LG << "frames to init from: " << image1 << " " << image2;
 
-		update_callback.invoke(0, "Selecting keyframes");
+		/* Reconstruct for two images */
+		libmv::vector<libmv::Marker> image_markers =
+				normalized_tracks.MarkersForTracksInBothImages(image1, image2);
 
-		selectTwoKeyframesBasedOnGRICAndVariance(tracks,
-		                                         normalized_tracks,
-		                                         camera_intrinsics,
-		                                         reconstruction_options,
-		                                         keyframe1,
-		                                         keyframe2);
+		LG << "number of markers for init: " << image_markers.size();
 
-		/* so keyframes in the interface would be updated */
-		libmv_reconstruction_options->keyframe1 = keyframe1;
-		libmv_reconstruction_options->keyframe2 = keyframe2;
-	}
+		update_callback.invoke(0, "Initial reconstruction");
 
-	/* actual reconstruction */
-	LG << "frames to init from: " << keyframe1 << " " << keyframe2;
+		libmv::EuclideanReconstructTwoFrames(image_markers, &reconstruction);
 
-	libmv::vector<libmv::Marker> keyframe_markers =
-		normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+		/* Perform bundle adjustment */
+		libmv::EuclideanBundle(normalized_tracks, &reconstruction);
 
-	LG << "number of markers for init: " << keyframe_markers.size();
+		/* Reconstruct for all frames */
+		libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
+																					 &reconstruction, &update_callback);
+	}
 
-	update_callback.invoke(0, "Initial reconstruction");
+	if (libmv_reconstruction_options->refine_intrinsics) {
+		/* Refine bundle parameters */
+		libmv::BundleOptions refinement_bundle_options =
+				refinementOptionsFromReconstructionOptions(*libmv_reconstruction_options);
 
-	libmv::EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
-	libmv::EuclideanBundle(normalized_tracks, &reconstruction);
-	libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
-	                                       &reconstruction, &update_callback);
+		progress_update_callback(callback_customdata, 1.0, "Refining solution");
 
-	/* refinement */
-	if (libmv_reconstruction_options->refine_intrinsics) {
-		libmv_solveRefineIntrinsics(tracks,
-		                            libmv_reconstruction_options->refine_intrinsics,
-		                            libmv::BUNDLE_NO_CONSTRAINTS,
-		                            progress_update_callback,
-		                            callback_customdata,
-		                            &reconstruction,
-		                            &camera_intrinsics);
+		libmv::EuclideanBundleCommonIntrinsics(tracks,
+		                                       refinement_bundle_options,
+		                                       &reconstruction,
+		                                       camera_intrinsics);
 	}
 
-	/* set reconstruction scale to unity */
+	/* Set reconstruction scale to unity */
 	libmv::EuclideanScaleToUnity(&reconstruction);
 
-	/* finish reconstruction */
-	finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
-	                     progress_update_callback, callback_customdata);
-
-	return (struct libmv_Reconstruction *)libmv_reconstruction;
-}
-
-struct libmv_Reconstruction *libmv_solveModal(const struct 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)
-{
-	struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
-
-	libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks);
-	libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
-	libmv::CameraIntrinsics &camera_intrinsics = libmv_reconstruction->intrinsics;
-
-	ReconstructUpdateCallback update_callback =
-		ReconstructUpdateCallback(progress_update_callback, callback_customdata);
-
-	cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, &camera_intrinsics);
-
-	/* Invert the camera intrinsics. */
-	libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
-
-	/* Actual reconstruction. */
-	libmv::ModalSolver(normalized_tracks, &reconstruction, &update_callback);
-
-	libmv::CameraIntrinsics empty_intrinsics;
-	libmv::EuclideanBundleCommonIntrinsics(normalized_tracks,
-	                                       libmv::BUNDLE_NO_INTRINSICS,
-	                                       libmv::BUNDLE_NO_TRANSLATION,
-	                                       &reconstruction,
-	                                       &empty_intrinsics);
-
-	/* Refinement. */
-	if (libmv_reconstruction_options->refine_intrinsics) {
-		libmv_solveRefineIntrinsics(tracks,
-		                            libmv_reconstruction_options->refine_intrinsics,
-		                            libmv::BUNDLE_NO_TRANSLATION,
-		                            progress_update_callback, callback_customdata,
-		                            &reconstruction,
-		                            &camera_intrinsics);
-	}
-
-	/* Finish reconstruction. */
+	/* Finish reconstruction */
 	finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
 	                     progress_update_callback, callback_customdata);
 
@@ -723,16 +717,16 @@
 }
 
 static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point,
-                                   const libmv::EuclideanCamera &camera,
+                                   const libmv::EuclideanView &view,
                                    const libmv::CameraIntrinsics &intrinsics)
 {
-	libmv::Vec3 projected = camera.R * point.X + camera.t;
+	libmv::Vec3 projected = view.R * point.X + view.t;
 	projected /= projected(2);
 
 	libmv::Marker reprojected_marker;
 	intrinsics.ApplyIntrinsics(projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
 
-	reprojected_marker.image = camera.image;
+	reprojected_marker.image = view.image;
 	reprojected_marker.track = point.track;
 
 	return reprojected_marker;
@@ -741,23 +735,25 @@
 double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track)
 {
 	const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
-	const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+	const std::vector<libmv::CameraIntrinsics> *intrinsics = &libmv_reconstruction->intrinsics;
 	libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersForTrack(track);
 
 	int num_reprojected = 0;
 	double total_error = 0.0;
 
 	for (int i = 0; i < markers.size(); ++i) {
-		const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+		int camera = markers[i].camera;
+		const libmv::EuclideanView *view = reconstruction->ViewForImage(markers[i].image);
 		const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+		const libmv::CameraIntrinsics camera_intrinsics = (*intrinsics)[camera];
 
-		if (!camera || !point) {
+		if (!view || !point) {
 			continue;
 		}
 
 		num_reprojected++;
 
-		libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+		libmv::Marker reprojected_marker = ProjectMarker(*point, *view, camera_intrinsics);
 		double ex = reprojected_marker.x - markers[i].x;
 		double ey = reprojected_marker.y - markers[i].y;
 
@@ -767,16 +763,18 @@
 	return total_error / num_reprojected;
 }
 
-double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_reconstruction, int image)
+double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_reconstruction,
+                                       int image)
 {
 	const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
-	const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+  int camera = libmv_reconstruction->tracks.CameraFromImage(image);
+	const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics[camera];
 	libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
-	const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
+	const libmv::EuclideanView *view = reconstruction->ViewForImage(image);
 	int num_reprojected = 0;
 	double total_error = 0.0;
 
-	if (!camera)
+	if (!view)
 		return 0;
 
 	for (int i = 0; i < markers.size(); ++i) {
@@ -788,7 +786,7 @@
 
 		num_reprojected++;
 
-		libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+		libmv::Marker reprojected_marker = ProjectMarker(*point, *view, *intrinsics);
 		double ex = reprojected_marker.x - markers[i].x;
 		double ey = reprojected_marker.y - markers[i].y;
 
@@ -799,12 +797,12 @@
 }
 
 int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_reconstruction,
-                                      int image, double mat[4][4])
+                                     int image, double mat[4][4])
 {
 	const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
-	const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
+	const libmv::EuclideanView *view = reconstruction->ViewForImage(image);
 
-	if (camera) {
+	if (view) {
 		for (int j = 0; j < 3; ++j) {
 			for (int k = 0; k < 3; ++k) {
 				int l = k;
@@ -812,13 +810,13 @@
 				if (k == 1) l = 2;
 				else if (k == 2) l = 1;
 
-				if (j == 2) mat[j][l] = -camera->R(j,k);
-				else mat[j][l] = camera->R(j,k);
+				if (j == 2) mat[j][l] = -view->R(j,k);
+				else mat[j][l] = view->R(j,k);
 			}
 			mat[j][3] = 0.0;
 		}
 
-		libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
+		libmv::Vec3 optical_center = -view->R.transpose() * view->t;
 
 		mat[3][0] = optical_center(0);
 		mat[3][1] = optical_center(2);
@@ -837,9 +835,10 @@
 	return libmv_reconstruction->error;
 }
 
-struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_reconstruction)
+struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_reconstruction,
+                                                                     int camera)
 {
-	return (struct libmv_CameraIntrinsics *)&libmv_reconstruction->intrinsics;
+	return (struct libmv_CameraIntrinsics *)&libmv_reconstruction->intrinsics[camera];
 }
 
 /* ************ Feature detector ************ */
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv-capi.h svn/extern/libmv/libmv-capi.h
--- trunk/extern/libmv/libmv-capi.h	2013-09-22 13:27:13.000000000 +0100
+++ svn/extern/libmv/libmv-capi.h	2013-09-14 11:24:31.000000000 +0100
@@ -73,14 +73,20 @@
 /* Tracks */
 struct libmv_Tracks *libmv_tracksNew(void);
 void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
-void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y);
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y, int camera);
 
 /* Reconstruction */
+#define LIBMV_TRACKING_MOTION_MODAL        (1 << 0)
+
 #define LIBMV_REFINE_FOCAL_LENGTH          (1 << 0)
 #define LIBMV_REFINE_PRINCIPAL_POINT       (1 << 1)
 #define LIBMV_REFINE_RADIAL_DISTORTION_K1  (1 << 2)
 #define LIBMV_REFINE_RADIAL_DISTORTION_K2  (1 << 4)
 
+#define LIBMV_CONSTRAIN_FOCAL_LENGTH       (1 << 0)
+
+#define LIBMV_CONSTRAIN_FOCAL_LENGTH       (1 << 0)
+
 typedef struct libmv_CameraIntrinsicsOptions {
 	double focal_length;
 	double principal_point_x, principal_point_y;
@@ -93,7 +99,11 @@
 	int select_keyframes;
 	int keyframe1, keyframe2;
 
-	int refine_intrinsics;
+	short motion_flag;
+
+	short refine_intrinsics;
+	short constrain_intrinsics;
+	double focal_length_min, focal_length_max;
 
 	double success_threshold;
 	int use_fallback_reconstruction;
@@ -101,16 +111,11 @@
 
 typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
 
-struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks *libmv_tracks,
-		const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+struct libmv_Reconstruction *libmv_solve(const struct 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);
-struct libmv_Reconstruction *libmv_solveModal(const struct 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);
 void libmv_reconstructionDestroy(struct libmv_Reconstruction *libmv_reconstruction);
 int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
 double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track);
@@ -118,7 +123,8 @@
 int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_reconstruction,
                                      int image, double mat[4][4]);
 double libmv_reprojectionError(const struct libmv_Reconstruction *libmv_reconstruction);
-struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction);
+struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction,
+                                                                     int camera);
 
 /* Feature detector */
 struct libmv_Features *libmv_detectFeaturesFAST(const unsigned char *data, int width, int height, int stride,
diff -ru '--exclude=.svn' trunk/extern/libmv/libmv-capi_stub.cc svn/extern/libmv/libmv-capi_stub.cc
--- trunk/extern/libmv/libmv-capi_stub.cc	2013-09-22 13:27:12.000000000 +0100
+++ svn/extern/libmv/libmv-capi_stub.cc	2013-09-14 12:02:39.000000000 +0100
@@ -84,8 +84,10 @@
 	return NULL;
 }
 
-void libmv_tracksInsert(struct libmv_Tracks * /*libmv_tracks*/, int /*image*/,
-                        int /*track*/, double /*x*/, double /*y*/)
+void libmv_tracksInsert(struct libmv_Tracks * /*libmv_tracks*/,
+                        int /*image*/, int /*track*/,
+                        double /*x*/, double /*y*/,
+                        int /*camera*/)
 {
 }
 
@@ -95,7 +97,7 @@
 
 /* ************ Reconstruction solver ************ */
 
-struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks * /*libmv_tracks*/,
+libmv_Reconstruction *libmv_solve(const libmv_Tracks * /*libmv_tracks*/,
 		const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
 		libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
 		reconstruct_progress_update_cb /*progress_update_callback*/,
@@ -104,15 +106,6 @@
 	return NULL;
 }
 
-struct libmv_Reconstruction *libmv_solveModal(const struct 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*/)
-{
-	return NULL;
-}
-
 int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
                                      int /*track*/, double /*pos*/[3])
 {
@@ -124,13 +117,14 @@
 	return 0.0;
 }
 
-double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/, int /*image*/)
+double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
+                                       int /*image*/)
 {
 	return 0.0;
 }
 
-int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/, int /*image*/,
-                                      double /*mat*/[4][4])
+int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
+                                     int /*image*/, double /*mat*/[4][4])
 {
 	return 0;
 }
@@ -180,7 +174,8 @@
 /* ************ camera intrinsics ************ */
 
 struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
-		struct libmv_Reconstruction * /*libmv_reconstruction*/)
+		struct libmv_Reconstruction * /*libmv_reconstruction*/,
+    int /*camera*/)
 {
 	return NULL;
 }
Only in svn/release/scripts/addons_contrib: object_edit_linked.py
Only in svn/release/scripts/addons_contrib: uv_texture_atlas.py
diff -ru '--exclude=.svn' trunk/release/scripts/startup/bl_ui/space_clip.py svn/release/scripts/startup/bl_ui/space_clip.py
--- trunk/release/scripts/startup/bl_ui/space_clip.py	2013-09-22 13:26:24.000000000 +0100
+++ svn/release/scripts/startup/bl_ui/space_clip.py	2013-09-22 13:10:32.000000000 +0100
@@ -353,6 +353,19 @@
         col.prop(settings, "refine_intrinsics", text="")
 
         col = layout.column(align=True)
+        col.active = "FOCAL_LENGTH" in settings.refine_intrinsics
+        col.prop(settings, "use_focal_length_constraint");
+        sub = col.column(align=True)
+        sub.active = settings.use_focal_length_constraint
+        if tracking.camera.units == 'MILLIMETERS':
+            sub.prop(settings, "focal_length_min", text="Min")
+            sub.prop(settings, "focal_length_max", text="Max")
+        else:
+            sub.prop(settings, "focal_length_min_pixels", text="Min")
+            sub.prop(settings, "focal_length_max_pixels", text="Max")
+
+
+        col = layout.column(align=True)
         col.active = not settings.use_tripod_solver
         col.prop(settings, "use_fallback_reconstruction",
                  text="Allow Fallback")
@@ -943,6 +956,17 @@
         layout.operator("clip.set_scene_frames")
 
 
+class CLIP_PT_multicamera_clip(CLIP_PT_clip_view_panel, Panel):
+    bl_space_type = 'CLIP_EDITOR'
+    bl_region_type = 'TOOLS'
+    bl_label = "Multicamera"
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.operator("clip.create_correspondence")
+
+
 class CLIP_MT_view(Menu):
     bl_label = "View"
 
diff -ru '--exclude=.svn' trunk/source/blender/blenkernel/BKE_tracking.h svn/source/blender/blenkernel/BKE_tracking.h
--- trunk/source/blender/blenkernel/BKE_tracking.h	2013-09-22 13:26:51.000000000 +0100
+++ svn/source/blender/blenkernel/BKE_tracking.h	2013-09-22 13:11:54.000000000 +0100
@@ -160,6 +160,7 @@
                                                                            struct MovieTrackingObject *object);
 
 /* **** Camera **** */
+void BKE_tracking_camera_focal_length_set(struct MovieTracking *tracking, float value);
 void BKE_tracking_camera_shift_get(struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
 void BKE_tracking_camera_to_blender(struct MovieTracking *tracking, struct Scene *scene,
                                     struct Camera *camera, int width, int height);
diff -ru '--exclude=.svn' trunk/source/blender/blenkernel/intern/movieclip.c svn/source/blender/blenkernel/intern/movieclip.c
--- trunk/source/blender/blenkernel/intern/movieclip.c	2013-09-22 13:26:50.000000000 +0100
+++ svn/source/blender/blenkernel/intern/movieclip.c	2013-09-20 16:35:35.000000000 +0100
@@ -57,6 +57,8 @@
 #include "DNA_scene_types.h"
 #include "DNA_view3d_types.h"
 
+#include "RNA_access.h"
+
 #include "BLI_utildefines.h"
 
 #include "BLI_blenlib.h"
@@ -657,10 +659,12 @@
 	detect_clip_source(clip);
 
 	movieclip_load_get_szie(clip);
+
 	if (clip->lastsize[0]) {
 		int width = clip->lastsize[0];
-
-		clip->tracking.camera.focal = 24.0f * width / clip->tracking.camera.sensor_width;
+ 
+		float focal = 24.0f * width / clip->tracking.camera.sensor_width;
+		BKE_tracking_camera_focal_length_set(&clip->tracking, focal);
 	}
 
 	movieclip_calc_length(clip);
diff -ru '--exclude=.svn' trunk/source/blender/blenkernel/intern/tracking.c svn/source/blender/blenkernel/intern/tracking.c
--- trunk/source/blender/blenkernel/intern/tracking.c	2013-09-22 13:26:50.000000000 +0100
+++ svn/source/blender/blenkernel/intern/tracking.c	2013-09-22 13:11:50.000000000 +0100
@@ -213,6 +213,8 @@
 	tracking->settings.dist = 1;
 	tracking->settings.object_distance = 1;
 	tracking->settings.reconstruction_success_threshold = 1e-3f;
+	tracking->settings.focal_length_min = 0.0f;
+	tracking->settings.focal_length_max = 5000.0f;
 
 	tracking->stabilization.scaleinf = 1.0f;
 	tracking->stabilization.locinf = 1.0f;
@@ -1798,6 +1800,20 @@
 	}
 }
 
+void BKE_tracking_camera_focal_length_set(MovieTracking *tracking, float value)
+{
+	MovieTrackingSettings *settings = &tracking->settings;
+	MovieTrackingCamera *camera = &tracking->camera;
+
+	if (!(settings->refine_intrinsics & REFINE_FOCAL_LENGTH) ||
+	    !(settings->constrain_intrinsics & CONSTRAIN_FOCAL_LENGTH))
+	{
+		settings->focal_length_min = value;
+		settings->focal_length_max = value;
+	}
+
+	camera->focal = value;
+}
 
 /* converts principal offset from center to offset of blender's camera */
 void BKE_tracking_camera_shift_get(MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
@@ -3455,7 +3471,9 @@
 	struct libmv_Tracks *tracks;
 	bool select_keyframes;
 	int keyframe1, keyframe2;
-	int refine_flags;
+	short refine_intrinsics;
+	short constrain_intrinsics;
+	float focal_length_min, focal_length_max;
 
 	struct libmv_Reconstruction *reconstruction;
 
@@ -3504,7 +3522,8 @@
 			if ((marker->flag & MARKER_DISABLED) == 0) {
 				libmv_tracksInsert(tracks, marker->framenr, tracknr,
 				                   (marker->pos[0] + track->offset[0]) * width,
-				                   (marker->pos[1] + track->offset[1]) * height);
+				                   (marker->pos[1] + track->offset[1]) * height,
+													 0);
 			}
 		}
 
@@ -3519,7 +3538,7 @@
 static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
 {
 	struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
-	struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction);
+	struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction, 0);
 
 	float aspy = 1.0f / tracking->camera.pixel_aspect;
 
@@ -3674,27 +3693,38 @@
 }
 
 /* Convert blender's refinement flags to libmv's. */
-static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, MovieTrackingObject *object)
-{
-	int refine = tracking->settings.refine_camera_intrinsics;
-	int flags = 0;
+static void reconstruct_refine_intrinsics_get_flags(const MovieTracking *tracking,
+                                                    const MovieTrackingObject *object,
+                                                    MovieReconstructContext *context)
+{
+	short refine = tracking->settings.refine_intrinsics;
+	short constrain = tracking->settings.constrain_intrinsics;
+	short libmv_refine = 0;
+	short libmv_constrain = 0;
 
-	if ((object->flag & TRACKING_OBJECT_CAMERA) == 0)
-		return 0;
+	if ((object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+		context->refine_intrinsics = 0;
+		context->constrain_intrinsics = 0;
+		return;
+	}
 
-	if (refine & REFINE_FOCAL_LENGTH)
-		flags |= LIBMV_REFINE_FOCAL_LENGTH;
+	if (refine & REFINE_FOCAL_LENGTH) {
+		libmv_refine |= LIBMV_REFINE_FOCAL_LENGTH;
+		if (constrain & CONSTRAIN_FOCAL_LENGTH)
+			libmv_constrain |= LIBMV_CONSTRAIN_FOCAL_LENGTH;
+	}
 
 	if (refine & REFINE_PRINCIPAL_POINT)
-		flags |= LIBMV_REFINE_PRINCIPAL_POINT;
+		libmv_refine |= LIBMV_REFINE_PRINCIPAL_POINT;
 
 	if (refine & REFINE_RADIAL_DISTORTION_K1)
-		flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
+		libmv_refine |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
 
 	if (refine & REFINE_RADIAL_DISTORTION_K2)
-		flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
+		libmv_refine |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
 
-	return flags;
+	context->refine_intrinsics = libmv_refine;
+	context->constrain_intrinsics = libmv_constrain;
 }
 
 /* Count tracks which has markers at both of keyframes. */
@@ -3820,7 +3850,10 @@
 	context->tracks = libmv_tracks_new(tracksbase, width, height * aspy);
 	context->keyframe1 = keyframe1;
 	context->keyframe2 = keyframe2;
-	context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
+
+	reconstruct_refine_intrinsics_get_flags(tracking, object, context);
+	context->focal_length_min = tracking->settings.focal_length_min;
+	context->focal_length_max = tracking->settings.focal_length_max;
 
 	return context;
 }
@@ -3851,10 +3884,12 @@
 	BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
 }
 /* FIll in camera intrinsics structure from reconstruction context. */
-static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
-                                              MovieReconstructContext *context)
+static void cameraIntrinsicsOptionsFromContext(const MovieReconstructContext *context,
+                                               libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
 {
 	camera_intrinsics_options->focal_length = context->focal_length;
+	CLAMP(camera_intrinsics_options->focal_length,
+	      context->focal_length_min, context->focal_length_max);
 
 	camera_intrinsics_options->principal_point_x = context->principal_point[0];
 	camera_intrinsics_options->principal_point_y = context->principal_point[1];
@@ -3868,15 +3903,20 @@
 }
 
 /* Fill in reconstruction options structure from reconstruction context. */
-static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *reconstruction_options,
-                                             MovieReconstructContext *context)
+static void reconstructionOptionsFromContext(MovieReconstructContext *context,
+                                             libmv_ReconstructionOptions *reconstruction_options)
 {
 	reconstruction_options->select_keyframes = context->select_keyframes;
 
 	reconstruction_options->keyframe1 = context->keyframe1;
 	reconstruction_options->keyframe2 = context->keyframe2;
 
-	reconstruction_options->refine_intrinsics = context->refine_flags;
+	reconstruction_options->motion_flag = context->motion_flag;
+
+	reconstruction_options->refine_intrinsics = context->refine_intrinsics;
+	reconstruction_options->constrain_intrinsics = context->constrain_intrinsics;
+	reconstruction_options->focal_length_min = context->focal_length_min;
+	reconstruction_options->focal_length_max = context->focal_length_max;
 
 	reconstruction_options->success_threshold = context->success_threshold;
 	reconstruction_options->use_fallback_reconstruction = context->use_fallback_reconstruction;
@@ -3907,26 +3947,20 @@
 	progressdata.stats_message = stats_message;
 	progressdata.message_size = message_size;
 
-	camraIntrincicsOptionsFromContext(&camera_intrinsics_options, context);
-	reconstructionOptionsFromContext(&reconstruction_options, context);
+	cameraIntrinsicsOptionsFromContext(context, &camera_intrinsics_options);
+	reconstructionOptionsFromContext(context, &reconstruction_options);
 
-	if (context->motion_flag & TRACKING_MOTION_MODAL) {
-		context->reconstruction = libmv_solveModal(context->tracks,
-		                                           &camera_intrinsics_options,
-		                                           &reconstruction_options,
-		                                           reconstruct_update_solve_cb, &progressdata);
-	}
-	else {
-		context->reconstruction = libmv_solveReconstruction(context->tracks,
-		                                                    &camera_intrinsics_options,
-		                                                    &reconstruction_options,
-		                                                    reconstruct_update_solve_cb, &progressdata);
-
-		if (context->select_keyframes) {
-			/* store actual keyframes used for reconstruction to update them in the interface later */
-			context->keyframe1 = reconstruction_options.keyframe1;
-			context->keyframe2 = reconstruction_options.keyframe2;
-		}
+	context->reconstruction = libmv_solve(context->tracks,
+	                                      &camera_intrinsics_options,
+	                                      &reconstruction_options,
+	                                      reconstruct_update_solve_cb,
+	                                      &progressdata);
+	if ((context->motion_flag & TRACKING_MOTION_MODAL) &&
+	    context->select_keyframes)
+	{
+		/* store actual keyframes used for reconstruction to update them in the interface later */
+		context->keyframe1 = reconstruction_options.keyframe1;
+		context->keyframe2 = reconstruction_options.keyframe2;
 	}
 
 	error = libmv_reprojectionError(context->reconstruction);
diff -ru '--exclude=.svn' trunk/source/blender/editors/space_clip/clip_intern.h svn/source/blender/editors/space_clip/clip_intern.h
--- trunk/source/blender/editors/space_clip/clip_intern.h	2013-09-22 13:27:05.000000000 +0100
+++ svn/source/blender/editors/space_clip/clip_intern.h	2013-09-22 13:10:32.000000000 +0100
@@ -201,6 +201,8 @@
 void CLIP_OT_keyframe_insert(struct wmOperatorType *ot);
 void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
 
+void CLIP_OT_create_correspondence(struct wmOperatorType *ot);
+
 /* tracking_select.c */
 void CLIP_OT_select(struct wmOperatorType *ot);
 void CLIP_OT_select_all(struct wmOperatorType *ot);
diff -ru '--exclude=.svn' trunk/source/blender/editors/space_clip/space_clip.c svn/source/blender/editors/space_clip/space_clip.c
--- trunk/source/blender/editors/space_clip/space_clip.c	2013-09-22 13:27:05.000000000 +0100
+++ svn/source/blender/editors/space_clip/space_clip.c	2013-09-22 13:10:32.000000000 +0100
@@ -526,6 +526,9 @@
 	WM_operatortype_append(CLIP_OT_keyframe_insert);
 	WM_operatortype_append(CLIP_OT_keyframe_delete);
 
+	/* Multicamera */
+	WM_operatortype_append(CLIP_OT_create_correspondence);
+
 	/* ** clip_graph_ops.c  ** */
 
 	/* graph editing */
diff -ru '--exclude=.svn' trunk/source/blender/editors/space_clip/tracking_ops.c svn/source/blender/editors/space_clip/tracking_ops.c
--- trunk/source/blender/editors/space_clip/tracking_ops.c	2013-09-22 13:27:06.000000000 +0100
+++ svn/source/blender/editors/space_clip/tracking_ops.c	2013-09-22 13:12:55.000000000 +0100
@@ -4198,3 +4198,20 @@
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+/********************** Multicamera operators ******************************/
+
+void CLIP_OT_create_correspondence(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Create correspondence";
+	ot->description = "Create a correspondence between selected tracks across multiple clips";
+	ot->idname = "CLIP_OT_create_correspondence";
+
+	/* api callbacks */
+	//ot->poll = ;
+	//ot->exec = ;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff -ru '--exclude=.svn' trunk/source/blender/makesdna/DNA_tracking_types.h svn/source/blender/makesdna/DNA_tracking_types.h
--- trunk/source/blender/makesdna/DNA_tracking_types.h	2013-09-22 13:26:51.000000000 +0100
+++ svn/source/blender/makesdna/DNA_tracking_types.h	2013-09-22 13:11:55.000000000 +0100
@@ -210,8 +210,10 @@
 	float reconstruction_success_threshold;
 	int reconstruction_flag;
 
-	/* which camera intrinsics to refine. uses on the REFINE_* flags */
-	short refine_camera_intrinsics, pad2;
+	/* refinement */
+	short refine_intrinsics;                  /* camera intrinsics to refine */
+	short constrain_intrinsics;               /* camera intrinsics to constrain */
+	float focal_length_min, focal_length_max; /* minimum and maximum values for focal length refinement in pixels */
 
 	/* ** tool settings ** */
 
@@ -413,7 +415,7 @@
 	TRACKING_USE_KEYFRAME_SELECTION      = (1 << 1)
 };
 
-/* MovieTrackingSettings->refine_camera_intrinsics */
+/* MovieTrackingSettings->refine_intrinsics */
 enum {
 	REFINE_FOCAL_LENGTH         = (1 << 0),
 	REFINE_PRINCIPAL_POINT      = (1 << 1),
@@ -421,6 +423,11 @@
 	REFINE_RADIAL_DISTORTION_K2 = (1 << 4)
 };
 
+/* MovieTrackingSettings->constrain_intrinsics */
+enum {
+	CONSTRAIN_FOCAL_LENGTH      = (1 << 0)
+};
+
 /* MovieTrackingStrabilization->flag */
 enum {
 	TRACKING_2D_STABILIZATION   = (1 << 0),
diff -ru '--exclude=.svn' trunk/source/blender/makesrna/intern/rna_tracking.c svn/source/blender/makesrna/intern/rna_tracking.c
--- trunk/source/blender/makesrna/intern/rna_tracking.c	2013-09-22 13:26:57.000000000 +0100
+++ svn/source/blender/makesrna/intern/rna_tracking.c	2013-09-22 13:12:11.000000000 +0100
@@ -55,6 +55,76 @@
 
 #include "WM_api.h"
 
+static void rna_trackingSettings_focal_length_min_pixels_set(PointerRNA *ptr, float value)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingSettings *settings = &clip->tracking.settings;
+
+	if (value > settings->focal_length_max)
+		value = settings->focal_length_max;
+
+	settings->focal_length_min = value;
+}
+
+static void rna_trackingSettings_focal_length_max_pixels_set(PointerRNA *ptr, float value)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingSettings *settings = &clip->tracking.settings;
+
+	if (value < settings->focal_length_min)
+		value = settings->focal_length_min;
+
+	settings->focal_length_max = value;
+}
+
+static float rna_trackingSettings_focal_length_min_get(PointerRNA *ptr)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingSettings *settings = &clip->tracking.settings;
+	MovieTrackingCamera *camera = &clip->tracking.camera;
+	float value = settings->focal_length_min;
+
+	if (clip->lastsize[0])
+		value = value * camera->sensor_width / (float)clip->lastsize[0];
+	
+	return value;
+}
+
+static void rna_trackingSettings_focal_length_min_set(PointerRNA *ptr, float value)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingCamera *camera = &clip->tracking.camera;
+
+	if (clip->lastsize[0])
+		value = clip->lastsize[0] * value / camera->sensor_width;
+
+	rna_trackingSettings_focal_length_min_pixels_set(ptr, value);
+}
+
+static float rna_trackingSettings_focal_length_max_get(PointerRNA *ptr)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingSettings *settings = &clip->tracking.settings;
+	MovieTrackingCamera *camera = &clip->tracking.camera;
+	float value = settings->focal_length_max;
+
+	if (clip->lastsize[0])
+		value = value * camera->sensor_width / (float)clip->lastsize[0];
+	
+	return value;
+}
+
+static void rna_trackingSettings_focal_length_max_set(PointerRNA *ptr, float value)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	MovieTrackingCamera *camera = &clip->tracking.camera;
+
+	if (clip->lastsize[0])
+		value = clip->lastsize[0] * value / camera->sensor_width;
+
+	rna_trackingSettings_focal_length_max_pixels_set(ptr, value);
+}
+
 static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
 {
 	return BLI_sprintfN("tracking");
@@ -306,7 +376,13 @@
 	return BLI_sprintfN("tracking.camera");
 }
 
-static float rna_trackingCamera_focal_mm_get(PointerRNA *ptr)
+static void rna_trackingCamera_focal_length_pixels_set(PointerRNA *ptr, float value)
+{
+	MovieClip *clip = (MovieClip *)ptr->id.data;
+	BKE_tracking_camera_focal_length_set(&clip->tracking, value);
+}
+
+static float rna_trackingCamera_focal_length_get(PointerRNA *ptr)
 {
 	MovieClip *clip = (MovieClip *)ptr->id.data;
 	MovieTrackingCamera *camera = &clip->tracking.camera;
@@ -318,7 +394,7 @@
 	return val;
 }
 
-static void rna_trackingCamera_focal_mm_set(PointerRNA *ptr, float value)
+static void rna_trackingCamera_focal_length_set(PointerRNA *ptr, float value)
 {
 	MovieClip *clip = (MovieClip *)ptr->id.data;
 	MovieTrackingCamera *camera = &clip->tracking.camera;
@@ -327,7 +403,7 @@
 		value = clip->lastsize[0] * value / camera->sensor_width;
 
 	if (value >= 0.0001f)
-		camera->focal = value;
+		BKE_tracking_camera_focal_length_set(&clip->tracking, value);
 }
 
 static char *rna_trackingStabilization_path(PointerRNA *UNUSED(ptr))
@@ -795,11 +871,56 @@
 
 	/* intrinsics refinement during bundle adjustment */
 	prop = RNA_def_property(srna, "refine_intrinsics", PROP_ENUM, PROP_NONE);
-	RNA_def_property_enum_sdna(prop, NULL, "refine_camera_intrinsics");
+	RNA_def_property_enum_sdna(prop, NULL, "refine_intrinsics");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_enum_items(prop, refine_items);
 	RNA_def_property_ui_text(prop, "Refine", "Refine intrinsics during camera solving");
 
+	/* constrain focal length for intrinsics refinement */
+	prop = RNA_def_property(srna, "use_focal_length_constraint", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_boolean_sdna(prop, NULL, "constrain_intrinsics", CONSTRAIN_FOCAL_LENGTH);
+	RNA_def_property_ui_text(prop, "Constrain Focal Length",
+	                         "Constrain the focal length during intrinsics refinement");
+
+	/* focal length constraint values in pixels */
+	prop = RNA_def_property(srna, "focal_length_min_pixels", PROP_FLOAT, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_float_sdna(prop, NULL, "focal_length_min");
+	RNA_def_property_range(prop, 0.0f, 10000.0f);
+	RNA_def_property_float_default(prop, 0.0f);
+	RNA_def_property_float_funcs(prop, NULL, "rna_trackingSettings_focal_length_min_pixels_set", NULL);
+	RNA_def_property_ui_text(prop, "Min Focal Length",
+	                         "Minimum focal length in pixels");
+
+	prop = RNA_def_property(srna, "focal_length_max_pixels", PROP_FLOAT, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_float_sdna(prop, NULL, "focal_length_max");
+	RNA_def_property_range(prop, 0.0f, 10000.0f);
+	RNA_def_property_float_default(prop, 10000.0f);
+	RNA_def_property_float_funcs(prop, NULL, "rna_trackingSettings_focal_length_max_pixels_set", NULL);
+	RNA_def_property_ui_text(prop, "Max Focal Length",
+	                         "Maximum focal length in pixels");
+
+	/* focal length constraint values in millimeters */
+	prop = RNA_def_property(srna, "focal_length_min", PROP_FLOAT, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_range(prop, 0.0f, 10000.0f);
+	RNA_def_property_float_default(prop, 0.0f);
+	RNA_def_property_float_funcs(prop, "rna_trackingSettings_focal_length_min_get",
+	                                   "rna_trackingSettings_focal_length_min_set", NULL);
+	RNA_def_property_ui_text(prop, "Min Focal Length",
+	                         "Minimum focal length in millimeters");
+
+	prop = RNA_def_property(srna, "focal_length_max", PROP_FLOAT, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_range(prop, 0.0f, 10000.0f);
+	RNA_def_property_float_default(prop, 10000.0f);
+	RNA_def_property_float_funcs(prop, "rna_trackingSettings_focal_length_max_get",
+	                                   "rna_trackingSettings_focal_length_max_set", NULL);
+	RNA_def_property_ui_text(prop, "Max Focal Length",
+	                         "Maximum focal length in millimeters");
+
 	/* tool settings */
 
 	/* distance */
@@ -979,7 +1100,8 @@
 	RNA_def_property_float_sdna(prop, NULL, "focal");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_range(prop, 0.0001f, 5000.0f);
-	RNA_def_property_float_funcs(prop, "rna_trackingCamera_focal_mm_get", "rna_trackingCamera_focal_mm_set", NULL);
+	RNA_def_property_float_funcs(prop, "rna_trackingCamera_focal_length_get",
+	                                   "rna_trackingCamera_focal_length_set", NULL);
 	RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
 	RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
 
@@ -988,6 +1110,7 @@
 	RNA_def_property_float_sdna(prop, NULL, "focal");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_range(prop, 0.0f, 5000.0f);
+	RNA_def_property_float_funcs(prop, NULL, "rna_trackingCamera_focal_length_pixels_set", NULL);
 	RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
 	RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
 
@@ -995,9 +1118,9 @@
 	prop = RNA_def_property(srna, "units", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_sdna(prop, NULL, "units");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_enum_items(prop, camera_units_items);
 	RNA_def_property_ui_text(prop, "Units", "Units used for camera focal length");
+	RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
 
 	/* Principal Point */
 	prop = RNA_def_property(srna, "principal", PROP_FLOAT, PROP_NONE);
Only in svn/source/tools: check_style_c_config.pyc
Only in svn/source/tools: __pycache__
