Camera tracking: expose progress and status from camera solver into interface
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 22 Nov 2011 14:45:22 +0000 (14:45 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 22 Nov 2011 14:45:22 +0000 (14:45 +0000)
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.

extern/libmv/libmv-capi.cpp
extern/libmv/libmv-capi.h
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 8c453944e9de780485a2631d341da0a33af12bbb..6be8d838d37eca746287db2364a037c7ced59a24 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"
@@ -356,7 +358,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();
@@ -377,15 +380,17 @@ 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();
+
+       progress_update_callback(callback_customdata, 0, "Initial reconstruction");
 
        libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction);
        libmv::EuclideanBundle(normalized_tracks, reconstruction);
 
-       libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction);
+       libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction, progress_update_callback, callback_customdata);
 
        if (refine_intrinsics) {
                /* only a few combinations are supported but trust the caller */
@@ -402,9 +407,12 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
                if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
                        libmv_refine_flags |= libmv::BUNDLE_RADIAL_K2;
                }
+
+               progress_update_callback(callback_customdata, 0, "Refining solution");
                libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags, reconstruction, intrinsics);
        }
 
+       progress_update_callback(callback_customdata, 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);
index 9512a41c00f33cd6d1a53fbfc96d73aca015be2e..93f41d237e85bd9c3861ae7008f69bc0997d451e 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"
@@ -120,11 +121,14 @@ struct ProjectivePipelineRoutines {
 template<typename PipelineRoutines>
 void InternalCompleteReconstruction(
     const Tracks &tracks,
-    typename PipelineRoutines::Reconstruction *reconstruction) {
+    typename PipelineRoutines::Reconstruction *reconstruction,
+    progress_update_callback update_callback,
+    void *update_customdata) {
   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();
@@ -180,6 +184,9 @@ void InternalCompleteReconstruction(
       if (reconstructed_markers.size() >= 5) {
         if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
           num_resects++;
+          tot_resects++;
+          if(update_callback)
+            update_callback(update_customdata, (float)tot_resects/(max_image), "Completing solution");
           LG << "Ran Resect() for image " << image;
         } else {
           LG << "Failed Resect() for image " << image;
@@ -211,6 +218,8 @@ void InternalCompleteReconstruction(
       if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
         num_resects++;
         LG << "Ran Resect() for image " << image;
+        if(update_callback)
+          update_callback(update_customdata, (float)tot_resects/(max_image), "Completing solution");
       } else {
         LG << "Failed Resect() for image " << image;
       }
@@ -289,15 +298,20 @@ double ProjectiveReprojectionError(
 }
 
 void EuclideanCompleteReconstruction(const Tracks &tracks,
-                                     EuclideanReconstruction *reconstruction) {
+                                     EuclideanReconstruction *reconstruction,
+                                     progress_update_callback update_callback,
+                                     void *update_customdata) {
   InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
-                                                            reconstruction);
+                                                            reconstruction,
+                                                            update_callback,
+                                                            update_customdata);
 }
 
 void ProjectiveCompleteReconstruction(const Tracks &tracks,
                                       ProjectiveReconstruction *reconstruction) {
   InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
-                                                             reconstruction);
+                                                             reconstruction,
+                                                             NULL, NULL);
 }
 
 void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
index b7dfcb7993a7ed33ccc8b878ebc69b42843749b3..dc1a79506f2f1369060b8a0afa423355d46d9cb9 100644 (file)
@@ -26,6 +26,8 @@
 
 namespace libmv {
 
+typedef void (*progress_update_callback) (void *customdata, double progress, const char *message);
+
 /*!
     Estimate camera poses and scene 3D coordinates for all frames and tracks.
 
@@ -46,7 +48,9 @@ namespace libmv {
     \sa EuclideanResect, EuclideanIntersect, EuclideanBundle
 */
 void EuclideanCompleteReconstruction(const Tracks &tracks,
-                                     EuclideanReconstruction *reconstruction);
+                                     EuclideanReconstruction *reconstruction,
+                                     progress_update_callback update_callback,
+                                     void *update_customdata);
 
 /*!
     Estimate camera matrices and homogeneous 3D coordinates for all frames and
index d844873ef89bd88326487715c54626e287b43096..4a3b50533455ab2a65e3cd968a553898bebb712f 100644 (file)
@@ -97,7 +97,7 @@ struct MovieReconstructContext* BKE_tracking_reconstruction_context_new(struct M
                        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);
+                       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);
index 67edec3c21e5b4fafad1c7ed1c16a711ae713ac1..cb58abbfa24128c411734e30bff7a895db319a6e 100644 (file)
@@ -1328,6 +1328,8 @@ typedef struct ReconstructProgressData {
        short *stop;
        short *do_update;
        float *progress;
+       char *stats_message;
+       int message_size;
 } ReconstructProgressData;
 
 #if WITH_LIBMV
@@ -1616,20 +1618,7 @@ void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
        MEM_freeN(context);
 }
 
-#if 0
-
-/* TODO: this two callbacks are supposed to be used to make solving more
-         interactive with the interface, so approximated progress would be
-         displayed and it's also can be nice to have option to break solving
-         (would fit other jobs design in blender)
-
-         customdata is used to pass some context data to libmv which can be used
-         later for set progress came form libmv to job
-
-         keir, it's not necessary that progress is linear and it's not necessary
-         that breaking happens immediately */
-
-static void solve_reconstruction_update_cb(void *customdata, float progress)
+static void solve_reconstruction_update_cb(void *customdata, double progress, const char *message)
 {
        ReconstructProgressData *progressdata= customdata;
 
@@ -1637,8 +1626,15 @@ static void solve_reconstruction_update_cb(void *customdata, float progress)
                *progressdata->progress= progress;
                *progressdata->do_update= 1;
        }
+
+       if(progress) {
+               BLI_snprintf(progressdata->stats_message, progressdata->message_size, "%s | %d%%", message, (int)(progress*100));
+       } else {
+               BLI_strncpy(progressdata->stats_message, message, progressdata->message_size);
+       }
 }
 
+#if 0
 static int solve_reconstruction_testbreak_cb(void *customdata)
 {
        ReconstructProgressData *progressdata= customdata;
@@ -1650,7 +1646,8 @@ static int solve_reconstruction_testbreak_cb(void *customdata)
 }
 #endif
 
-void BKE_tracking_solve_reconstruction(MovieReconstructContext *context, short *stop, short *do_update, float *progress)
+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;
@@ -1660,13 +1657,16 @@ void BKE_tracking_solve_reconstruction(MovieReconstructContext *context, short *
        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);
+               context->k1, context->k2, context->k3,
+               solve_reconstruction_update_cb, &progressdata);
 
        error= libmv_reprojectionError(context->reconstruction);
 
index a6aecac1c34db8b460d263f2c0957a6d9cdea7f1..817322584588de8fb2d137271ae9cd059b50186e 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 aa610fb4485b101045d9e880a6501bece7cdf82c..dc3a857c2c98f82bdb07b4431510715130d6c6c2 100644 (file)
@@ -1511,13 +1511,13 @@ void CLIP_OT_track_markers(wmOperatorType *ot)
 /********************** solve camera operator *********************/
 
 typedef struct {
-       MovieClip *clip;
        Scene *scene;
+       MovieClip *clip;
+       MovieClipUser user;
 
        ReportList *reports;
 
-       MovieClipUser user;
-
+       char stats_message[256];
        struct MovieReconstructContext *context;
 } SolveCameraJob;
 
@@ -1544,14 +1544,25 @@ static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op
        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);
+       BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
+                       scj->stats_message, sizeof(scj->stats_message));
 }
 
 static void solve_camera_freejob(void *scv)
@@ -1597,6 +1608,9 @@ static void solve_camera_freejob(void *scv)
                WM_main_add_notifier(NC_OBJECT, camera);
        }
 
+       MEM_freeN(tracking->stats);
+       tracking->stats= NULL;
+
        DAG_id_tag_update(&clip->id, 0);
 
        WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
@@ -1637,6 +1651,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
        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";
 
@@ -1650,6 +1665,8 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
                return OPERATOR_CANCELLED;
        }
 
+       BLI_strncpy(tracking->stats->message, "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);
@@ -1658,7 +1675,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
        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.2, NC_MOVIECLIP|NA_EVALUATED, 0);
-       WM_jobs_callbacks(steve, solve_camera_startjob, NULL, NULL, NULL);
+       WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
 
        G.afbreek= 0;
 
index cbac3721ac38df2316234b153382b79bb46bfc08..88173e6cac337f9c3abbc0f26d68a06e531be500 100644 (file)
@@ -165,6 +165,11 @@ typedef struct MovieTrackingReconstruction {
        struct MovieReconstructedCamera *cameras;       /* reconstructed cameras */
 } MovieTrackingReconstruction;
 
+typedef struct MovieTrackingStats {
+       float progress;
+       char message[256];
+} MovieTrackingStats;
+
 typedef struct MovieTracking {
        MovieTrackingSettings settings; /* different tracking-related settings */
        char pad2[4];
@@ -174,6 +179,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 */