Rework 2D stabilizator

See this page for motivation and description of concepts:
https://github.com/Ichthyostega/blender/wiki

See this video for UI explanation and demonstration of usage
http://vimeo.com/blenderHack/stabilizerdemo

This proposal attempts to improve usability of Blender's image stabilization
feature for real-world footage esp. with moving and panning camera. It builds
upon the feature tracking to get a measurement of 2D image movement.

  - Use a weighted average of movement contributions (instead of a median).
  - Allow for rotation compensation and zoom (image scale) compensation.
  - Allow to pick a different set of tracks for translation and for
    rotation/zoom.
  - Treat translation / rotation / zoom contributions systematically in a
    similar way.
  - Improve handling of partial tracking data with gaps and varying
    start / end points.
  - Have a user definable anchor frame and interpolate / extrapolate data to
    avoid jumping back to "neutral" position when no tracking data is available.
  - Support for travelling and panning shots by including an //intended//
    position/rotation/zoom ("target position"). The idea is for these parameters
    to be //animated// by the user, in order to supply an smooth, intended
    camera movement. This way, we can keep the image content roughly in frame
    even when moving completely away from the initial view.

A known shortcoming is that the pivot point for rotation compensation is set to
the translation compensated image center. This can produce spurious rotation on
travelling shots, which needs to be compensated manually (by animating the
target rotation parameter). There are several possible ways to address that
problem, yet all of them are considered beyond the scope of this improvement
proposal for now.

Own modifications:

- Restrict line length, it's really handy for split-view editing
- In motion tracking we prefer fully human-readable comments, meaning we
  don't use doxygen with it's weird markup and comments are supposed to
  start with capital and end with a full stop,
- Add explicit comparison of pointer to NULL.

Reviewers: sergey

Subscribers: kusi, kdawg, forest-house, mardy, Samoth, plasmasolutions, willolis, sebastian_k, hype, enetheru, sunboy, jta, leon_cheung

Maniphest Tasks: T49036

Differential Revision: https://developer.blender.org/D583
This commit is contained in:
Hermann Voßeler 2016-08-16 10:32:55 +02:00 committed by Sergey Sharybin
parent c00b2d8991
commit b1677201f9
Notes: blender-bot 2023-02-14 07:53:51 +01:00
Referenced by issue #49036, improve usability of 2D stabilizator
17 changed files with 1736 additions and 370 deletions

View File

@ -621,6 +621,7 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
text="", toggle=True, icon='IMAGE_ALPHA')
layout.prop(act_track, "weight")
layout.prop(act_track, "weight_stab")
if act_track.has_bundle:
label_text = "Average Error: %.4f" % (act_track.average_error)
@ -907,44 +908,80 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
self.layout.prop(stab, "use_2d_stabilization", text="")
def draw(self, context):
layout = self.layout
tracking = context.space_data.clip.tracking
stab = tracking.stabilization
layout = self.layout
layout.active = stab.use_2d_stabilization
row = layout.row()
row.template_list("UI_UL_list", "stabilization_tracks", stab, "tracks",
stab, "active_track_index", rows=2)
layout.prop(stab, "anchor_frame")
sub = row.column(align=True)
box = layout.box()
row = box.row(align=True)
row.prop(stab, "show_tracks_expanded", text="", emboss=False)
sub.operator("clip.stabilize_2d_add", icon='ZOOMIN', text="")
sub.operator("clip.stabilize_2d_remove", icon='ZOOMOUT', text="")
if not stab.show_tracks_expanded:
row.label(text="Tracks For Stabilization")
else:
row.label(text="Tracks For Location")
row = box.row()
row.template_list("UI_UL_list", "stabilization_tracks", stab, "tracks",
stab, "active_track_index", rows=2)
sub.menu('CLIP_MT_stabilize_2d_specials', text="",
icon='DOWNARROW_HLT')
sub = row.column(align=True)
layout.prop(stab, "influence_location")
sub.operator("clip.stabilize_2d_add", icon='ZOOMIN', text="")
sub.operator("clip.stabilize_2d_remove", icon='ZOOMOUT', text="")
layout.prop(stab, "use_autoscale")
col = layout.column()
col.active = stab.use_autoscale
col.prop(stab, "scale_max")
col.prop(stab, "influence_scale")
sub.menu('CLIP_MT_stabilize_2d_specials', text="",
icon='DOWNARROW_HLT')
row = box.row()
row.label(text="Tracks For Rotation / Scale")
row = box.row()
row.active = stab.use_stabilize_rotation
row.template_list("UI_UL_list", "stabilization_rotation_tracks", stab, "rotation_tracks",
stab, "active_rotation_track_index", rows=2)
sub = row.column(align=True)
sub.operator("clip.stabilize_2d_rotation_add", icon='ZOOMIN', text="")
sub.operator("clip.stabilize_2d_rotation_remove", icon='ZOOMOUT', text="")
sub.menu('CLIP_MT_stabilize_2d_rotation_specials', text="",
icon='DOWNARROW_HLT')
layout.prop(stab, "use_stabilize_rotation")
row = layout.row()
row.active = stab.use_stabilize_rotation
row.prop(stab, "use_stabilize_scale")
if stab.use_autoscale:
row = layout.row(align=True)
row.prop(stab, "use_autoscale")
row.prop(stab, "scale_max", text="Max")
else:
layout.prop(stab, "use_autoscale")
layout.separator()
layout.label(text="Expected Position")
layout.prop(stab, "target_pos", text="")
layout.prop(stab, "target_rot")
if stab.use_autoscale:
layout.label(text="Auto Scale Factor: %5.3f" % (1.0 / stab.target_zoom))
else:
layout.prop(stab, "target_zoom")
layout.separator()
row = layout.row()
row.active = 0 < len(stab.tracks.values())
row.prop(stab, "influence_location")
col = layout.column()
col.active = stab.use_stabilize_rotation
row = col.row(align=True)
row.prop_search(stab, "rotation_track", tracking, "tracks", text="")
row.operator("clip.stabilize_2d_set_rotation", text="", icon='ZOOMIN')
col.active = stab.use_stabilize_rotation and 0 < len(stab.rotation_tracks.values())
row = col.row()
row.active = stab.rotation_track is not None
row.prop(stab, "influence_rotation")
row = col.row()
row.prop(stab, "influence_scale")
layout.prop(stab, "filter_type")
@ -1434,7 +1471,7 @@ class CLIP_MT_track_color_specials(Menu):
class CLIP_MT_stabilize_2d_specials(Menu):
bl_label = "Track Color Specials"
bl_label = "Translation Track Specials"
def draw(self, context):
layout = self.layout
@ -1442,5 +1479,14 @@ class CLIP_MT_stabilize_2d_specials(Menu):
layout.operator("clip.stabilize_2d_select")
class CLIP_MT_stabilize_2d_rotation_specials(Menu):
bl_label = "Rotation Track Specials"
def draw(self, context):
layout = self.layout
layout.operator("clip.stabilize_2d_rotation_select")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@ -277,9 +277,9 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking, struct ListBase
bool place_outside_layer);
/* **** 2D stabilization **** */
void BKE_tracking_stabilization_data_get(struct MovieTracking *tracking, int framenr, int width, int height,
void BKE_tracking_stabilization_data_get(struct MovieClip *clip, int framenr, int width, int height,
float translation[2], float *scale, float *angle);
struct ImBuf *BKE_tracking_stabilize_frame(struct MovieTracking *tracking, int framenr, struct ImBuf *ibuf,
struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip, int framenr, struct ImBuf *ibuf,
float translation[2], float *scale, float *angle);
void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect, float translation[2],
float scale, float angle, float mat[4][4]);

View File

@ -1033,7 +1033,7 @@ static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBu
stableibuf = cache->stabilized.ibuf;
BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
BKE_tracking_stabilization_data_get(clip, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
/* check for stabilization parameters */
if (tscale != cache->stabilized.scale ||
@ -1057,7 +1057,7 @@ static ImBuf *put_stabilized_frame_to_cache(MovieClip *clip, MovieClipUser *user
float tloc[2], tscale, tangle;
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
stableibuf = BKE_tracking_stabilize_frame(&clip->tracking, clip_framenr, ibuf, tloc, &tscale, &tangle);
stableibuf = BKE_tracking_stabilize_frame(clip, clip_framenr, ibuf, tloc, &tscale, &tangle);
copy_v2_v2(cache->stabilized.loc, tloc);
@ -1270,8 +1270,6 @@ void BKE_movieclip_reload(MovieClip *clip)
/* clear cache */
free_buffers(clip);
clip->tracking.stabilization.ok = false;
/* update clip source */
detect_clip_source(clip);

View File

@ -241,13 +241,9 @@ static void tracking_reconstruction_copy(
/* Copy stabilization structure. */
static void tracking_stabilization_copy(
MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src,
GHash *tracks_mapping)
MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src)
{
*stabilization_dst = *stabilization_src;
if (stabilization_src->rot_track) {
stabilization_dst->rot_track = BLI_ghash_lookup(tracks_mapping, stabilization_src->rot_track);
}
}
/* Copy tracking object. */
@ -284,7 +280,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping);
tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping);
tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction);
tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, tracks_mapping);
tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization);
if (tracking_src->act_track) {
tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
}
@ -316,7 +312,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
}
/* Initialize motion tracking settings to default values,
* used when new movie clip datablock is creating.
* used when new movie clip datablock is created.
*/
void BKE_tracking_settings_init(MovieTracking *tracking)
{
@ -333,11 +329,23 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->settings.dist = 1;
tracking->settings.object_distance = 1;
tracking->stabilization.scaleinf = 1.0f;
tracking->stabilization.anchor_frame = MINFRAME;
zero_v2(tracking->stabilization.target_pos);
tracking->stabilization.target_rot = 0.0f;
tracking->stabilization.scale = 1.0f;
tracking->stabilization.act_track = 0;
tracking->stabilization.act_rot_track = 0;
tracking->stabilization.tot_track = 0;
tracking->stabilization.tot_rot_track = 0;
tracking->stabilization.scaleinf = 1.0f;
tracking->stabilization.locinf = 1.0f;
tracking->stabilization.rotinf = 1.0f;
tracking->stabilization.maxscale = 2.0f;
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
BKE_tracking_object_add(tracking, "Camera");
}
@ -552,6 +560,7 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, ListBase *tr
track->flag = settings->default_flag;
track->algorithm_flag = settings->default_algorithm_flag;
track->weight = settings->default_weight;
track->weight_stab = settings->default_weight;
memset(&marker, 0, sizeof(marker));
marker.pos[0] = x;
@ -590,6 +599,12 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
new_track->markers = MEM_dupallocN(new_track->markers);
/* Orevent duplicate from being used for 2D stabilization.
* If necessary, it shall be added explicitly.
*/
new_track->flag &= ~TRACK_USE_2D_STAB;
new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
return new_track;
}

File diff suppressed because it is too large Load Diff

View File

@ -7478,7 +7478,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
clip->tracking_context = NULL;
clip->tracking.stats = NULL;
clip->tracking.stabilization.ok = 0;
/* Needed for proper versioning, will be NULL for all newer files anyway. */
clip->tracking.stabilization.rot_track = newdataadr(fd, clip->tracking.stabilization.rot_track);
clip->tracking.dopesheet.ok = 0;

View File

@ -63,6 +63,7 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "BKE_gpencil.h"
#include "BLI_math.h"
@ -75,6 +76,26 @@
#include "MEM_guardedalloc.h"
/**
* Setup rotation stabilization from ancient single track spec.
* Former Version of 2D stabilization used a single tracking marker to determine the rotation
* to be compensated. Now several tracks can contribute to rotation detection and this feature
* is enabled by the MovieTrackingTrack#flag on a per track base.
*/
static void migrate_single_rot_stabilization_track_settings(MovieTrackingStabilization *stab)
{
if (stab->rot_track) {
if (!(stab->rot_track->flag & TRACK_USE_2D_STAB_ROT)) {
stab->tot_rot_track++;
stab->rot_track->flag |= TRACK_USE_2D_STAB_ROT;
}
}
stab->rot_track = NULL; /* this field is now ignored */
/* by default show the track lists expanded, to improve "discoverability" */
stab->flag |= TRACKING_SHOW_STAB_TRACKS;
}
static void do_version_constraints_radians_degrees_270_1(ListBase *lb)
{
bConstraint *con;
@ -1321,4 +1342,41 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* ------- end of grease pencil initialization --------------- */
}
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) {
MovieClip *clip;
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object;
for (tracking_object = tracking->objects.first;
tracking_object != NULL;
tracking_object = tracking_object->next)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
MovieTrackingTrack *track;
for (track = tracksbase->first;
track != NULL;
track = track->next)
{
track->weight_stab = track->weight;
}
}
}
}
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingStabilization", "int", "tot_rot_track")) {
MovieClip *clip;
for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) {
if (clip->tracking.stabilization.rot_track) {
migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization);
if (!clip->tracking.stabilization.scale) {
/* ensure init.
* Was previously used for autoscale only,
* now used always (as "target scale") */
clip->tracking.stabilization.scale = 1.0f;
}
}
}
}
}

View File

@ -91,7 +91,7 @@ void MovieClipNode::convertToOperations(NodeConverter &converter, const Composit
if (stab->flag & TRACKING_2D_STABILIZATION) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, context.getFramenumber());
BKE_tracking_stabilization_data_get(&movieClip->tracking, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
BKE_tracking_stabilization_data_get(movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
}
}

View File

@ -47,7 +47,7 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4],
angle = 0.0f;
if (this->m_clip) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
BKE_tracking_stabilization_data_get(&this->m_clip->tracking, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
}
switch (this->m_attribute) {
case MCA_SCALE:

View File

@ -185,7 +185,10 @@ void CLIP_OT_detect_features(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_add(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_remove(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_select(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_set_rotation(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_rotation_add(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_rotation_remove(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_rotation_select(struct wmOperatorType *ot);
void CLIP_OT_clean_tracks(struct wmOperatorType *ot);

View File

@ -175,21 +175,14 @@ void clip_graph_tracking_iterate(SpaceClip *sc, bool selected_only, bool include
void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
{
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
bool has_bundle = false, update_stab = false;
bool has_bundle = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
if (track == act_track)
tracking->act_track = NULL;
if (track == stab->rot_track) {
stab->rot_track = NULL;
update_stab = true;
}
/* handle reconstruction display in 3d viewport */
if (track->flag & TRACK_HAS_BUNDLE)
has_bundle = true;
@ -207,8 +200,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
if (update_stab) {
tracking->stabilization.ok = false;
if (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}

View File

@ -225,18 +225,6 @@ static void clip_scopes_check_gpencil_change(ScrArea *sa)
}
}
static void clip_stabilization_tag_refresh(ScrArea *sa)
{
SpaceClip *sc = (SpaceClip *) sa->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip) {
MovieTrackingStabilization *stab = &clip->tracking.stabilization;
stab->ok = false;
}
}
/* ******************** default callbacks for clip space ***************** */
static SpaceLink *clip_new(const bContext *C)
@ -368,7 +356,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NA_REMOVED:
case NA_EDITED:
case NA_EVALUATED:
clip_stabilization_tag_refresh(sa);
/* fall-through */
case NA_SELECTED:
@ -412,7 +399,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NC_SPACE:
if (wmn->data == ND_SPACE_CLIP) {
clip_scopes_tag_refresh(sa);
clip_stabilization_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
break;
@ -457,7 +443,7 @@ static void clip_operatortypes(void)
/* navigation */
WM_operatortype_append(CLIP_OT_frame_jump);
/* foorage */
/* set optical center to frame center */
WM_operatortype_append(CLIP_OT_set_center_principal);
/* selection */
@ -505,7 +491,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_stabilize_2d_add);
WM_operatortype_append(CLIP_OT_stabilize_2d_remove);
WM_operatortype_append(CLIP_OT_stabilize_2d_select);
WM_operatortype_append(CLIP_OT_stabilize_2d_set_rotation);
WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_add);
WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_remove);
WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_select);
/* clean-up */
WM_operatortype_append(CLIP_OT_clear_track_path);

View File

@ -1509,8 +1509,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
bool update_stabilization = false;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
if (act_track == NULL) {
@ -1528,8 +1530,23 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
BKE_tracking_tracks_join(tracking, act_track, track);
if (tracking->stabilization.rot_track == track) {
tracking->stabilization.rot_track = act_track;
if (track->flag & TRACK_USE_2D_STAB) {
update_stabilization = true;
if ((act_track->flag & TRACK_USE_2D_STAB) == 0) {
act_track->flag |= TRACK_USE_2D_STAB;
} else {
stab->tot_track--;
}
BLI_assert(0 <= stab->tot_track);
}
if (track->flag & TRACK_USE_2D_STAB_ROT) {
update_stabilization = true;
if ((act_track->flag & TRACK_USE_2D_STAB_ROT) == 0) {
act_track->flag |= TRACK_USE_2D_STAB_ROT;
} else {
stab->tot_rot_track--;
}
BLI_assert(0 <= stab->tot_rot_track);
}
for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
@ -1551,6 +1568,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
}
}
if (update_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
GSetIterator gs_iter;
int framenr = ED_space_clip_get_clip_frame_number(sc);
GSET_ITER (gs_iter, point_tracks) {

View File

@ -84,7 +84,6 @@ static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
stab->ok = 0;
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@ -96,7 +95,7 @@ void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Stabilization Tracks";
ot->description = "Add selected tracks to 2D stabilization tool";
ot->description = "Add selected tracks to 2D translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_add";
/* api callbacks */
@ -139,7 +138,6 @@ static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
stab->ok = 0;
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@ -151,7 +149,7 @@ void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Stabilization Track";
ot->description = "Remove selected track from stabilization";
ot->description = "Remove selected track from translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_remove";
/* api callbacks */
@ -193,7 +191,7 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Stabilization Tracks";
ot->description = "Select tracks which are used for stabilization";
ot->description = "Select tracks which are used for translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_select";
/* api callbacks */
@ -204,20 +202,31 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/***************** set 2d stabilization rotation track operator ****************/
/********************** add 2d stabilization tracks for rotation operator ****************/
static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
static int stabilize_2d_rotation_add_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
MovieTrackingStabilization *stab = &tracking->stabilization;
if (act_track != NULL) {
MovieTrackingStabilization *stab = &tracking->stabilization;
stab->rot_track = act_track;
stab->ok = 0;
bool update = false;
for (MovieTrackingTrack *track = tracksbase->first;
track != NULL;
track = track->next)
{
if (TRACK_VIEW_SELECTED(sc, track) &&
(track->flag & TRACK_USE_2D_STAB_ROT) == 0)
{
track->flag |= TRACK_USE_2D_STAB_ROT;
stab->tot_rot_track++;
update = true;
}
}
if (update) {
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@ -225,18 +234,114 @@ static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
void CLIP_OT_stabilize_2d_rotation_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Set Rotation Track";
ot->description = "Use active track to compensate rotation when "
"doing 2D stabilization";
ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
ot->name = "Add Stabilization Rotation Tracks";
ot->description = "Add selected tracks to 2D rotation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_rotation_add";
/* api callbacks */
ot->exec = stabilize_2d_set_rotation_exec;
ot->exec = stabilize_2d_rotation_add_exec;
ot->poll = stabilize_2d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** remove 2d stabilization tracks for rotation operator *************/
static int stabilize_2d_rotation_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
int a = 0;
bool update = false;
for (MovieTrackingTrack *track = tracksbase->first;
track != NULL;
track = track->next)
{
if (track->flag & TRACK_USE_2D_STAB_ROT) {
if (a == stab->act_rot_track) {
track->flag &= ~TRACK_USE_2D_STAB_ROT;
stab->act_rot_track--;
stab->tot_rot_track--;
if (stab->act_rot_track < 0) {
stab->act_rot_track = 0;
}
update = true;
break;
}
a++;
}
}
if (update) {
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
return OPERATOR_FINISHED;
}
void CLIP_OT_stabilize_2d_rotation_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Stabilization Rotation Track";
ot->description = "Remove selected track from rotation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_rotation_remove";
/* api callbacks */
ot->exec = stabilize_2d_rotation_remove_exec;
ot->poll = stabilize_2d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** select 2d stabilization rotation tracks operator *****************/
static int stabilize_2d_rotation_select_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
bool update = false;
for (MovieTrackingTrack *track = tracksbase->first;
track != NULL;
track = track->next)
{
if (track->flag & TRACK_USE_2D_STAB_ROT) {
BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
update = true;
}
}
if (update) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
}
return OPERATOR_FINISHED;
}
void CLIP_OT_stabilize_2d_rotation_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Stabilization Rotation Tracks";
ot->description = "Select tracks which are used for rotation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_rotation_select";
/* api callbacks */
ot->exec = stabilize_2d_rotation_select_exec;
ot->poll = stabilize_2d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}

View File

@ -158,7 +158,10 @@ typedef struct MovieTrackingTrack {
* Used to prevent jumps of the camera when tracks are appearing or
* disappearing.
*/
float weight, pad;
float weight;
/* track weight especially for 2D stabilization */
float weight_stab;
} MovieTrackingTrack;
typedef struct MovieTrackingPlaneMarker {
@ -250,19 +253,24 @@ typedef struct MovieTrackingSettings {
typedef struct MovieTrackingStabilization {
int flag;
int tot_track, act_track; /* total number and index of active track in list */
int tot_track, act_track; /* total number of translation tracks and index of active track in list */
int tot_rot_track, act_rot_track; /* total number of rotation tracks and index of active track in list */
/* 2d stabilization */
float maxscale; /* max auto-scale factor */
MovieTrackingTrack *rot_track; /* track used to stabilize rotation */
MovieTrackingTrack *rot_track DNA_DEPRECATED; /* use TRACK_USE_2D_STAB_ROT on individual tracks instead */
int anchor_frame; /* reference point to anchor stabilization offset */
float target_pos[2]; /* expected target position of frame after raw stabilization, will be subtracted */
float target_rot; /* expected target rotation of frame after raw stabilization, will be compensated */
float scale; /* zoom factor known to be present on original footage. Also used for autoscale */
float locinf, scaleinf, rotinf; /* influence on location, scale and rotation */
int filter; /* filter used for pixel interpolation */
/* some pre-computing run-time variables */
int ok; /* are precomputed values and scaled buf relevant? */
float scale; /* autoscale factor */
/* initialization and run-time data */
int ok DNA_DEPRECATED; /* Without effect now, we initialize on every frame. Formerly used for caching of init values */
} MovieTrackingStabilization;
typedef struct MovieTrackingReconstruction {
@ -386,7 +394,8 @@ enum {
TRACK_USE_2D_STAB = (1 << 8),
TRACK_PREVIEW_GRAYSCALE = (1 << 9),
TRACK_DOPE_SEL = (1 << 10),
TRACK_PREVIEW_ALPHA = (1 << 11)
TRACK_PREVIEW_ALPHA = (1 << 11),
TRACK_USE_2D_STAB_ROT = (1 << 12)
};
/* MovieTrackingTrack->motion_model */
@ -452,7 +461,9 @@ enum {
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
TRACKING_STABILIZE_ROTATION = (1 << 2)
TRACKING_STABILIZE_ROTATION = (1 << 2),
TRACKING_STABILIZE_SCALE = (1 << 3),
TRACKING_SHOW_STAB_TRACKS = (1 << 5)
};
/* MovieTrackingStrabilization->filter */

View File

@ -422,6 +422,7 @@ extern StructRNA RNA_MovieClipSequence;
extern StructRNA RNA_MovieTracking;
extern StructRNA RNA_MovieTrackingObject;
extern StructRNA RNA_MovieTrackingTrack;
extern StructRNA RNA_MovieTrackingStabilization;
extern StructRNA RNA_MulticamSequence;
extern StructRNA RNA_MultiresModifier;
extern StructRNA RNA_MusgraveTexture;

View File

@ -394,6 +394,16 @@ static int rna_track_2d_stabilization(CollectionPropertyIterator *UNUSED(iter),
return 0;
}
static int rna_track_2d_stabilization_rotation(CollectionPropertyIterator *UNUSED(iter), void *data)
{
MovieTrackingTrack *track = (MovieTrackingTrack *)data;
if ((track->flag & TRACK_USE_2D_STAB_ROT) == 0)
return 1;
return 0;
}
static void rna_tracking_stabTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@ -421,6 +431,44 @@ static void rna_tracking_stabTracks_active_index_range(PointerRNA *ptr, int *min
*max = max_ii(0, clip->tracking.stabilization.tot_track - 1);
}
static void rna_tracking_stabRotTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
rna_iterator_listbase_begin(iter, &clip->tracking.tracks, rna_track_2d_stabilization_rotation);
}
static int rna_tracking_stabRotTracks_active_index_get(PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
return clip->tracking.stabilization.act_rot_track;
}
static void rna_tracking_stabRotTracks_active_index_set(PointerRNA *ptr, int value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
clip->tracking.stabilization.act_rot_track = value;
}
static void rna_tracking_stabRotTracks_active_index_range(PointerRNA *ptr, int *min, int *max,
int *UNUSED(softmin), int *UNUSED(softmax))
{
MovieClip *clip = (MovieClip *)ptr->id.data;
*min = 0;
*max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
}
static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
nodeUpdateID(scene->nodetree, &clip->id);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
DAG_id_tag_update(&clip->id, 0);
}
static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@ -432,20 +480,6 @@ static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scen
}
}
static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingStabilization *stab = &clip->tracking.stabilization;
stab->ok = 0;
nodeUpdateID(scene->nodetree, &clip->id);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
DAG_id_tag_update(&clip->id, 0);
}
static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
@ -1495,6 +1529,12 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Weight", "Influence of this track on a final solution");
/* weight_stab */
prop = RNA_def_property(srna, "weight_stab", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "weight_stab");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Stab Weight", "Influence of this track on 2D stabilization");
/* offset */
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 2);
@ -1634,15 +1674,15 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem filter_items[] = {
{TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", ""},
{TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", ""},
{TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", ""},
{TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", "No interpolation; use nearest neighbor pixel"},
{TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", "Simple interpolation between adjacent pixels"},
{TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", "High quality pixel interpolation"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "MovieTrackingStabilization", NULL);
RNA_def_struct_path_func(srna, "rna_trackingStabilization_path");
RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "Match-moving stabilization data for tracking");
RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "2D stabilization based on tracking markers");
/* 2d stabilization */
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
@ -1651,22 +1691,29 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_rotation */
prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize detected rotation around center of frame");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_scale */
prop = RNA_def_property(srna, "use_stabilize_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_SCALE);
RNA_def_property_ui_text(prop, "Stabilize Scale", "Compensate any scale changes relative to center of rotation");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* tracks */
prop = RNA_def_property(srna, "tracks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_tracking_stabTracks_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MovieTrackingTrack");
RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks used for stabilization");
RNA_def_property_ui_text(prop, "Translation Tracks", "Collection of tracks used for 2D stabilization (translation)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* rotation track */
prop = RNA_def_property(srna, "rotation_track", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "rot_track");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Rotation Track", "Track used to compensate rotation");
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
/* active track index */
prop = RNA_def_property(srna, "active_track_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "act_track");
@ -1674,7 +1721,57 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, "rna_tracking_stabTracks_active_index_get",
"rna_tracking_stabTracks_active_index_set",
"rna_tracking_stabTracks_active_index_range");
RNA_def_property_ui_text(prop, "Active Track Index", "Index of active track in stabilization tracks list");
RNA_def_property_ui_text(prop, "Active Track Index", "Index of active track in translation stabilization tracks list");
/* tracks used for rotation stabilization */
prop = RNA_def_property(srna, "rotation_tracks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_tracking_stabRotTracks_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MovieTrackingTrack");
RNA_def_property_ui_text(prop, "Rotation Tracks", "Collection of tracks used for 2D stabilization (translation)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* active rotation track index */
prop = RNA_def_property(srna, "active_rotation_track_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "act_rot_track");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_int_funcs(prop, "rna_tracking_stabRotTracks_active_index_get",
"rna_tracking_stabRotTracks_active_index_set",
"rna_tracking_stabRotTracks_active_index_range");
RNA_def_property_ui_text(prop, "Active Rotation Track Index", "Index of active track in rotation stabilization tracks list");
/* anchor frame */
prop = RNA_def_property(srna, "anchor_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "anchor_frame");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Anchor Frame", "Reference point to anchor stabilization (other frames will be adjusted relative to this frame's position)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* target position */
prop = RNA_def_property(srna, "target_pos", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 2);
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); /* increment in steps of 0.01 and show 3 digit after point */
RNA_def_property_float_sdna(prop, NULL, "target_pos");
RNA_def_property_ui_text(prop, "Expected Position", "Known relative offset of original shot, will be subtracted; e.g. for panning shot, can be animated");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
/* target rotation */
prop = RNA_def_property(srna, "target_rot", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "target_rot");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Expected Rotation", "Rotation present on original shot, will be compensated; e.g. for deliberate tilting");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
/* target scale */
prop = RNA_def_property(srna, "target_zoom", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "scale");
RNA_def_property_range(prop, FLT_EPSILON, 100.0f);
RNA_def_property_ui_range(prop, 0.1f, 10.0f, 1, 3); /* increment in steps of 0.01. Show 3 digit after point */
RNA_def_property_ui_text(prop, "Expected Zoom", "Explicitly scale resulting frame to compensate zoom of original shot");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* autoscale */
prop = RNA_def_property(srna, "use_autoscale", PROP_BOOLEAN, PROP_NONE);
@ -1705,13 +1802,6 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale Influence", "Influence of stabilization algorithm on footage scale");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_rotation */
prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize horizon line on the shot");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* influence_rotation */
prop = RNA_def_property(srna, "influence_rotation", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rotinf");
@ -1723,8 +1813,15 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "filter");
RNA_def_property_enum_items(prop, filter_items);
RNA_def_property_ui_text(prop, "Filter", "Method to use to filter stabilization");
RNA_def_property_ui_text(prop, "Interpolate", "Interpolation to use for sub-pixel shifts and rotations due to stabilization");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* UI display : show participating tracks */
prop = RNA_def_property(srna, "show_tracks_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SHOW_STAB_TRACKS);
RNA_def_property_ui_text(prop, "Show Tracks", "Show UI list of tracks participating in stabilization");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
}
static void rna_def_reconstructedCamera(BlenderRNA *brna)