Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2014-12-23 08:04:03 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2014-12-23 08:04:03 +0300
commit9282d305bdc56522543129436db1e8a5d19cf39f (patch)
treeb6d0cdcc7dd3f4113cf9e4f9813c40f44d29746e /source/blender/blenkernel/intern/tracking_auto.c
parentde724a258eda45d1fed2b2176006c3b2df8abea2 (diff)
parent646a96bf8edc211a06f3df652101c265ee166e8d (diff)
Merge branch 'master' into texture_nodes_refactortexture_nodes_refactor
Conflicts: source/blender/nodes/texture/nodes/node_texture_math.c
Diffstat (limited to 'source/blender/blenkernel/intern/tracking_auto.c')
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
new file mode 100644
index 00000000000..22a380ea835
--- /dev/null
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -0,0 +1,568 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ * Keir Mierle
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/tracking_auto.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_movieclip_types.h"
+#include "DNA_object_types.h" /* SELECT */
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+
+#include "libmv-capi.h"
+#include "tracking_private.h"
+
+typedef struct AutoTrackOptions {
+ int clip_index; /** Index of the clip this track belogs to. */
+ int track_index; /* Index of the track in AutoTrack tracks structure. */
+ MovieTrackingTrack *track; /* Pointer to an original track/ */
+ libmv_TrackRegionOptions track_region_options; /* Options for the region
+ tracker. */
+ bool use_keyframe_match; /* Keyframe pattern matching. */
+
+ /* TODO(sergey): A bit awkward to keep it in here, only used to
+ * place a disabled marker once the tracking fails,
+ * Wither find a more clear way to do it or call it track context
+ * or state, not options.
+ */
+ bool is_failed;
+ int failed_frame;
+} AutoTrackOptions;
+
+typedef struct AutoTrackContext {
+ MovieClip *clips[MAX_ACCESSOR_CLIP];
+ int num_clips;
+
+ MovieClipUser user;
+ int frame_width, frame_height;
+
+ struct libmv_AutoTrack *autotrack;
+ TrackingImageAccessor *image_accessor;
+
+ int num_tracks; /* Number of tracks being tracked. */
+ AutoTrackOptions *options; /* Per-tracking track options. */
+
+ bool backwards;
+ bool sequence;
+ int first_frame;
+ int sync_frame;
+ bool first_sync;
+ SpinLock spin_lock;
+} AutoTrackContext;
+
+static void normalized_to_libmv_frame(const float normalized[2],
+ const int frame_dimensions[2],
+ float result[2])
+{
+ result[0] = normalized[0] * frame_dimensions[0] - 0.5f;
+ result[1] = normalized[1] * frame_dimensions[1] - 0.5f;
+}
+
+static void normalized_relative_to_libmv_frame(const float normalized[2],
+ const float origin[2],
+ const int frame_dimensions[2],
+ float result[2])
+{
+ result[0] = (normalized[0] + origin[0]) * frame_dimensions[0] - 0.5f;
+ result[1] = (normalized[1] + origin[1]) * frame_dimensions[1] - 0.5f;
+}
+
+static void libmv_frame_to_normalized(const float frame_coord[2],
+ const int frame_dimensions[2],
+ float result[2])
+{
+ result[0] = (frame_coord[0] + 0.5f) / frame_dimensions[0];
+ result[1] = (frame_coord[1] + 0.5f) / frame_dimensions[1];
+}
+
+static void libmv_frame_to_normalized_relative(const float frame_coord[2],
+ const float origin[2],
+ const int frame_dimensions[2],
+ float result[2])
+{
+ result[0] = (frame_coord[0] - origin[0]) / frame_dimensions[0];
+ result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1];
+}
+
+static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
+ /*const*/ MovieTrackingMarker *marker,
+ int clip,
+ int track_index,
+ int frame_width,
+ int frame_height,
+ bool backwards,
+ libmv_Marker *libmv_marker)
+{
+ const int frame_dimensions[2] = {frame_width, frame_height};
+ int i;
+ libmv_marker->clip = clip;
+ libmv_marker->frame = marker->framenr;
+ libmv_marker->track = track_index;
+
+ normalized_to_libmv_frame(marker->pos,
+ frame_dimensions,
+ libmv_marker->center);
+ for (i = 0; i < 4; ++i) {
+ normalized_relative_to_libmv_frame(marker->pattern_corners[i],
+ marker->pos,
+ frame_dimensions,
+ libmv_marker->patch[i]);
+ }
+
+ normalized_relative_to_libmv_frame(marker->search_min,
+ marker->pos,
+ frame_dimensions,
+ libmv_marker->search_region_min);
+
+ normalized_relative_to_libmv_frame(marker->search_max,
+ marker->pos,
+ frame_dimensions,
+ libmv_marker->search_region_max);
+
+ /* TODO(sergey): All the markers does have 1.0 weight. */
+ libmv_marker->weight = 1.0f;
+
+ if (marker->flag & MARKER_TRACKED) {
+ libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
+ }
+ else {
+ libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
+ }
+ libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
+ libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
+ libmv_marker->model_id = 0;
+
+ /* TODO(sergey): We currently don't support reference marker from
+ * different clip.
+ */
+ libmv_marker->reference_clip = clip;
+
+ if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
+ MovieTrackingMarker *keyframe_marker =
+ tracking_get_keyframed_marker(track,
+ marker->framenr,
+ backwards);
+ libmv_marker->reference_frame = keyframe_marker->framenr;
+ }
+ else {
+ libmv_marker->reference_frame = backwards ?
+ marker->framenr - 1 :
+ marker->framenr;
+ }
+
+ libmv_marker->disabled_channels =
+ ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
+ ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
+ ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
+}
+
+static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
+ int frame_width,
+ int frame_height,
+ MovieTrackingMarker *marker)
+{
+ const int frame_dimensions[2] = {frame_width, frame_height};
+ int i;
+ marker->framenr = libmv_marker->frame;
+
+ libmv_frame_to_normalized(libmv_marker->center,
+ frame_dimensions,
+ marker->pos);
+ for (i = 0; i < 4; ++i) {
+ libmv_frame_to_normalized_relative(libmv_marker->patch[i],
+ libmv_marker->center,
+ frame_dimensions,
+ marker->pattern_corners[i]);
+ }
+
+ libmv_frame_to_normalized_relative(libmv_marker->search_region_min,
+ libmv_marker->center,
+ frame_dimensions,
+ marker->search_min);
+
+ libmv_frame_to_normalized_relative(libmv_marker->search_region_max,
+ libmv_marker->center,
+ frame_dimensions,
+ marker->search_max);
+
+ marker->flag = 0;
+ if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
+ marker->flag |= MARKER_TRACKED;
+ }
+ else {
+ marker->flag &= ~MARKER_TRACKED;
+ }
+}
+
+static bool check_track_trackable(MovieClip *clip,
+ MovieTrackingTrack *track,
+ MovieClipUser *user)
+{
+ if (TRACK_SELECTED(track) &&
+ (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0)
+ {
+ MovieTrackingMarker *marker;
+ int frame;
+ frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
+ marker = BKE_tracking_marker_get(track, frame);
+ return (marker->flag & MARKER_DISABLED) == 0;
+ }
+ return false;
+}
+
+/* Returns false if marker crossed margin area from frame bounds. */
+static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
+ int margin,
+ int frame_width,
+ int frame_height)
+{
+ float patch_min[2], patch_max[2];
+ float margin_left, margin_top, margin_right, margin_bottom;
+
+ INIT_MINMAX2(patch_min, patch_max);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
+
+ margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
+ margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
+ margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
+ margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
+
+ if (libmv_marker->center[0] < margin_left ||
+ libmv_marker->center[0] > frame_width - margin_right ||
+ libmv_marker->center[1] < margin_bottom ||
+ libmv_marker->center[1] > frame_height - margin_top)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
+ MovieClipUser *user,
+ const bool backwards,
+ const bool sequence)
+{
+ AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext),
+ "autotrack context");
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingTrack *track;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int i, track_index, frame_width, frame_height;
+
+ BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
+
+ /* TODO(sergey): Currently using only a single clip. */
+ context->clips[0] = clip;
+ context->num_clips = 1;
+
+ context->user = *user;
+ context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ context->user.render_flag = 0;
+ context->frame_width = frame_width;
+ context->frame_height = frame_height;
+ context->backwards = backwards;
+ context->sequence = sequence;
+ context->first_frame = user->framenr;
+ context->sync_frame = user->framenr;
+ context->first_sync = true;
+
+ BLI_spin_init(&context->spin_lock);
+
+ context->image_accessor =
+ tracking_image_accessor_new(context->clips, 1, user->framenr);
+ context->autotrack =
+ libmv_autoTrackNew(context->image_accessor->libmv_accessor);
+
+ /* Fill in Autotrack with all markers we know. */
+ track_index = 0;
+ for (track = tracksbase->first;
+ track;
+ track = track->next)
+ {
+ if (check_track_trackable(clip, track, user)) {
+ context->num_tracks++;
+ }
+
+ for (i = 0; i < track->markersnr; ++i) {
+ MovieTrackingMarker *marker = track->markers + i;
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ libmv_Marker libmv_marker;
+ dna_marker_to_libmv_marker(track,
+ marker,
+ 0,
+ track_index,
+ frame_width,
+ frame_height,
+ backwards,
+ &libmv_marker);
+ libmv_autoTrackAddMarker(context->autotrack,
+ &libmv_marker);
+ }
+ }
+ track_index++;
+ }
+
+ /* Create per-track tracking options. */
+ context->options =
+ MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
+ "auto track options");
+ i = track_index = 0;
+ for (track = tracksbase->first;
+ track;
+ track = track->next)
+ {
+ if (check_track_trackable(clip, track, user)) {
+ AutoTrackOptions *options = &context->options[i++];
+ /* TODO(sergey): Single clip only for now. */
+ options->clip_index = 0;
+ options->track_index = track_index;
+ options->track = track;
+ tracking_configure_tracker(track,
+ NULL,
+ &options->track_region_options);
+ options->use_keyframe_match =
+ track->pattern_match == TRACK_MATCH_KEYFRAME;
+ }
+ ++track_index;
+ }
+
+ return context;
+}
+
+bool BKE_autotrack_context_step(AutoTrackContext *context)
+{
+ int frame_delta = context->backwards ? -1 : 1;
+ bool ok = false;
+ int track;
+
+#pragma omp parallel for if(context->num_tracks > 1)
+ for (track = 0; track < context->num_tracks; ++track) {
+ AutoTrackOptions *options = &context->options[track];
+ libmv_Marker libmv_current_marker,
+ libmv_reference_marker,
+ libmv_tracked_marker;
+ libmv_TrackRegionResult libmv_result;
+ int frame = BKE_movieclip_remap_scene_to_clip_frame(
+ context->clips[options->clip_index],
+ context->user.framenr);
+ bool has_marker;
+
+ BLI_spin_lock(&context->spin_lock);
+ has_marker = libmv_autoTrackGetMarker(context->autotrack,
+ options->clip_index,
+ frame,
+ options->track_index,
+ &libmv_current_marker);
+ BLI_spin_unlock(&context->spin_lock);
+
+ if (has_marker) {
+ if (!tracking_check_marker_margin(&libmv_current_marker,
+ options->track->margin,
+ context->frame_width,
+ context->frame_height))
+ {
+ continue;
+ }
+
+ libmv_tracked_marker = libmv_current_marker;
+ libmv_tracked_marker.frame = frame + frame_delta;
+
+ if (options->use_keyframe_match) {
+ libmv_tracked_marker.reference_frame =
+ libmv_current_marker.reference_frame;
+ libmv_autoTrackGetMarker(context->autotrack,
+ options->clip_index,
+ libmv_tracked_marker.reference_frame,
+ options->track_index,
+ &libmv_reference_marker);
+ }
+ else {
+ libmv_tracked_marker.reference_frame = frame;
+ libmv_reference_marker = libmv_current_marker;
+ }
+
+ if (libmv_autoTrackMarker(context->autotrack,
+ &options->track_region_options,
+ &libmv_tracked_marker,
+ &libmv_result))
+ {
+ BLI_spin_lock(&context->spin_lock);
+ libmv_autoTrackAddMarker(context->autotrack,
+ &libmv_tracked_marker);
+ BLI_spin_unlock(&context->spin_lock);
+ }
+ else {
+ options->is_failed = true;
+ options->failed_frame = frame + frame_delta;
+ }
+ ok = true;
+ }
+ }
+
+ BLI_spin_lock(&context->spin_lock);
+ context->user.framenr += frame_delta;
+ BLI_spin_unlock(&context->spin_lock);
+
+ return ok;
+}
+
+void BKE_autotrack_context_sync(AutoTrackContext *context)
+{
+ int newframe, frame_delta = context->backwards ? -1 : 1;
+ int clip, frame;
+
+ BLI_spin_lock(&context->spin_lock);
+ newframe = context->user.framenr;
+ for (frame = context->sync_frame;
+ frame != (context->backwards ? newframe - 1 : newframe + 1);
+ frame += frame_delta)
+ {
+ MovieTrackingMarker marker;
+ libmv_Marker libmv_marker;
+ int clip = 0;
+ int track;
+ for (track = 0; track < context->num_tracks; ++track) {
+ AutoTrackOptions *options = &context->options[track];
+ int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
+ context->clips[options->clip_index], frame);
+ if (options->is_failed && options->failed_frame == track_frame) {
+ MovieTrackingMarker *prev_marker =
+ BKE_tracking_marker_get_exact(options->track, frame);
+ if (prev_marker) {
+ marker = *prev_marker;
+ marker.framenr = context->backwards ?
+ track_frame - 1 :
+ track_frame + 1;
+ marker.flag |= MARKER_DISABLED;
+ BKE_tracking_marker_insert(options->track, &marker);
+ continue;
+ }
+ }
+ if (libmv_autoTrackGetMarker(context->autotrack,
+ clip,
+ track_frame,
+ options->track_index,
+ &libmv_marker))
+ {
+ libmv_marker_to_dna_marker(&libmv_marker,
+ context->frame_width,
+ context->frame_height,
+ &marker);
+ if (context->first_sync && frame == context->sync_frame) {
+ tracking_marker_insert_disabled(options->track,
+ &marker,
+ !context->backwards,
+ false);
+ }
+ BKE_tracking_marker_insert(options->track, &marker);
+ tracking_marker_insert_disabled(options->track,
+ &marker,
+ context->backwards,
+ false);
+ }
+ }
+ }
+ BLI_spin_unlock(&context->spin_lock);
+
+ for (clip = 0; clip < context->num_clips; ++clip) {
+ MovieTracking *tracking = &context->clips[clip]->tracking;
+ BKE_tracking_dopesheet_tag_update(tracking);
+ }
+
+ context->sync_frame = newframe;
+ context->first_sync = false;
+}
+
+void BKE_autotrack_context_sync_user(AutoTrackContext *context,
+ MovieClipUser *user)
+{
+ user->framenr = context->sync_frame;
+}
+
+void BKE_autotrack_context_finish(AutoTrackContext *context)
+{
+ int clip_index;
+
+ for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
+ MovieClip *clip = context->clips[clip_index];
+ ListBase *plane_tracks_base =
+ BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
+ int track;
+ for (track = 0; track < context->num_tracks; ++track) {
+ MovieTrackingTrack *old_track;
+ bool do_update = false;
+ int j;
+
+ old_track = context->options[track].track;
+ for (j = 0; j < plane_track->point_tracksnr; j++) {
+ if (plane_track->point_tracks[j] == old_track) {
+ do_update = true;
+ break;
+ }
+ }
+
+ if (do_update) {
+ BKE_tracking_track_plane_from_existing_motion(
+ plane_track,
+ context->first_frame);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_autotrack_context_free(AutoTrackContext *context)
+{
+ libmv_autoTrackDestroy(context->autotrack);
+ tracking_image_accessor_destroy(context->image_accessor);
+ MEM_freeN(context->options);
+ BLI_spin_end(&context->spin_lock);
+ MEM_freeN(context);
+}