Implement per-frame track reprojection error visualization
authorSergey Sharybin <sergey.vfx@gmail.com>
Sun, 13 Oct 2013 20:26:29 +0000 (22:26 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 25 Dec 2013 13:24:04 +0000 (19:24 +0600)
It is now possible to display per-frame track reprojection
error in curve view of clip editor. Simply enable corresponding
option in filter buttons.

Currently displayed using blue color which might confuse with
average reprojection error, further color tweaks are possible
and easy.

Also changed icon track x/y curves. Better icons here are
really appreciated.

release/scripts/startup/bl_ui/space_clip.py
source/blender/editors/space_clip/clip_graph_draw.c
source/blender/editors/space_clip/clip_graph_ops.c
source/blender/editors/space_clip/clip_intern.h
source/blender/editors/space_clip/clip_utils.c
source/blender/editors/space_clip/space_clip.c
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_space.c

index d6a63c6497ba6d256bed51708145c4172b73a3ac..3a203c77463f3ae400351ef845668dae3b31f552 100644 (file)
@@ -98,7 +98,8 @@ class CLIP_HT_header(Header):
                     sub.active = clip.tracking.reconstruction.is_valid
                     sub.prop(sc, "show_graph_frames", icon='SEQUENCE', text="")
 
-                    row.prop(sc, "show_graph_tracks", icon='ANIM', text="")
+                    row.prop(sc, "show_graph_tracks_motion", icon='IPO', text="")
+                    row.prop(sc, "show_graph_tracks_error", icon='ANIM', text="")
                 else:
                     row.prop(sc, "show_filters", icon='DISCLOSURE_TRI_RIGHT',
                              text="Filters")
index 80b844464dbae901ff226dbd8e3bd60ea42251e4..16845bb10fbb45a97e203f974e5b5ef0af510d79 100644 (file)
@@ -116,7 +116,7 @@ static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track,
        glBegin(GL_LINE_STRIP);
 }
 
-static void tracking_segment_end_cb(void *UNUSED(userdata))
+static void tracking_segment_end_cb(void *UNUSED(userdata), int UNUSED(coord))
 {
        glEnd();
 
@@ -151,7 +151,7 @@ static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track,
        }
 }
 
-static void draw_tracks_curves(View2D *v2d, SpaceClip *sc)
+static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc)
 {
        MovieClip *clip = ED_space_clip_get_clip(sc);
        MovieTracking *tracking = &clip->tracking;
@@ -191,6 +191,108 @@ static void draw_tracks_curves(View2D *v2d, SpaceClip *sc)
                                           &userdata, tracking_segment_knot_cb, NULL, NULL);
 }
 
+typedef struct TrackErrorCurveUserData {
+       MovieTracking *tracking;
+       MovieTrackingObject *tracking_object;
+       MovieTrackingTrack *active_track;
+       bool matrix_initialized;
+       int matrix_frame;
+       float projection_matrix[4][4];
+       int width, height;
+       float aspy;
+} TrackErrorCurveUserData;
+
+static void tracking_error_segment_point_cb(void *userdata,
+                                            MovieTrackingTrack *track, MovieTrackingMarker *marker,
+                                            int coord, int scene_framenr, float UNUSED(value))
+{
+       if (coord == 1) {
+               TrackErrorCurveUserData *data = (TrackErrorCurveUserData *) userdata;
+               float reprojected_position[4], bundle_position[4], marker_position[2], delta[2];
+               float reprojection_error;
+
+               if (!data->matrix_initialized || data->matrix_frame != scene_framenr) {
+                       BKE_tracking_get_projection_matrix(data->tracking, data->tracking_object,
+                                                          scene_framenr, data->width, data->height,
+                                                          data->projection_matrix);
+               }
+
+               copy_v3_v3(bundle_position, track->bundle_pos);
+               bundle_position[3] = 1;
+
+               mul_v4_m4v4(reprojected_position, data->projection_matrix, bundle_position);
+               reprojected_position[0] = (reprojected_position[0] /
+                                         (reprojected_position[3] * 2.0f) + 0.5f) * data->width;
+               reprojected_position[1] = (reprojected_position[1] /
+                                         (reprojected_position[3] * 2.0f) + 0.5f) * data->height * data->aspy;
+
+               BKE_tracking_distort_v2(data->tracking, reprojected_position, reprojected_position);
+
+               marker_position[0] = (marker->pos[0] + track->offset[0]) * data->width;
+               marker_position[1] = (marker->pos[1] + track->offset[1]) * data->height * data->aspy;
+
+               sub_v2_v2v2(delta, reprojected_position, marker_position);
+               reprojection_error = len_v2(delta);
+
+               glVertex2f(scene_framenr, reprojection_error);
+       }
+}
+
+static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord)
+{
+       if (coord == 1) {
+               TrackErrorCurveUserData *data = (TrackErrorCurveUserData *) userdata;
+               float col[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+
+               if (track == data->active_track) {
+                       col[3] = 1.0f;
+                       glLineWidth(2.0f);
+               }
+               else {
+                       col[3] = 0.5f;
+                       glLineWidth(1.0f);
+               }
+
+               glColor4fv(col);
+
+               glBegin(GL_LINE_STRIP);
+       }
+}
+
+static void tracking_error_segment_end_cb(void *UNUSED(userdata), int coord)
+{
+       if (coord == 1) {
+               glEnd();
+               glLineWidth(1.0f);
+       }
+}
+
+static void draw_tracks_error_curves(SpaceClip *sc)
+{
+       MovieClip *clip = ED_space_clip_get_clip(sc);
+       MovieTracking *tracking = &clip->tracking;
+       TrackErrorCurveUserData data;
+
+       data.tracking = tracking;
+       data.tracking_object = BKE_tracking_object_get_active(tracking);
+       data.active_track = BKE_tracking_track_get_active(tracking);
+       data.matrix_initialized = false;
+       BKE_movieclip_get_size(clip, &sc->user, &data.width, &data.height);
+       data.aspy = 1.0f / tracking->camera.pixel_aspect;
+
+       if (!data.width || !data.height) {
+               return;
+       }
+
+       clip_graph_tracking_values_iterate(sc,
+                                          (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
+                                          (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
+                                          &data,
+                                          tracking_error_segment_point_cb,
+                                          tracking_error_segment_start_cb,
+                                          tracking_error_segment_end_cb);
+}
+
 static void draw_frame_curves(SpaceClip *sc)
 {
        MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -237,8 +339,11 @@ void clip_draw_graph(SpaceClip *sc, ARegion *ar, Scene *scene)
        UI_view2d_grid_free(grid);
 
        if (clip) {
-               if (sc->flag & SC_SHOW_GRAPH_TRACKS)
-                       draw_tracks_curves(v2d, sc);
+               if (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION)
+                       draw_tracks_motion_curves(v2d, sc);
+
+               if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR)
+                       draw_tracks_error_curves(sc);
 
                if (sc->flag & SC_SHOW_GRAPH_FRAMES)
                        draw_frame_curves(sc);
index e0062ecd24316fa6196d618f12f19d7f2e9ca456..22b14df2b38f414742f83740cbfe6dca9f9aa9cf 100644 (file)
@@ -130,7 +130,7 @@ static void find_nearest_tracking_segment_cb(void *userdata, MovieTrackingTrack
        copy_v2_v2(data->prev_co, co);
 }
 
-static void find_nearest_tracking_segment_end_cb(void *userdata)
+static void find_nearest_tracking_segment_end_cb(void *userdata, int UNUSED(coord))
 {
        MouseSelectUserData *data = userdata;
 
index af9d8f9713890c0a00c4755fe864a0ba8a276c86..811f8e2eaab957100bd33c25e6623bcfbc7dc92a 100644 (file)
@@ -125,12 +125,12 @@ void ED_clip_tool_props_register(struct ARegionType *art);
 void clip_graph_tracking_values_iterate_track(struct SpaceClip *sc, struct MovieTrackingTrack *track, void *userdata,
                                               void (*func)(void *userdata, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int coord, int scene_framenr, float val),
                                               void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord),
-                                              void (*segment_end)(void *userdata));
+                                              void (*segment_end)(void *userdata, int coord));
 
 void clip_graph_tracking_values_iterate(struct SpaceClip *sc, bool selected_only, bool include_hidden, void *userdata,
                                         void (*func)(void *userdata, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int coord, int scene_framenr, float val),
                                         void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord),
-                                        void (*segment_end)(void *userdata));
+                                        void (*segment_end)(void *userdata, int coord));
 
 void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool include_hidden, void *userdata,
                                  void (*func)(void *userdata, struct MovieTrackingMarker *marker));
index 060531ae82c5ef7b6e21f7534dd9019bb99df32c..4b90fa5839f26b0e89fbc0fa063d5ad3075fb5bb 100644 (file)
@@ -70,7 +70,7 @@ void clip_graph_tracking_values_iterate_track(
         void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord,
                      int scene_framenr, float val),
         void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord),
-        void (*segment_end)(void *userdata))
+        void (*segment_end)(void *userdata, int coord))
 {
        MovieClip *clip = ED_space_clip_get_clip(sc);
        int width, height, coord;
@@ -89,7 +89,7 @@ void clip_graph_tracking_values_iterate_track(
                        if (marker->flag & MARKER_DISABLED) {
                                if (open) {
                                        if (segment_end)
-                                               segment_end(userdata);
+                                               segment_end(userdata, coord);
 
                                        open = false;
                                }
@@ -121,7 +121,7 @@ void clip_graph_tracking_values_iterate_track(
 
                if (open) {
                        if (segment_end)
-                               segment_end(userdata);
+                               segment_end(userdata, coord);
                }
        }
 }
@@ -131,7 +131,7 @@ void clip_graph_tracking_values_iterate(
         void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker,
                      int coord, int scene_framenr, float val),
         void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord),
-        void (*segment_end)(void *userdata))
+        void (*segment_end)(void *userdata, int coord))
 {
        MovieClip *clip = ED_space_clip_get_clip(sc);
        MovieTracking *tracking = &clip->tracking;
index 2cabb595fb77c8378aae3d97cec4cd42b5547406..e1262d0d7b8c2d7ba5c8ff9296150d6eeb8e172e 100644 (file)
@@ -247,7 +247,7 @@ static SpaceLink *clip_new(const bContext *C)
        sc = MEM_callocN(sizeof(SpaceClip), "initclip");
        sc->spacetype = SPACE_CLIP;
        sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_MANUAL_CALIBRATION |
-                  SC_SHOW_GRAPH_TRACKS | SC_SHOW_GRAPH_FRAMES | SC_SHOW_GPENCIL;
+                  SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_GPENCIL;
        sc->zoom = 1.0f;
        sc->path_length = 20;
        sc->scopes.track_preview_height = 120;
index 9038885f6af571eed506348eb232e38c73e35c0f..f2dc4dce11f5304f92381bf1044cc226373db119 100644 (file)
@@ -1107,27 +1107,28 @@ typedef struct SpaceClip {
 
 /* SpaceClip->flag */
 typedef enum eSpaceClip_Flag {
-       SC_SHOW_MARKER_PATTERN = (1 << 0),
-       SC_SHOW_MARKER_SEARCH  = (1 << 1),
-       SC_LOCK_SELECTION      = (1 << 2),
-       SC_SHOW_TINY_MARKER    = (1 << 3),
-       SC_SHOW_TRACK_PATH     = (1 << 4),
-       SC_SHOW_BUNDLES        = (1 << 5),
-       SC_MUTE_FOOTAGE        = (1 << 6),
-       SC_HIDE_DISABLED       = (1 << 7),
-       SC_SHOW_NAMES          = (1 << 8),
-       SC_SHOW_GRID           = (1 << 9),
-       SC_SHOW_STABLE         = (1 << 10),
-       SC_MANUAL_CALIBRATION  = (1 << 11),
-       SC_SHOW_GPENCIL        = (1 << 12),
-       SC_SHOW_FILTERS        = (1 << 13),
-       SC_SHOW_GRAPH_FRAMES   = (1 << 14),
-       SC_SHOW_GRAPH_TRACKS   = (1 << 15),
-/*     SC_SHOW_PYRAMID_LEVELS = (1 << 16), */  /* UNUSED */
-       SC_LOCK_TIMECURSOR     = (1 << 17),
-       SC_SHOW_SECONDS        = (1 << 18),
-       SC_SHOW_GRAPH_SEL_ONLY = (1 << 19),
-       SC_SHOW_GRAPH_HIDDEN   = (1 << 20),
+       SC_SHOW_MARKER_PATTERN      = (1 << 0),
+       SC_SHOW_MARKER_SEARCH       = (1 << 1),
+       SC_LOCK_SELECTION           = (1 << 2),
+       SC_SHOW_TINY_MARKER         = (1 << 3),
+       SC_SHOW_TRACK_PATH          = (1 << 4),
+       SC_SHOW_BUNDLES             = (1 << 5),
+       SC_MUTE_FOOTAGE             = (1 << 6),
+       SC_HIDE_DISABLED            = (1 << 7),
+       SC_SHOW_NAMES               = (1 << 8),
+       SC_SHOW_GRID                = (1 << 9),
+       SC_SHOW_STABLE              = (1 << 10),
+       SC_MANUAL_CALIBRATION       = (1 << 11),
+       SC_SHOW_GPENCIL             = (1 << 12),
+       SC_SHOW_FILTERS             = (1 << 13),
+       SC_SHOW_GRAPH_FRAMES        = (1 << 14),
+       SC_SHOW_GRAPH_TRACKS_MOTION = (1 << 15),
+/*     SC_SHOW_PYRAMID_LEVELS      = (1 << 16), */     /* UNUSED */
+       SC_LOCK_TIMECURSOR          = (1 << 17),
+       SC_SHOW_SECONDS             = (1 << 18),
+       SC_SHOW_GRAPH_SEL_ONLY      = (1 << 19),
+       SC_SHOW_GRAPH_HIDDEN        = (1 << 20),
+       SC_SHOW_GRAPH_TRACKS_ERROR  = (1 << 21),
 } eSpaceClip_Flag;
 
 /* SpaceClip->mode */
index fdaf204be23972b2184985ed7bd9c7bb9b596b8d..ae6b2e756586227716ddcb0f7c66b7bb4073069f 100644 (file)
@@ -3745,14 +3745,21 @@ static void rna_def_space_clip(BlenderRNA *brna)
                                 "Show curve for per-frame average error (camera motion should be solved first)");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
 
-       /* show graph_tracks */
-       prop = RNA_def_property(srna, "show_graph_tracks", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GRAPH_TRACKS);
-       RNA_def_property_ui_text(prop, "Show Tracks",
+       /* show graph tracks motion */
+       prop = RNA_def_property(srna, "show_graph_tracks_motion", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GRAPH_TRACKS_MOTION);
+       RNA_def_property_ui_text(prop, "Show Tracks Motion",
                                 "Display the speed curves (in \"x\" direction red, in \"y\" direction green) "
                                 "for the selected tracks");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
 
+       /* show graph tracks motion */
+       prop = RNA_def_property(srna, "show_graph_tracks_error", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GRAPH_TRACKS_ERROR);
+       RNA_def_property_ui_text(prop, "Show Tracks Error",
+                                "Display the reprojection error curve for selected tracks");
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
+
        /* show_only_selected */
        prop = RNA_def_property(srna, "show_graph_only_selected", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GRAPH_SEL_ONLY);