Camera tracking: moved camera solver into it's own job
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 28 Nov 2011 13:49:42 +0000 (13:49 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 28 Nov 2011 13:49:42 +0000 (13:49 +0000)
In some cases solving can take a while (especially when refining is used)
and keeping interface locked is a bit annoying. Now camera solver is moved
to job system and interface isn't locking.

Reporting progress isn't really accurate, but trying to make it more linear
can lead to spending more effort on it than having benefit. Also, changing
status in the information line helps to understand that blender isn't hang
up and solving is till working nicely.

Main changes in code:
- libmv_solveReconstruction now accepts additional parameters:
  * progress_update_callback - a function which is getting called
    from solver algorithm to report progress back to Blender.
  * callback_customdata - a user-defined context which is passing
    to progress_update_callback so progress can be updated in needed
    blender-side data structures.

  This parameters are optional.

- Added structure MovieTrackingStats which is placed in MovieTracking
  structure. It's supposed to be used for displaying information about
  different operations (currently it's only camera solver, but can be
  easily used for something else in the future) in clip editor.
  This statistics structure is getting allocated for time operator is
  working and not saving into .blend file.

- Clip Editor now displays statistics stored in MovieTrackingStats structure
  like it's done for rendering.

13 files changed:
extern/libmv/CMakeLists.txt
extern/libmv/libmv-capi.cpp
extern/libmv/libmv-capi.h
extern/libmv/libmv/simple_pipeline/callbacks.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/callbacks.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/pipeline.cc
extern/libmv/libmv/simple_pipeline/pipeline.h
source/blender/blenkernel/BKE_tracking.h
source/blender/blenkernel/intern/tracking.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/space_clip/clip_draw.c
source/blender/editors/space_clip/tracking_ops.c
source/blender/makesdna/DNA_tracking_types.h

index cd1f572197ce988c33e3b86d9d1f9eb440e4cf50..6f0d5f3d126cd67b02922cc3beb39fc02a571918 100644 (file)
@@ -39,6 +39,7 @@ set(SRC
        libmv-capi.cpp
        libmv/numeric/numeric.cc
        libmv/numeric/poly.cc
+       libmv/simple_pipeline/callbacks.cc
        libmv/simple_pipeline/reconstruction.cc
        libmv/simple_pipeline/resect.cc
        libmv/simple_pipeline/intersect.cc
@@ -83,6 +84,7 @@ set(SRC
        libmv/numeric/poly.h
        libmv/numeric/function_derivative.h
        libmv/numeric/numeric.h
+       libmv/simple_pipeline/callbacks.h
        libmv/simple_pipeline/resect.h
        libmv/simple_pipeline/reconstruction.h
        libmv/simple_pipeline/camera_intrinsics.h
index 8c453944e9de780485a2631d341da0a33af12bbb..f08aea9fbd1359c651359def49a920584e925963 100644 (file)
@@ -31,6 +31,8 @@
 #include "libmv-capi.h"
 
 #include "glog/logging.h"
+#include "libmv/logging/logging.h"
+
 #include "Math/v3d_optimization.h"
 
 #include "libmv/tracking/esm_region_tracker.h"
@@ -41,6 +43,7 @@
 
 #include "libmv/tracking/sad.h"
 
+#include "libmv/simple_pipeline/callbacks.h"
 #include "libmv/simple_pipeline/tracks.h"
 #include "libmv/simple_pipeline/initialize_reconstruction.h"
 #include "libmv/simple_pipeline/bundle.h"
@@ -339,6 +342,26 @@ void libmv_tracksDestroy(libmv_Tracks *libmv_tracks)
 
 /* ************ Reconstruction solver ************ */
 
+class ReconstructUpdateCallback : public libmv::ProgressUpdateCallback {
+public:
+       ReconstructUpdateCallback(reconstruct_progress_update_cb progress_update_callback,
+                       void *callback_customdata)
+       {
+               progress_update_callback_ = progress_update_callback;
+               callback_customdata_ = callback_customdata;
+       }
+
+       void invoke(double progress, const char *message)
+       {
+               if(progress_update_callback_) {
+                       progress_update_callback_(callback_customdata_, progress, message);
+               }
+       }
+protected:
+       reconstruct_progress_update_cb progress_update_callback_;
+       void *callback_customdata_;
+};
+
 int libmv_refineParametersAreValid(int parameters) {
        return (parameters == (LIBMV_REFINE_FOCAL_LENGTH))         ||
               (parameters == (LIBMV_REFINE_FOCAL_LENGTH           |
@@ -356,7 +379,8 @@ int libmv_refineParametersAreValid(int parameters) {
 
 
 libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
-               int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3)
+                       int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
 {
        /* Invert the camera intrinsics. */
        libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
@@ -364,6 +388,9 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
        libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
        libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
 
+       ReconstructUpdateCallback update_callback =
+               ReconstructUpdateCallback(progress_update_callback, callback_customdata);
+
        intrinsics->SetFocalLength(focal_length, focal_length);
        intrinsics->SetPrincipalPoint(principal_x, principal_y);
        intrinsics->SetRadialDistortion(k1, k2, k3);
@@ -377,15 +404,16 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
 
        libmv::Tracks normalized_tracks(markers);
 
-       // printf("frames to init from: %d, %d\n", keyframe1, keyframe2);
+       LG << "frames to init from: " << keyframe1 << " " << keyframe2;
        libmv::vector<libmv::Marker> keyframe_markers =
                normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
-       // printf("number of markers for init: %d\n", keyframe_markers.size());
+       LG << "number of markers for init: " << keyframe_markers.size();
+
+       update_callback.invoke(0, "Initial reconstruction");
 
        libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction);
        libmv::EuclideanBundle(normalized_tracks, reconstruction);
-
-       libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction);
+       libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction, &update_callback);
 
        if (refine_intrinsics) {
                /* only a few combinations are supported but trust the caller */
@@ -402,9 +430,13 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
                if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
                        libmv_refine_flags |= libmv::BUNDLE_RADIAL_K2;
                }
-               libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags, reconstruction, intrinsics);
+
+               progress_update_callback(callback_customdata, 1.0, "Refining solution");
+               libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags,
+                       reconstruction, intrinsics);
        }
 
+       progress_update_callback(callback_customdata, 1.0, "Finishing solution");
        libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
        libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
 
index 8252a11739b2306e012cc1b5cda31460971cd2da..536f8a5f14cf4edb5fa631cd965c14ef5733d6ed 100644 (file)
@@ -64,10 +64,14 @@ void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
 #define LIBMV_REFINE_PRINCIPAL_POINT   (1<<1)
 #define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2)
 #define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4)
+
+typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
+
 int libmv_refineParametersAreValid(int parameters);
 
 struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
-                       int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3);
+                       int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       reconstruct_progress_update_cb progress_update_callback, void *callback_customdata);
 int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
 double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track);
 double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image);
diff --git a/extern/libmv/libmv/simple_pipeline/callbacks.cc b/extern/libmv/libmv/simple_pipeline/callbacks.cc
new file mode 100644 (file)
index 0000000..7e4bca6
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "libmv/simple_pipeline/callbacks.h"
+
+namespace libmv {
+
+void ProgressUpdateCallback::invoke(double progress, const char* message)
+{
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/callbacks.h b/extern/libmv/libmv/simple_pipeline/callbacks.h
new file mode 100644 (file)
index 0000000..675f73c
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBMV_SIMPLE_PIPELINE_CALLBACKS_H_
+#define LIBMV_SIMPLE_PIPELINE_CALLBACKS_H_
+
+namespace libmv {
+
+class ProgressUpdateCallback {
+ public:
+  virtual void invoke(double progress, const char *message);
+};
+
+}  // namespace libmv
+
+#endif  // LIBMV_SIMPLE_PIPELINE_MARKERS_H_
index 9512a41c00f33cd6d1a53fbfc96d73aca015be2e..382365e579f379b9bb46bad646ae1ce63c38a5c8 100644 (file)
@@ -21,6 +21,7 @@
 #include <cstdio>
 
 #include "libmv/logging/logging.h"
+#include "libmv/simple_pipeline/pipeline.h"
 #include "libmv/simple_pipeline/bundle.h"
 #include "libmv/simple_pipeline/intersect.h"
 #include "libmv/simple_pipeline/resect.h"
@@ -117,14 +118,32 @@ struct ProjectivePipelineRoutines {
 
 }  // namespace
 
+static void CompleteReconstructionLogProress(ProgressUpdateCallback *update_callback,
+    double progress,
+    const char *step = NULL)
+{
+  if(update_callback) {
+    char message[256];
+
+    if(step)
+      snprintf(message, sizeof(message), "Completing solution %d%% | %s", (int)(progress*100), step);
+    else
+      snprintf(message, sizeof(message), "Completing solution %d%%", (int)(progress*100));
+
+    update_callback->invoke(progress, message);
+  }
+}
+
 template<typename PipelineRoutines>
 void InternalCompleteReconstruction(
     const Tracks &tracks,
-    typename PipelineRoutines::Reconstruction *reconstruction) {
+    typename PipelineRoutines::Reconstruction *reconstruction,
+    ProgressUpdateCallback *update_callback = NULL) {
   int max_track = tracks.MaxTrack();
   int max_image = tracks.MaxImage();
   int num_resects = -1;
   int num_intersects = -1;
+  int tot_resects = 0;
   LG << "Max track: " << max_track;
   LG << "Max image: " << max_image;
   LG << "Number of markers: " << tracks.NumMarkers();
@@ -148,12 +167,17 @@ void InternalCompleteReconstruction(
       LG << "Got " << reconstructed_markers.size()
          << " reconstructed markers for track " << track;
       if (reconstructed_markers.size() >= 2) {
+        CompleteReconstructionLogProress(update_callback,
+                                         (double)tot_resects/(max_image));
         PipelineRoutines::Intersect(reconstructed_markers, reconstruction);
         num_intersects++;
         LG << "Ran Intersect() for track " << track;
       }
     }
     if (num_intersects) {
+      CompleteReconstructionLogProress(update_callback,
+                                       (double)tot_resects/(max_image),
+                                       "Bundling...");
       PipelineRoutines::Bundle(tracks, reconstruction);
       LG << "Ran Bundle() after intersections.";
     }
@@ -178,8 +202,11 @@ void InternalCompleteReconstruction(
       LG << "Got " << reconstructed_markers.size()
          << " reconstructed markers for image " << image;
       if (reconstructed_markers.size() >= 5) {
+        CompleteReconstructionLogProress(update_callback,
+                                         (double)tot_resects/(max_image));
         if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
           num_resects++;
+          tot_resects++;
           LG << "Ran Resect() for image " << image;
         } else {
           LG << "Failed Resect() for image " << image;
@@ -187,6 +214,9 @@ void InternalCompleteReconstruction(
       }
     }
     if (num_resects) {
+      CompleteReconstructionLogProress(update_callback,
+                                       (double)tot_resects/(max_image),
+                                       "Bundling...");
       PipelineRoutines::Bundle(tracks, reconstruction);
     }
     LG << "Did " << num_resects << " resects.";
@@ -208,6 +238,8 @@ void InternalCompleteReconstruction(
       }
     }
     if (reconstructed_markers.size() >= 5) {
+      CompleteReconstructionLogProress(update_callback,
+                                       (double)tot_resects/(max_image));
       if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
         num_resects++;
         LG << "Ran Resect() for image " << image;
@@ -217,6 +249,9 @@ void InternalCompleteReconstruction(
     }
   }
   if (num_resects) {
+    CompleteReconstructionLogProress(update_callback,
+                                     (double)tot_resects/(max_image),
+                                     "Bundling...");
     PipelineRoutines::Bundle(tracks, reconstruction);
   }
 }
@@ -244,7 +279,7 @@ double InternalReprojectionError(const Tracks &image_tracks,
         PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
     double ex = reprojected_marker.x - markers[i].x;
     double ey = reprojected_marker.y - markers[i].y;
-
+#if 0
     const int N = 100;
     char line[N];
     snprintf(line, N,
@@ -262,6 +297,7 @@ double InternalReprojectionError(const Tracks &image_tracks,
            ex,
            ey,
            sqrt(ex*ex + ey*ey));
+#endif
     total_error += sqrt(ex*ex + ey*ey);
   }
   LG << "Skipped " << num_skipped << " markers.";
@@ -289,9 +325,11 @@ double ProjectiveReprojectionError(
 }
 
 void EuclideanCompleteReconstruction(const Tracks &tracks,
-                                     EuclideanReconstruction *reconstruction) {
+                                     EuclideanReconstruction *reconstruction,
+                                     ProgressUpdateCallback *update_callback) {
   InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
-                                                            reconstruction);
+                                                            reconstruction,
+                                                            update_callback);
 }
 
 void ProjectiveCompleteReconstruction(const Tracks &tracks,
index b7dfcb7993a7ed33ccc8b878ebc69b42843749b3..e940b57bc0ddbaccc8edcd4075f759a72aa0beb2 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
 #define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
 
+#include "libmv/simple_pipeline/callbacks.h"
 #include "libmv/simple_pipeline/tracks.h"
 #include "libmv/simple_pipeline/reconstruction.h"
 
@@ -46,7 +47,8 @@ namespace libmv {
     \sa EuclideanResect, EuclideanIntersect, EuclideanBundle
 */
 void EuclideanCompleteReconstruction(const Tracks &tracks,
-                                     EuclideanReconstruction *reconstruction);
+                                     EuclideanReconstruction *reconstruction,
+                                     ProgressUpdateCallback *update_callback = NULL);
 
 /*!
     Estimate camera matrices and homogeneous 3D coordinates for all frames and
index 530d8c7a1dbba2a26e1d28985038509b33689e93..e55d40ebfe5aa99a89a035ec25dfe67918cca961 100644 (file)
@@ -34,6 +34,7 @@
 
 struct bGPDlayer;
 struct ImBuf;
+struct MovieReconstructContext;
 struct MovieTrackingTrack;
 struct MovieTrackingMarker;
 struct MovieTracking;
@@ -91,9 +92,14 @@ void BKE_tracking_sync_user(struct MovieClipUser *user, struct MovieTrackingCont
 int BKE_tracking_next(struct MovieTrackingContext *context);
 
 /* Camera solving */
-int BKE_tracking_can_solve(struct MovieTracking *tracking, char *error_msg, int error_size);
-
-float BKE_tracking_solve_reconstruction(struct MovieTracking *tracking, int width, int height);
+int BKE_tracking_can_reconstruct(struct MovieTracking *tracking, char *error_msg, int error_size);
+
+struct MovieReconstructContext* BKE_tracking_reconstruction_context_new(struct MovieTracking *tracking,
+                       int keyframe1, int keyframe2, int width, int height);
+void BKE_tracking_reconstruction_context_free(struct MovieReconstructContext *context);
+void BKE_tracking_solve_reconstruction(struct MovieReconstructContext *context,
+                       short *stop, short *do_update, float *progress, char *stats_message, int message_size);
+int BKE_tracking_finish_reconstruction(struct MovieReconstructContext *context, struct MovieTracking *tracking);
 
 struct MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(struct MovieTracking *tracking, int framenr);
 void BKE_tracking_get_interpolated_camera(struct MovieTracking *tracking, int framenr, float mat[4][4]);
index be20e36dfbe336299d010346e76797378dac861e..0a9412e9b360a210aad08f933a65b98c3a500284 100644 (file)
@@ -1279,7 +1279,7 @@ int BKE_tracking_next(MovieTrackingContext *context)
                                        #pragma omp critical
                                        {
                                                /* check if there's no keyframe/tracked markers before tracking marker.
-                                                   if so -- create disabled marker before currently tracking "segment" */
+                                                  if so -- create disabled marker before currently tracking "segment" */
                                                put_disabled_marker(track, marker, 1, 0);
                                        }
                                }
@@ -1331,6 +1331,36 @@ int BKE_tracking_next(MovieTrackingContext *context)
        return ok;
 }
 
+/*********************** camera solving *************************/
+
+typedef struct MovieReconstructContext {
+#ifdef WITH_LIBMV
+       struct libmv_Tracks *tracks;
+       int keyframe1, keyframe2;
+       short refine_flags;
+
+       struct libmv_Reconstruction *reconstruction;
+#endif
+
+       float focal_length;
+       float principal_point[2];
+       float k1, k2, k3;
+
+       float reprojection_error;
+
+       TracksMap *tracks_map;
+
+       int sfra, efra;
+} MovieReconstructContext;
+
+typedef struct ReconstructProgressData {
+       short *stop;
+       short *do_update;
+       float *progress;
+       char *stats_message;
+       int message_size;
+} ReconstructProgressData;
+
 #if WITH_LIBMV
 static struct libmv_Tracks *create_libmv_tracks(MovieTracking *tracking, int width, int height)
 {
@@ -1357,8 +1387,9 @@ static struct libmv_Tracks *create_libmv_tracks(MovieTracking *tracking, int wid
        return tracks;
 }
 
-static void retrieve_libmv_reconstruct_intrinscis(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction)
+static void retrieve_libmv_reconstruct_intrinscis(MovieReconstructContext *context, MovieTracking *tracking)
 {
+       struct libmv_Reconstruction *libmv_reconstruction= context->reconstruction;
        struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_ReconstructionExtractIntrinsics(libmv_reconstruction);
 
        float aspy= 1.0f/tracking->camera.pixel_aspect;
@@ -1378,14 +1409,14 @@ static void retrieve_libmv_reconstruct_intrinscis(MovieTracking *tracking, struc
        tracking->camera.k2= k2;
 }
 
-static int retrieve_libmv_reconstruct_tracks(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction)
+static int retrieve_libmv_reconstruct_tracks(MovieReconstructContext *context, MovieTracking *tracking)
 {
-       int tracknr= 0;
-       int sfra= INT_MAX, efra= INT_MIN, a, origin_set= 0;
-       MovieTrackingTrack *track;
+       struct libmv_Reconstruction *libmv_reconstruction= context->reconstruction;
        MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
        MovieReconstructedCamera *reconstructed;
-       int ok= 1;
+       MovieTrackingTrack *track;
+       int ok= 1, tracknr= 0, a, origin_set= 0;
+       int sfra= context->sfra, efra= context->efra;
        float imat[4][4];
 
        unit_m4(imat);
@@ -1408,30 +1439,6 @@ static int retrieve_libmv_reconstruct_tracks(MovieTracking *tracking, struct lib
                        printf("No bundle for track #%d '%s'\n", tracknr, track->name);
                }
 
-               if(track->markersnr) {
-                       int first= 0, last= track->markersnr;
-                       MovieTrackingMarker *first_marker= &track->markers[0];
-                       MovieTrackingMarker *last_marker= &track->markers[track->markersnr-1];
-
-                       /* find first not-disabled marker */
-                       while(first<track->markersnr-1 && first_marker->flag&MARKER_DISABLED) {
-                               first++;
-                               first_marker++;
-                       }
-
-                       /* find last not-disabled marker */
-                       while(last>=0 && last_marker->flag&MARKER_DISABLED) {
-                               last--;
-                               last_marker--;
-                       }
-
-                       if(first<track->markersnr-1)
-                               sfra= MIN2(sfra, first_marker->framenr);
-
-                       if(last>=0)
-                               efra= MAX2(efra, last_marker->framenr);
-               }
-
                track= track->next;
                tracknr++;
        }
@@ -1494,12 +1501,14 @@ static int retrieve_libmv_reconstruct_tracks(MovieTracking *tracking, struct lib
        return ok;
 }
 
-static int retrieve_libmv_reconstruct(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction)
+static int retrieve_libmv_reconstruct(MovieReconstructContext *context, MovieTracking *tracking)
 {
+       tracks_map_merge(context->tracks_map, tracking);
+
        /* take the intrinscis back from libmv */
-       retrieve_libmv_reconstruct_intrinscis(tracking, libmv_reconstruction);
+       retrieve_libmv_reconstruct_intrinscis(context, tracking);
 
-       return retrieve_libmv_reconstruct_tracks(tracking, libmv_reconstruction);
+       return retrieve_libmv_reconstruct_tracks(context, tracking);
 }
 
 static int get_refine_intrinsics_flags(MovieTracking *tracking)
@@ -1541,7 +1550,7 @@ static int count_tracks_on_both_keyframes(MovieTracking *tracking)
 }
 #endif
 
-int BKE_tracking_can_solve(MovieTracking *tracking, char *error_msg, int error_size)
+int BKE_tracking_can_reconstruct(MovieTracking *tracking, char *error_msg, int error_size)
 {
 #if WITH_LIBMV
        if(count_tracks_on_both_keyframes(tracking)<8) {
@@ -1552,46 +1561,161 @@ int BKE_tracking_can_solve(MovieTracking *tracking, char *error_msg, int error_s
        return 1;
 #else
        BLI_strncpy(error_msg, "Blender is compiled without motion tracking library", error_size);
-       (void)tracking;
+       (void) tracking;
 
        return 0;
 #endif
 }
 
-float BKE_tracking_solve_reconstruction(MovieTracking *tracking, int width, int height)
+MovieReconstructContext* BKE_tracking_reconstruction_context_new(MovieTracking *tracking,
+                       int keyframe1, int keyframe2, int width, int height)
 {
-#if WITH_LIBMV
-       {
-               MovieTrackingCamera *camera= &tracking->camera;
-               float aspy= 1.0f/tracking->camera.pixel_aspect;
-               struct libmv_Tracks *tracks= create_libmv_tracks(tracking, width, height*aspy);
-               struct libmv_Reconstruction *reconstruction = libmv_solveReconstruction(tracks,
-                       tracking->settings.keyframe1, tracking->settings.keyframe2,
-                       get_refine_intrinsics_flags(tracking),
-                       camera->focal,
-                       camera->principal[0], camera->principal[1]*aspy,
-                       camera->k1, camera->k2, camera->k3);
-               float error= libmv_reprojectionError(reconstruction);
+       MovieReconstructContext *context= MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
+       MovieTrackingCamera *camera= &tracking->camera;
+       float aspy= 1.0f/tracking->camera.pixel_aspect;
+       int num_tracks= BLI_countlist(&tracking->tracks);
+       int sfra= INT_MAX, efra= INT_MIN;
+       MovieTrackingTrack *track;
 
-               tracking->reconstruction.error= error;
+       context->tracks_map= tracks_map_new(num_tracks, 0);
+       track= tracking->tracks.first;
+       while(track) {
+               int first= 0, last= track->markersnr;
+               MovieTrackingMarker *first_marker= &track->markers[0];
+               MovieTrackingMarker *last_marker= &track->markers[track->markersnr-1];
+
+               /* find first not-disabled marker */
+               while(first<track->markersnr-1 && first_marker->flag&MARKER_DISABLED) {
+                       first++;
+                       first_marker++;
+               }
 
-               if(!retrieve_libmv_reconstruct(tracking, reconstruction))
-                       error= -1.0f;
+               /* find last not-disabled marker */
+               while(last>=0 && last_marker->flag&MARKER_DISABLED) {
+                       last--;
+                       last_marker--;
+               }
 
-               libmv_destroyReconstruction(reconstruction);
-               libmv_tracksDestroy(tracks);
+               if(first<track->markersnr-1)
+                       sfra= MIN2(sfra, first_marker->framenr);
 
-               tracking->reconstruction.flag|= TRACKING_RECONSTRUCTED;
+               if(last>=0)
+                       efra= MAX2(efra, last_marker->framenr);
 
-               return error;
+               tracks_map_insert(context->tracks_map, track, NULL);
+
+               track= track->next;
        }
+
+       context->sfra= sfra;
+       context->efra= efra;
+
+#ifdef WITH_LIBMV
+       context->tracks= create_libmv_tracks(tracking, width, height*aspy);
+       context->keyframe1= keyframe1;
+       context->keyframe2= keyframe2;
+       context->refine_flags= get_refine_intrinsics_flags(tracking);
 #else
-       (void)tracking;
-       (void)width;
-       (void)height;
+       (void) width;
+       (void) height;
+       (void) keyframe1;
+       (void) keyframe2;
+#endif
+
+       context->focal_length= camera->focal;
+       context->principal_point[0]= camera->principal[0];
+       context->principal_point[1]= camera->principal[1]*aspy;
 
-       return -1.0f;
+       context->k1= camera->k1;
+       context->k2= camera->k2;
+       context->k2= camera->k2;
+
+       return context;
+}
+
+void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
+{
+#ifdef WITH_LIBMV
+       if(context->reconstruction)
+                       libmv_destroyReconstruction(context->reconstruction);
+
+       libmv_tracksDestroy(context->tracks);
+#endif
+
+       tracks_map_free(context->tracks_map, NULL);
+
+       MEM_freeN(context);
+}
+
+static void solve_reconstruction_update_cb(void *customdata, double progress, const char *message)
+{
+       ReconstructProgressData *progressdata= customdata;
+
+       if(progressdata->progress) {
+               *progressdata->progress= progress;
+               *progressdata->do_update= 1;
+       }
+
+       BLI_snprintf(progressdata->stats_message, progressdata->message_size,
+                       "Solving camera | %s", message);
+}
+
+#if 0
+static int solve_reconstruction_testbreak_cb(void *customdata)
+{
+       ReconstructProgressData *progressdata= customdata;
+
+       if(progressdata->stop && *progressdata->stop)
+               return 1;
+
+       return G.afbreek;
+}
 #endif
+
+void BKE_tracking_solve_reconstruction(MovieReconstructContext *context, short *stop,
+                       short *do_update, float *progress, char *stats_message, int message_size)
+{
+#ifdef WITH_LIBMV
+       float error;
+
+       ReconstructProgressData progressdata;
+
+       progressdata.stop= stop;
+       progressdata.do_update= do_update;
+       progressdata.progress= progress;
+       progressdata.stats_message= stats_message;
+       progressdata.message_size= message_size;
+
+       context->reconstruction = libmv_solveReconstruction(context->tracks,
+               context->keyframe1, context->keyframe2,
+               context->refine_flags,
+               context->focal_length,
+               context->principal_point[0], context->principal_point[1],
+               context->k1, context->k2, context->k3,
+               solve_reconstruction_update_cb, &progressdata);
+
+       error= libmv_reprojectionError(context->reconstruction);
+
+       context->reprojection_error= error;
+#else
+       (void) context;
+       (void) stop;
+       (void) do_update;
+       (void) progress;
+#endif
+}
+
+int BKE_tracking_finish_reconstruction(MovieReconstructContext *context, MovieTracking *tracking)
+{
+       tracking->reconstruction.error= context->reprojection_error;
+       tracking->reconstruction.flag|= TRACKING_RECONSTRUCTED;
+
+#ifdef WITH_LIBMV
+       if(!retrieve_libmv_reconstruct(context, tracking))
+               return 0;
+#endif
+
+       return 1;
 }
 
 void BKE_track_unique_name(MovieTracking *tracking, MovieTrackingTrack *track)
index e38e62aa6910c4bbc034ce7f786f58d54046cbc4..3db36a075d7ee40c71ad2a91237ef214025fc62a 100644 (file)
@@ -5966,6 +5966,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
 
        clip->anim= NULL;
        clip->tracking_context= NULL;
+       clip->tracking.stats= NULL;
 
        clip->tracking.stabilization.ok= 0;
        clip->tracking.stabilization.scaleibuf= NULL;
index 630038d4c6be6ce7bde02b12da742fdd2e5599bd..a53da4ce0069c998cf66e7bdc016e0bb8471f0a2 100644 (file)
@@ -191,27 +191,38 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
 
 static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar)
 {
+       MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
        char str[256]= {0};
+       int block= 0;
 
-       if(sc->flag&SC_LOCK_SELECTION)
-               strcpy(str, "Locked");
+       if(tracking->stats) {
+               BLI_strncpy(str, tracking->stats->message, sizeof(str));
+               block= 1;
+       } else {
+               if(sc->flag&SC_LOCK_SELECTION)
+                       strcpy(str, "Locked");
+       }
 
        if(str[0]) {
                uiStyle *style= UI_GetStyle();
-               int fontsize, fontwidth;
                int fontid= style->widget.uifont_id;
+               int fontwidth;
+
+               BLF_size(fontid, 11.0f, 72);
 
-               BLF_size(fontid, 11.0f, U.dpi);
-               fontsize= BLF_height(fontid, str);
-               fontwidth= BLF_width(fontid, str);
+               if(block)
+                       fontwidth= ar->winx;
+               else
+                       fontwidth= BLF_width(fontid, str);
 
                glEnable(GL_BLEND);
 
                glColor4f(0.0f, 0.0f, 0.0f, 0.6f);
-               glRecti(0, ar->winy-fontsize-9, fontwidth+12, ar->winy);
+               glRecti(0, ar->winy-17, fontwidth+12, ar->winy);
 
                glColor3f(1.0f, 1.0f, 1.0f);
-               BLF_position(fontid, 6.0f, ar->winy-fontsize-5.0f, 0.0f);
+               BLF_position(fontid, 6.0f, ar->winy-13.0f, 0.0f);
                BLF_draw(fontid, str, strlen(str));
 
                glDisable(GL_BLEND);
index 6057cacbcce144e0f4e3d8bffeb84a32756d43cf..89c58ab5d81a0d56609b2f3be705fb66ebfbe1a9 100644 (file)
@@ -1485,7 +1485,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
 
 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
 {
-       /* no running blender, remove handler and pass through */
+       /* no running tracking, remove handler and pass through */
        if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
                return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
 
@@ -1522,61 +1522,201 @@ void CLIP_OT_track_markers(wmOperatorType *ot)
 
 /********************** solve camera operator *********************/
 
-static int solve_camera_exec(bContext *C, wmOperator *op)
+typedef struct {
+       Scene *scene;
+       MovieClip *clip;
+       MovieClipUser user;
+
+       ReportList *reports;
+
+       char stats_message[256];
+
+       struct MovieReconstructContext *context;
+} SolveCameraJob;
+
+static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        Scene *scene= CTX_data_scene(C);
        MovieTracking *tracking= &clip->tracking;
+       MovieTrackingSettings *settings= &clip->tracking.settings;
        int width, height;
-       float error;
-       char error_msg[255];
 
-       if(!BKE_tracking_can_solve(tracking, error_msg, sizeof(error_msg))) {
-               BKE_report(op->reports, RPT_ERROR, error_msg);
-
-               return OPERATOR_CANCELLED;
-       }
+       if(!BKE_tracking_can_reconstruct(tracking, error_msg, max_error))
+               return 0;
 
        /* could fail if footage uses images with different sizes */
        BKE_movieclip_get_size(clip, &sc->user, &width, &height);
 
-       error= BKE_tracking_solve_reconstruction(tracking, width, height);
+       scj->clip= clip;
+       scj->scene= scene;
+       scj->reports= op->reports;
+       scj->user= sc->user;
+
+       scj->context= BKE_tracking_reconstruction_context_new(tracking,
+                       settings->keyframe1, settings->keyframe2, width, height);
+
+       tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
+
+       return 1;
+}
+
+static void solve_camera_updatejob(void *scv)
+{
+       SolveCameraJob *scj= (SolveCameraJob *)scv;
+       MovieTracking *tracking= &scj->clip->tracking;
+
+       BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
+}
+
+static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
+{
+       SolveCameraJob *scj= (SolveCameraJob *)scv;
+
+       BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
+                       scj->stats_message, sizeof(scj->stats_message));
+}
+
+static void solve_camera_freejob(void *scv)
+{
+       SolveCameraJob *scj= (SolveCameraJob *)scv;
+       MovieTracking *tracking= &scj->clip->tracking;
+       Scene *scene= scj->scene;
+       MovieClip *clip= scj->clip;
+       int solved;
+
+       if(!scj->context) {
+               /* job weren't fully initialized due to some error */
+               MEM_freeN(scj);
+               return;
+       }
 
-       if(error<0)
-               BKE_report(op->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
+       solved= BKE_tracking_finish_reconstruction(scj->context, tracking);
+
+       if(!solved)
+               BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
        else
-               BKE_reportf(op->reports, RPT_INFO, "Average reprojection error %.3f", error);
+               BKE_reportf(scj->reports, RPT_INFO, "Average reprojection error %.3f", tracking->reconstruction.error);
 
+       /* set currently solved clip as active for scene */
        if(scene->clip)
                id_us_min(&clip->id);
 
        scene->clip= clip;
        id_us_plus(&clip->id);
 
+       /* set blender camera focal length so result would look fine there */
        if(!scene->camera)
                scene->camera= scene_find_camera(scene);
 
        if(scene->camera) {
-               /* set blender camera focal length so result would look fine there */
                Camera *camera= (Camera*)scene->camera->data;
+               int width, height;
+
+               BKE_movieclip_get_size(clip, &scj->user, &width, &height);
 
                BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
 
-               WM_event_add_notifier(C, NC_OBJECT, camera);
+               WM_main_add_notifier(NC_OBJECT, camera);
        }
 
+       MEM_freeN(tracking->stats);
+       tracking->stats= NULL;
+
        DAG_id_tag_update(&clip->id, 0);
 
-       WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
-       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+       WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
+       WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, NULL);
 
        /* update active clip displayed in scene buttons */
-       WM_event_add_notifier(C, NC_SCENE, scene);
+       WM_main_add_notifier(NC_SCENE, scene);
+
+       BKE_tracking_reconstruction_context_free(scj->context);
+       MEM_freeN(scj);
+}
+
+static int solve_camera_exec(bContext *C, wmOperator *op)
+{
+       SolveCameraJob *scj;
+       char error_msg[256]= "\0";
+
+       scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+       if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+               if(error_msg[0])
+                       BKE_report(op->reports, RPT_ERROR, error_msg);
+
+               solve_camera_freejob(scj);
+
+               return OPERATOR_CANCELLED;
+       }
+
+       solve_camera_startjob(scj, NULL, NULL, NULL);
+
+       solve_camera_freejob(scj);
 
        return OPERATOR_FINISHED;
 }
 
+static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+       SolveCameraJob *scj;
+       ScrArea *sa= CTX_wm_area(C);
+       SpaceClip *sc= CTX_wm_space_clip(C);
+       MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       wmJob *steve;
+       char error_msg[256]= "\0";
+
+       scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+       if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+               if(error_msg[0])
+                       BKE_report(op->reports, RPT_ERROR, error_msg);
+
+               solve_camera_freejob(scj);
+
+               return OPERATOR_CANCELLED;
+       }
+
+       BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
+
+       /* hide reconstruction statistics from previous solve */
+       clip->tracking.reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
+       WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
+
+       /* setup job */
+       steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera", WM_JOB_PROGRESS);
+       WM_jobs_customdata(steve, scj, solve_camera_freejob);
+       WM_jobs_timer(steve, 0.1, NC_MOVIECLIP|NA_EVALUATED, 0);
+       WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
+
+       G.afbreek= 0;
+
+       WM_jobs_start(CTX_wm_manager(C), steve);
+       WM_cursor_wait(0);
+
+       /* add modal handler for ESC */
+       WM_event_add_modal_handler(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+{
+       /* no running solver, remove handler and pass through */
+       if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
+               return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
+
+       /* running tracking */
+       switch (event->type) {
+               case ESCKEY:
+                       return OPERATOR_RUNNING_MODAL;
+                       break;
+       }
+
+       return OPERATOR_PASS_THROUGH;
+}
+
 void CLIP_OT_solve_camera(wmOperatorType *ot)
 {
        /* identifiers */
@@ -1586,6 +1726,8 @@ void CLIP_OT_solve_camera(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= solve_camera_exec;
+       ot->invoke= solve_camera_invoke;
+       ot->modal= solve_camera_modal;
        ot->poll= ED_space_clip_poll;
 
        /* flags */
index c795cea88fb6118abc5d82151ae333f4b4d1a9f6..c4e6fcc4dc8ee5b60f6bb571d8d8ec41d618a99a 100644 (file)
@@ -172,6 +172,10 @@ typedef struct MovieTrackingReconstruction {
        struct MovieReconstructedCamera *cameras;       /* reconstructed cameras */
 } MovieTrackingReconstruction;
 
+typedef struct MovieTrackingStats {
+       char message[256];
+} MovieTrackingStats;
+
 typedef struct MovieTracking {
        MovieTrackingSettings settings; /* different tracking-related settings */
        MovieTrackingCamera camera;             /* camera intrinsics */
@@ -179,6 +183,8 @@ typedef struct MovieTracking {
        MovieTrackingReconstruction reconstruction;     /* reconstruction data */
        MovieTrackingStabilization stabilization;       /* stabilization data */
        MovieTrackingTrack *act_track;          /* active track */
+
+       MovieTrackingStats *stats;              /* statistics displaying in clip editor */
 } MovieTracking;
 
 /* MovieTrackingCamera->units */