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>2013-12-30 15:03:59 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2014-01-01 20:32:48 +0400
commit2785e8e73d3473cf481ba65a6b50a50c194e63d8 (patch)
tree179263a95aa25ccf8ecd383786dd535419aeabe4 /source/blender/blenkernel/intern/tracking.c
parent5933b2455c409963580ea616047f2f2ee332ff71 (diff)
Split tracking.c into several files
File tracking.c became rather huge and annoying to maintain and it really contains several independent areas of motrack pipeline. Now we've got: * tracking.c: general-purpose functions which are used by blender, clip editor, RNA and so. * tracking_detect.c: feature detection functions (blender-side, logic is still in libmv). * tracking_plane_tracker.c: blender-side 2D tracking logic. * tracking_plane_tracker.c: plane track tracker. * tracking_solver.c: functions for camera solving. * tracking_stabilize.c: 2D stabilization functions. * tracking_util.c: utility functions for all those files and which shouldn't be public.
Diffstat (limited to 'source/blender/blenkernel/intern/tracking.c')
-rw-r--r--source/blender/blenkernel/intern/tracking.c2436
1 files changed, 20 insertions, 2416 deletions
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index e07d84a99ce..fec6733b25c 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -69,6 +69,7 @@
#include "raskter.h"
#include "libmv-capi.h"
+#include "tracking_private.h"
typedef struct MovieDistortion {
struct libmv_CameraIntrinsics *intrinsics;
@@ -80,21 +81,6 @@ static struct {
/*********************** Common functions *************************/
-/* Duplicate the specified track, result will no belong to any list. */
-static MovieTrackingTrack *tracking_track_duplicate(MovieTrackingTrack *track)
-{
- MovieTrackingTrack *new_track;
-
- new_track = MEM_callocN(sizeof(MovieTrackingTrack), "tracking_track_duplicate new_track");
-
- *new_track = *track;
- new_track->next = new_track->prev = NULL;
-
- new_track->markers = MEM_dupallocN(new_track->markers);
-
- return new_track;
-}
-
/* Free the whole list of tracks, list's head and tail are set to NULL. */
static void tracking_tracks_free(ListBase *tracks)
{
@@ -328,141 +314,6 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking, MovieTrackingOb
}
}
-/* **** space transformation functions **** */
-
-/* Three coordinate frames: Frame, Search, and Marker
- * Two units: Pixels, Unified
- * Notation: {coordinate frame}_{unit}; for example, "search_pixel" are search
- * window relative coordinates in pixels, and "frame_unified" are unified 0..1
- * coordinates relative to the entire frame.
- */
-static void unified_to_pixel(int frame_width, int frame_height,
- const float unified_coords[2], float pixel_coords[2])
-{
- pixel_coords[0] = unified_coords[0] * frame_width;
- pixel_coords[1] = unified_coords[1] * frame_height;
-}
-
-static void marker_to_frame_unified(const MovieTrackingMarker *marker, const float marker_unified_coords[2],
- float frame_unified_coords[2])
-{
- frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0];
- frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1];
-}
-
-static void marker_unified_to_frame_pixel_coordinates(int frame_width, int frame_height,
- const MovieTrackingMarker *marker,
- const float marker_unified_coords[2],
- float frame_pixel_coords[2])
-{
- marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords);
- unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords);
-}
-
-static void get_search_origin_frame_pixel(int frame_width, int frame_height,
- const MovieTrackingMarker *marker, float frame_pixel[2])
-{
- /* Get the lower left coordinate of the search window and snap to pixel coordinates */
- marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker->search_min, frame_pixel);
- frame_pixel[0] = (int)frame_pixel[0];
- frame_pixel[1] = (int)frame_pixel[1];
-}
-
-static void pixel_to_unified(int frame_width, int frame_height, const float pixel_coords[2], float unified_coords[2])
-{
- unified_coords[0] = pixel_coords[0] / frame_width;
- unified_coords[1] = pixel_coords[1] / frame_height;
-}
-
-static void marker_unified_to_search_pixel(int frame_width, int frame_height,
- const MovieTrackingMarker *marker,
- const float marker_unified[2], float search_pixel[2])
-{
- float frame_pixel[2];
- float search_origin_frame_pixel[2];
-
- marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker_unified, frame_pixel);
- get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel);
- sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel);
-}
-
-static void search_pixel_to_marker_unified(int frame_width, int frame_height,
- const MovieTrackingMarker *marker,
- const float search_pixel[2], float marker_unified[2])
-{
- float frame_unified[2];
- float search_origin_frame_pixel[2];
-
- get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel);
- add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
- pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);
-
- /* marker pos is in frame unified */
- sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
-}
-
-/* Each marker has 5 coordinates associated with it that get warped with
- * tracking: the four corners ("pattern_corners"), and the center ("pos").
- * This function puts those 5 points into the appropriate frame for tracking
- * (the "search" coordinate frame).
- */
-static void get_marker_coords_for_tracking(int frame_width, int frame_height,
- const MovieTrackingMarker *marker,
- double search_pixel_x[5], double search_pixel_y[5])
-{
- int i;
- float unified_coords[2];
- float pixel_coords[2];
-
- /* Convert the corners into search space coordinates. */
- for (i = 0; i < 4; i++) {
- marker_unified_to_search_pixel(frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords);
- search_pixel_x[i] = pixel_coords[0] - 0.5f;
- search_pixel_y[i] = pixel_coords[1] - 0.5f;
- }
-
- /* Convert the center position (aka "pos"); this is the origin */
- unified_coords[0] = 0.0f;
- unified_coords[1] = 0.0f;
- marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords);
-
- search_pixel_x[4] = pixel_coords[0] - 0.5f;
- search_pixel_y[4] = pixel_coords[1] - 0.5f;
-}
-
-/* Inverse of above. */
-static void set_marker_coords_from_tracking(int frame_width, int frame_height, MovieTrackingMarker *marker,
- const double search_pixel_x[5], const double search_pixel_y[5])
-{
- int i;
- float marker_unified[2];
- float search_pixel[2];
-
- /* Convert the corners into search space coordinates. */
- for (i = 0; i < 4; i++) {
- search_pixel[0] = search_pixel_x[i] + 0.5;
- search_pixel[1] = search_pixel_y[i] + 0.5;
- search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]);
- }
-
- /* Convert the center position (aka "pos"); this is the origin */
- search_pixel[0] = search_pixel_x[4] + 0.5;
- search_pixel[1] = search_pixel_y[4] + 0.5;
- search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified);
-
- /* If the tracker tracked nothing, then "marker_unified" would be zero.
- * Otherwise, the entire patch shifted, and that delta should be applied to
- * all the coordinates.
- */
- for (i = 0; i < 4; i++) {
- marker->pattern_corners[i][0] -= marker_unified[0];
- marker->pattern_corners[i][1] -= marker_unified[1];
- }
-
- marker->pos[0] += marker_unified[0];
- marker->pos[1] += marker_unified[1];
-}
-
/*********************** clipboard *************************/
/* Free clipboard by freeing memory used by all tracks in it. */
@@ -494,7 +345,7 @@ void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingOb
/* Then copy all selected visible tracks to it. */
while (track) {
if (TRACK_SELECTED(track) && (track->flag & TRACK_HIDDEN) == 0) {
- MovieTrackingTrack *new_track = tracking_track_duplicate(track);
+ MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
BLI_addtail(&tracking_clipboard.tracks, new_track);
}
@@ -520,7 +371,7 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
MovieTrackingTrack *track = tracking_clipboard.tracks.first;
while (track) {
- MovieTrackingTrack *new_track = tracking_track_duplicate(track);
+ MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
BLI_addtail(tracksbase, new_track);
BKE_tracking_track_unique_name(tracksbase, new_track);
@@ -531,33 +382,6 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
/*********************** Tracks *************************/
-/* Place a disabled marker before or after specified ref_marker.
- *
- * If before is truth, disabled marker is placed before reference
- * one, and it's placed after it otherwise.
- *
- * If there's already a marker at the frame where disabled one
- * is expected to be placed, nothing will happen if overwrite
- * is false.
- */
-static void tracking_marker_insert_disabled(MovieTrackingTrack *track, const MovieTrackingMarker *ref_marker,
- bool before, bool overwrite)
-{
- MovieTrackingMarker marker_new;
-
- marker_new = *ref_marker;
- marker_new.flag &= ~MARKER_TRACKED;
- marker_new.flag |= MARKER_DISABLED;
-
- if (before)
- marker_new.framenr--;
- else
- marker_new.framenr++;
-
- if (overwrite || !BKE_tracking_track_has_marker_at_frame(track, marker_new.framenr))
- BKE_tracking_marker_insert(track, &marker_new);
-}
-
/* Add new track to a specified tracks base.
*
* Coordinates are expected to be in normalized 0..1 space,
@@ -621,6 +445,21 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, ListBase *tr
return track;
}
+/* Duplicate the specified track, result will no belong to any list. */
+MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
+{
+ MovieTrackingTrack *new_track;
+
+ new_track = MEM_callocN(sizeof(MovieTrackingTrack), "tracking_track_duplicate new_track");
+
+ *new_track = *track;
+ new_track->next = new_track->prev = NULL;
+
+ new_track->markers = MEM_dupallocN(new_track->markers);
+
+ return new_track;
+}
+
/* Ensure specified track has got unique name,
* if it's not name of specified track will be changed
* keeping names of all other tracks unchanged.
@@ -1804,7 +1643,6 @@ static void reconstructed_camera_scale_set(MovieTrackingObject *object, float ma
}
}
-
/* converts principal offset from center to offset of blender's camera */
void BKE_tracking_camera_shift_get(MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
{
@@ -2130,7 +1968,7 @@ ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *sea
IMB_float_from_rect(search_ibuf);
}
- get_marker_coords_for_tracking(frame_width, frame_height, marker, src_pixel_x, src_pixel_y);
+ tracking_get_marker_coords_for_tracking(frame_width, frame_height, marker, src_pixel_x, src_pixel_y);
/* from_anchor means search buffer was obtained for an anchored position,
* which means applying track offset rounded to pixel space (we could not
@@ -2209,7 +2047,7 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, Mov
int x, y, w, h;
float search_origin[2];
- get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin);
+ tracking_get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin);
x = search_origin[0];
y = search_origin[1];
@@ -2307,2240 +2145,6 @@ void BKE_tracking_disable_channels(ImBuf *ibuf, bool disable_red, bool disable_g
ibuf->userflags |= IB_RECT_INVALID;
}
-/*********************** Tracks map *************************/
-
-typedef struct TracksMap {
- char object_name[MAX_NAME];
- bool is_camera;
-
- int num_tracks;
- int customdata_size;
-
- char *customdata;
- MovieTrackingTrack *tracks;
-
- GHash *hash;
-
- int ptr;
-} TracksMap;
-
-static TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size)
-{
- TracksMap *map = MEM_callocN(sizeof(TracksMap), "TrackingsMap");
-
- BLI_strncpy(map->object_name, object_name, sizeof(map->object_name));
- map->is_camera = is_camera;
-
- map->num_tracks = num_tracks;
- map->customdata_size = customdata_size;
-
- map->tracks = MEM_callocN(sizeof(MovieTrackingTrack) * num_tracks, "TrackingsMap tracks");
-
- if (customdata_size)
- map->customdata = MEM_callocN(customdata_size * num_tracks, "TracksMap customdata");
-
- map->hash = BLI_ghash_ptr_new("TracksMap hash");
-
- return map;
-}
-
-static int tracks_map_get_size(TracksMap *map)
-{
- return map->num_tracks;
-}
-
-static void tracks_map_get_indexed_element(TracksMap *map, int index, MovieTrackingTrack **track, void **customdata)
-{
- *track = &map->tracks[index];
-
- if (map->customdata)
- *customdata = &map->customdata[index * map->customdata_size];
-}
-
-static void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track, void *customdata)
-{
- MovieTrackingTrack new_track = *track;
-
- new_track.markers = MEM_dupallocN(new_track.markers);
-
- map->tracks[map->ptr] = new_track;
-
- if (customdata)
- memcpy(&map->customdata[map->ptr * map->customdata_size], customdata, map->customdata_size);
-
- BLI_ghash_insert(map->hash, &map->tracks[map->ptr], track);
-
- map->ptr++;
-}
-
-static void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
-{
- MovieTrackingTrack *track;
- ListBase tracks = {NULL, NULL}, new_tracks = {NULL, NULL};
- ListBase *old_tracks;
- int a;
-
- if (map->is_camera) {
- old_tracks = &tracking->tracks;
- }
- else {
- MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, map->object_name);
-
- if (!object) {
- /* object was deleted by user, create new one */
- object = BKE_tracking_object_add(tracking, map->object_name);
- }
-
- old_tracks = &object->tracks;
- }
-
- /* duplicate currently operating tracks to temporary list.
- * this is needed to keep names in unique state and it's faster to change names
- * of currently operating tracks (if needed)
- */
- for (a = 0; a < map->num_tracks; a++) {
- MovieTrackingTrack *old_track;
- bool mapped_to_old = false;
-
- track = &map->tracks[a];
-
- /* find original of operating track in list of previously displayed tracks */
- old_track = BLI_ghash_lookup(map->hash, track);
- if (old_track) {
- if (BLI_findindex(old_tracks, old_track) != -1) {
- BLI_remlink(old_tracks, old_track);
-
- /* Copy flags like selection back to the track map. */
- track->flag = old_track->flag;
- track->pat_flag = old_track->pat_flag;
- track->search_flag = old_track->search_flag;
-
- /* Copy all the rest settings back from the map to the actual tracks. */
- MEM_freeN(old_track->markers);
- *old_track = *track;
- old_track->markers = MEM_dupallocN(old_track->markers);
-
- BLI_addtail(&tracks, old_track);
-
- mapped_to_old = true;
- }
- }
-
- if (mapped_to_old == false) {
- MovieTrackingTrack *new_track = tracking_track_duplicate(track);
-
- /* Update old-new track mapping */
- BLI_ghash_remove(map->hash, track, NULL, NULL);
- BLI_ghash_insert(map->hash, track, new_track);
-
- BLI_addtail(&tracks, new_track);
- }
- }
-
- /* move all tracks, which aren't operating */
- track = old_tracks->first;
- while (track) {
- MovieTrackingTrack *next = track->next;
- BLI_addtail(&new_tracks, track);
- track = next;
- }
-
- /* now move all tracks which are currently operating and keep their names unique */
- track = tracks.first;
- while (track) {
- MovieTrackingTrack *next = track->next;
-
- BLI_remlink(&tracks, track);
-
- track->next = track->prev = NULL;
- BLI_addtail(&new_tracks, track);
-
- BLI_uniquename(&new_tracks, track, CTX_DATA_(BLF_I18NCONTEXT_ID_MOVIECLIP, "Track"), '.',
- offsetof(MovieTrackingTrack, name), sizeof(track->name));
-
- track = next;
- }
-
- *old_tracks = new_tracks;
-}
-
-static void tracks_map_free(TracksMap *map, void (*customdata_free)(void *customdata))
-{
- int i = 0;
-
- BLI_ghash_free(map->hash, NULL, NULL);
-
- for (i = 0; i < map->num_tracks; i++) {
- if (map->customdata && customdata_free)
- customdata_free(&map->customdata[i * map->customdata_size]);
-
- BKE_tracking_track_free(&map->tracks[i]);
- }
-
- if (map->customdata)
- MEM_freeN(map->customdata);
-
- MEM_freeN(map->tracks);
- MEM_freeN(map);
-}
-
-/*********************** 2D tracking *************************/
-
-typedef struct TrackContext {
- /* the reference marker and cutout search area */
- MovieTrackingMarker reference_marker;
-
- /* keyframed patch. This is the search area */
- float *search_area;
- int search_area_height;
- int search_area_width;
- int framenr;
-
- float *mask;
-} TrackContext;
-
-typedef struct MovieTrackingContext {
- MovieClipUser user;
- MovieClip *clip;
- int clip_flag;
-
- int frames, first_frame;
- bool first_time;
-
- MovieTrackingSettings settings;
- TracksMap *tracks_map;
-
- bool backwards, sequence;
- int sync_frame;
-} MovieTrackingContext;
-
-static void track_context_free(void *customdata)
-{
- TrackContext *track_context = (TrackContext *)customdata;
-
- if (track_context->search_area)
- MEM_freeN(track_context->search_area);
-
- if (track_context->mask)
- MEM_freeN(track_context->mask);
-}
-
-/* Create context for motion 2D tracking, copies all data needed
- * for thread-safe tracking, allowing clip modifications during
- * tracking.
- */
-MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, short backwards, short sequence)
-{
- MovieTrackingContext *context = MEM_callocN(sizeof(MovieTrackingContext), "trackingContext");
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingSettings *settings = &tracking->settings;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track;
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- int num_tracks = 0;
-
- context->clip = clip;
- context->settings = *settings;
- context->backwards = backwards;
- context->sync_frame = user->framenr;
- context->first_time = true;
- context->first_frame = user->framenr;
- context->sequence = sequence;
-
- /* count */
- track = tracksbase->first;
- while (track) {
- if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) {
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- if ((marker->flag & MARKER_DISABLED) == 0)
- num_tracks++;
- }
-
- track = track->next;
- }
-
- /* create tracking contextx for all tracks which would be tracked */
- if (num_tracks) {
- int width, height;
-
- context->tracks_map = tracks_map_new(object->name, object->flag & TRACKING_OBJECT_CAMERA,
- num_tracks, sizeof(TrackContext));
-
- BKE_movieclip_get_size(clip, user, &width, &height);
-
- /* create tracking data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_SELECTED(track) && (track->flag & (TRACK_HIDDEN | TRACK_LOCKED)) == 0) {
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- if ((marker->flag & MARKER_DISABLED) == 0) {
- TrackContext track_context;
- memset(&track_context, 0, sizeof(TrackContext));
- tracks_map_insert(context->tracks_map, track, &track_context);
- }
- }
-
- track = track->next;
- }
- }
-
- /* store needed clip flags passing to get_buffer functions
- * - MCLIP_USE_PROXY is needed to because timecode affects on movie clip
- * only in case Proxy/Timecode flag is set, so store this flag to use
- * timecodes properly but reset render size to SIZE_FULL so correct resolution
- * would be used for images
- * - MCLIP_USE_PROXY_CUSTOM_DIR is needed because proxy/timecode files might
- * be stored in a different location
- * ignore all the rest possible flags for now
- */
- context->clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
-
- context->user = *user;
- context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- context->user.render_flag = 0;
-
- if (!sequence)
- BLI_begin_threaded_malloc();
-
- return context;
-}
-
-/* Free context used for tracking. */
-void BKE_tracking_context_free(MovieTrackingContext *context)
-{
- if (!context->sequence)
- BLI_end_threaded_malloc();
-
- tracks_map_free(context->tracks_map, track_context_free);
-
- MEM_freeN(context);
-}
-
-/* Synchronize tracks between clip editor and tracking context,
- * by merging them together so all new created tracks and tracked
- * ones presents in the movie clip.
- */
-void BKE_tracking_context_sync(MovieTrackingContext *context)
-{
- MovieTracking *tracking = &context->clip->tracking;
- int newframe;
-
- tracks_map_merge(context->tracks_map, tracking);
-
- if (context->backwards)
- newframe = context->user.framenr + 1;
- else
- newframe = context->user.framenr - 1;
-
- context->sync_frame = newframe;
-
- BKE_tracking_dopesheet_tag_update(tracking);
-}
-
-/* Synchronize clip user's frame number with a frame number from tracking context,
- * used to update current frame displayed in the clip editor while tracking.
- */
-void BKE_tracking_context_sync_user(const MovieTrackingContext *context, MovieClipUser *user)
-{
- user->framenr = context->sync_frame;
-}
-
-/* **** utility functions for tracking **** */
-
-/* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
-static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels,
- float weight_red, float weight_green, float weight_blue)
-{
- int i;
-
- for (i = 0; i < num_pixels; i++) {
- const float *pixel = rgba + 4 * i;
-
- gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
- }
-}
-
-static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels,
- float weight_red, float weight_green, float weight_blue)
-{
- int i;
-
- for (i = 0; i < num_pixels; i++) {
- const unsigned char *pixel = rgba + i * 4;
-
- gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
- }
-}
-
-/* Get grayscale float search buffer for given marker and frame. */
-static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int *width_r, int *height_r)
-{
- ImBuf *searchibuf;
- float *gray_pixels;
- int width, height;
-
- searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
-
- if (!searchibuf) {
- *width_r = 0;
- *height_r = 0;
- return NULL;
- }
-
- width = searchibuf->x;
- height = searchibuf->y;
-
- gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
-
- if (searchibuf->rect_float) {
- float_rgba_to_gray(searchibuf->rect_float, gray_pixels, width * height,
- 0.2126f, 0.7152f, 0.0722f);
- }
- else {
- uint8_rgba_to_float_gray((unsigned char *)searchibuf->rect, gray_pixels, width * height,
- 0.2126f, 0.7152f, 0.0722f);
- }
-
- IMB_freeImBuf(searchibuf);
-
- *width_r = width;
- *height_r = height;
-
- return gray_pixels;
-}
-
-/* Get image boffer for a given frame
- *
- * Frame is in clip space.
- */
-static ImBuf *tracking_context_get_frame_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, int framenr)
-{
- ImBuf *ibuf;
- MovieClipUser new_user = *user;
-
- new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
-
- ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
-
- return ibuf;
-}
-
-/* Get previous keyframed marker. */
-static MovieTrackingMarker *tracking_context_get_keyframed_marker(MovieTrackingTrack *track,
- int curfra, bool backwards)
-{
- MovieTrackingMarker *marker_keyed = NULL;
- MovieTrackingMarker *marker_keyed_fallback = NULL;
- int a = BKE_tracking_marker_get(track, curfra) - track->markers;
-
- while (a >= 0 && a < track->markersnr) {
- int next = backwards ? a + 1 : a - 1;
- bool is_keyframed = false;
- MovieTrackingMarker *cur_marker = &track->markers[a];
- MovieTrackingMarker *next_marker = NULL;
-
- if (next >= 0 && next < track->markersnr)
- next_marker = &track->markers[next];
-
- if ((cur_marker->flag & MARKER_DISABLED) == 0) {
- /* If it'll happen so we didn't find a real keyframe marker,
- * fallback to the first marker in current tracked segment
- * as a keyframe.
- */
- if (next_marker && next_marker->flag & MARKER_DISABLED) {
- if (marker_keyed_fallback == NULL)
- marker_keyed_fallback = cur_marker;
- }
-
- is_keyframed |= (cur_marker->flag & MARKER_TRACKED) == 0;
- }
-
- if (is_keyframed) {
- marker_keyed = cur_marker;
-
- break;
- }
-
- a = next;
- }
-
- if (marker_keyed == NULL)
- marker_keyed = marker_keyed_fallback;
-
- return marker_keyed;
-}
-
-/* Get image buffer for previous marker's keyframe. */
-static ImBuf *tracking_context_get_keyframed_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
- MovieTrackingTrack *track, int curfra, bool backwards,
- MovieTrackingMarker **marker_keyed_r)
-{
- MovieTrackingMarker *marker_keyed;
- int keyed_framenr;
-
- marker_keyed = tracking_context_get_keyframed_marker(track, curfra, backwards);
- if (marker_keyed == NULL) {
- return NULL;
- }
-
- keyed_framenr = marker_keyed->framenr;
-
- *marker_keyed_r = marker_keyed;
-
- return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
-}
-
-/* Get image buffer which si used as referece for track. */
-static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
- MovieTrackingTrack *track, int curfra, bool backwards,
- MovieTrackingMarker **reference_marker)
-{
- ImBuf *ibuf = NULL;
-
- if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
- ibuf = tracking_context_get_keyframed_ibuf(clip, user, clip_flag, track, curfra, backwards, reference_marker);
- }
- else {
- ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
-
- /* use current marker as keyframed position */
- *reference_marker = BKE_tracking_marker_get(track, curfra);
- }
-
- return ibuf;
-}
-
-/* Update track's reference patch (patch from which track is tracking from)
- *
- * Returns false if reference image buffer failed to load.
- */
-static bool track_context_update_reference(MovieTrackingContext *context, TrackContext *track_context,
- MovieTrackingTrack *track, MovieTrackingMarker *marker, int curfra,
- int frame_width, int frame_height)
-{
- MovieTrackingMarker *reference_marker = NULL;
- ImBuf *reference_ibuf = NULL;
- int width, height;
-
- /* calculate patch for keyframed position */
- reference_ibuf = tracking_context_get_reference_ibuf(context->clip, &context->user, context->clip_flag,
- track, curfra, context->backwards, &reference_marker);
-
- if (!reference_ibuf)
- return false;
-
- track_context->reference_marker = *reference_marker;
-
- if (track_context->search_area) {
- MEM_freeN(track_context->search_area);
- }
-
- track_context->search_area = track_get_search_floatbuf(reference_ibuf, track, reference_marker, &width, &height);
- track_context->search_area_height = height;
- track_context->search_area_width = width;
-
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0) {
- if (track_context->mask)
- MEM_freeN(track_context->mask);
-
- track_context->mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
- }
-
- IMB_freeImBuf(reference_ibuf);
-
- return true;
-}
-
-/* Fill in libmv tracker options structure with settings need to be used to perform track. */
-static void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
- libmv_TrackRegionOptions *options)
-{
- options->motion_model = track->motion_model;
-
- options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
-
- options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) != 0);
-
- options->num_iterations = 50;
- options->minimum_correlation = track->minimum_correlation;
- options->sigma = 0.9;
-
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
- options->image1_mask = mask;
- else
- options->image1_mask = NULL;
-}
-
-/* returns false if marker crossed margin area from frame bounds */
-static bool tracking_check_marker_margin(MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int frame_width, int frame_height)
-{
- float pat_min[2], pat_max[2];
- float margin_left, margin_top, margin_right, margin_bottom;
- float normalized_track_margin[2];
-
- /* margin from frame boundaries */
- BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
-
- normalized_track_margin[0] = (float)track->margin / frame_width;
- normalized_track_margin[1] = (float)track->margin / frame_height;
-
- margin_left = max_ff(-pat_min[0], normalized_track_margin[0]);
- margin_top = max_ff( pat_max[1], normalized_track_margin[1]);
- margin_right = max_ff( pat_max[0], normalized_track_margin[0]);
- margin_bottom = max_ff(-pat_min[1], normalized_track_margin[1]);
-
- /* do not track markers which are too close to boundary */
- if (marker->pos[0] < margin_left || marker->pos[0] > 1.0f - margin_right ||
- marker->pos[1] < margin_bottom || marker->pos[1] > 1.0f - margin_top)
- {
- return false;
- }
-
- return true;
-}
-
-/* Scale search area of marker based on scale changes of pattern area,
- *
- * TODO(sergey): currently based on pattern bounding box scale change,
- * smarter approach here is welcome.
- */
-static void tracking_scale_marker_search(const MovieTrackingMarker *old_marker, MovieTrackingMarker *new_marker)
-{
- float old_pat_min[2], old_pat_max[2];
- float new_pat_min[2], new_pat_max[2];
- float scale_x, scale_y;
-
- BKE_tracking_marker_pattern_minmax(old_marker, old_pat_min, old_pat_max);
- BKE_tracking_marker_pattern_minmax(new_marker, new_pat_min, new_pat_max);
-
- scale_x = (new_pat_max[0] - new_pat_min[0]) / (old_pat_max[0] - old_pat_min[0]);
- scale_y = (new_pat_max[1] - new_pat_min[1]) / (old_pat_max[1] - old_pat_min[1]);
-
- new_marker->search_min[0] *= scale_x;
- new_marker->search_min[1] *= scale_y;
-
- new_marker->search_max[0] *= scale_x;
- new_marker->search_max[1] *= scale_y;
-}
-
-/* Insert new marker which was tracked from old_marker to a new image,
- * will also ensure tracked segment is surrounded by disabled markers.
- */
-static void tracking_insert_new_marker(MovieTrackingContext *context, MovieTrackingTrack *track,
- const MovieTrackingMarker *old_marker, int curfra, bool tracked,
- int frame_width, int frame_height,
- double dst_pixel_x[5], double dst_pixel_y[5])
-{
- MovieTrackingMarker new_marker;
- int frame_delta = context->backwards ? -1 : 1;
- int nextfra = curfra + frame_delta;
-
- new_marker = *old_marker;
-
- if (tracked) {
- set_marker_coords_from_tracking(frame_width, frame_height, &new_marker, dst_pixel_x, dst_pixel_y);
- new_marker.flag |= MARKER_TRACKED;
- new_marker.framenr = nextfra;
-
- tracking_scale_marker_search(old_marker, &new_marker);
-
- if (context->first_time) {
- /* check if there's no keyframe/tracked markers before tracking marker.
- * if so -- create disabled marker before currently tracking "segment"
- */
-
- tracking_marker_insert_disabled(track, old_marker, !context->backwards, false);
- }
-
- /* insert currently tracked marker */
- BKE_tracking_marker_insert(track, &new_marker);
-
- /* make currently tracked segment be finished with disabled marker */
- tracking_marker_insert_disabled(track, &new_marker, context->backwards, false);
- }
- else {
- new_marker.framenr = nextfra;
- new_marker.flag |= MARKER_DISABLED;
-
- BKE_tracking_marker_insert(track, &new_marker);
- }
-}
-
-/* Peform tracking from a reference_marker to destination_ibuf.
- * Uses marker as an initial position guess.
- *
- * Returns truth if tracker returned success, puts result
- * to dst_pixel_x and dst_pixel_y.
- */
-static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrack *track,
- MovieTrackingMarker *reference_marker, MovieTrackingMarker *marker,
- float *reference_search_area, int reference_search_area_width,
- int reference_search_area_height, float *mask,
- double dst_pixel_x[5], double dst_pixel_y[5])
-{
- /* To convert to the x/y split array format for libmv. */
- double src_pixel_x[5], src_pixel_y[5];
-
- /* Settings for the tracker */
- libmv_TrackRegionOptions options = {0};
- libmv_TrackRegionResult result;
-
- float *patch_new;
-
- int new_search_area_width, new_search_area_height;
- int frame_width, frame_height;
-
- bool tracked;
-
- frame_width = destination_ibuf->x;
- frame_height = destination_ibuf->y;
-
- /* for now track to the same search area dimension as marker has got for current frame
- * will make all tracked markers in currently tracked segment have the same search area
- * size, but it's quite close to what is actually needed
- */
- patch_new = track_get_search_floatbuf(destination_ibuf, track, marker,
- &new_search_area_width, &new_search_area_height);
-
- /* configure the tracker */
- tracking_configure_tracker(track, mask, &options);
-
- /* convert the marker corners and center into pixel coordinates in the search/destination images. */
- get_marker_coords_for_tracking(frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
- get_marker_coords_for_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
-
- if (patch_new == NULL || reference_search_area == NULL)
- return false;
-
- /* run the tracker! */
- tracked = libmv_trackRegion(&options,
- reference_search_area,
- reference_search_area_width,
- reference_search_area_height,
- patch_new,
- new_search_area_width,
- new_search_area_height,
- src_pixel_x, src_pixel_y,
- &result,
- dst_pixel_x, dst_pixel_y);
- MEM_freeN(patch_new);
-
- return tracked;
-}
-
-/* Track all the tracks from context one more frame,
- * returns FALSe if nothing was tracked.
- */
-bool BKE_tracking_context_step(MovieTrackingContext *context)
-{
- ImBuf *destination_ibuf;
- int frame_delta = context->backwards ? -1 : 1;
- int curfra = BKE_movieclip_remap_scene_to_clip_frame(context->clip, context->user.framenr);
- int a, map_size;
- bool ok = false;
-
- int frame_width, frame_height;
-
- map_size = tracks_map_get_size(context->tracks_map);
-
- /* Nothing to track, avoid unneeded frames reading to save time and memory. */
- if (!map_size)
- return false;
-
- /* Get an image buffer for frame we're tracking to. */
- context->user.framenr += frame_delta;
-
- destination_ibuf = BKE_movieclip_get_ibuf_flag(context->clip, &context->user,
- context->clip_flag, MOVIECLIP_CACHE_SKIP);
- if (!destination_ibuf)
- return false;
-
- frame_width = destination_ibuf->x;
- frame_height = destination_ibuf->y;
-
-#pragma omp parallel for private(a) shared(destination_ibuf, ok) if (map_size > 1)
- for (a = 0; a < map_size; a++) {
- TrackContext *track_context = NULL;
- MovieTrackingTrack *track;
- MovieTrackingMarker *marker;
-
- tracks_map_get_indexed_element(context->tracks_map, a, &track, (void **)&track_context);
-
- marker = BKE_tracking_marker_get_exact(track, curfra);
-
- if (marker && (marker->flag & MARKER_DISABLED) == 0) {
- bool tracked = false, need_readjust;
- double dst_pixel_x[5], dst_pixel_y[5];
-
- if (track->pattern_match == TRACK_MATCH_KEYFRAME)
- need_readjust = context->first_time;
- else
- need_readjust = true;
-
- /* do not track markers which are too close to boundary */
- if (tracking_check_marker_margin(track, marker, frame_width, frame_height)) {
- if (need_readjust) {
- if (track_context_update_reference(context, track_context, track, marker,
- curfra, frame_width, frame_height) == false)
- {
- /* happens when reference frame fails to be loaded */
- continue;
- }
- }
-
- tracked = configure_and_run_tracker(destination_ibuf, track,
- &track_context->reference_marker, marker,
- track_context->search_area,
- track_context->search_area_width,
- track_context->search_area_height,
- track_context->mask,
- dst_pixel_x, dst_pixel_y);
- }
-
-#pragma omp critical
- {
- tracking_insert_new_marker(context, track, marker, curfra, tracked,
- frame_width, frame_height, dst_pixel_x, dst_pixel_y);
- }
-
- ok = true;
- }
- }
-
- IMB_freeImBuf(destination_ibuf);
-
- context->first_time = false;
- context->frames++;
-
- return ok;
-}
-
-void BKE_tracking_context_finish(MovieTrackingContext *context)
-{
- MovieClip *clip = context->clip;
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingPlaneTrack *plane_track;
- int map_size = tracks_map_get_size(context->tracks_map);
-
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = plane_track->next)
- {
- if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < map_size; i++) {
- TrackContext *track_context = NULL;
- MovieTrackingTrack *track, *old_track;
- bool do_update = false;
- int j;
-
- tracks_map_get_indexed_element(context->tracks_map, i, &track, (void **)&track_context);
-
- old_track = BLI_ghash_lookup(context->tracks_map->hash, 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;
- }
- }
- }
- }
-}
-
-/* Refine marker's position using previously known keyframe.
- * Direction of searching for a keyframe depends on backwards flag,
- * which means if backwards is false, previous keyframe will be as
- * reference.
- */
-void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards)
-{
- MovieTrackingMarker *reference_marker = NULL;
- ImBuf *reference_ibuf, *destination_ibuf;
- float *search_area, *mask = NULL;
- int frame_width, frame_height;
- int search_area_height, search_area_width;
- int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
- int reference_framenr;
- MovieClipUser user = {0};
- double dst_pixel_x[5], dst_pixel_y[5];
- bool tracked;
-
- /* Construct a temporary clip used, used to acquire image buffers. */
- user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
-
- BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
-
- /* Get an image buffer for reference frame, also gets reference marker.
- *
- * Usually tracking_context_get_reference_ibuf will return current frame
- * if marker is keyframed, which is correct for normal tracking. But here
- * we'll want to have next/previous frame in such cases. So let's use small
- * magic with original frame number used to get reference frame for.
- */
- reference_framenr = backwards ? marker->framenr + 1 : marker->framenr - 1;
- reference_ibuf = tracking_context_get_reference_ibuf(clip, &user, clip_flag, track, reference_framenr,
- backwards, &reference_marker);
- if (reference_ibuf == NULL) {
- return;
- }
-
- /* Could not refine with self. */
- if (reference_marker == marker) {
- return;
- }
-
- /* Destination image buffer has got frame number corresponding to refining marker. */
- destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
- if (destination_ibuf == NULL) {
- IMB_freeImBuf(reference_ibuf);
- return;
- }
-
- /* Get search area from reference image. */
- search_area = track_get_search_floatbuf(reference_ibuf, track, reference_marker,
- &search_area_width, &search_area_height);
-
- /* If needed, compute track's mask. */
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
- mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
-
- /* Run the tracker from reference frame to current one. */
- tracked = configure_and_run_tracker(destination_ibuf, track, reference_marker, marker,
- search_area, search_area_width, search_area_height,
- mask, dst_pixel_x, dst_pixel_y);
-
- /* Refine current marker's position if track was successful. */
- if (tracked) {
- set_marker_coords_from_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
- marker->flag |= MARKER_TRACKED;
- }
-
- /* Free memory used for refining */
- MEM_freeN(search_area);
- if (mask)
- MEM_freeN(mask);
- IMB_freeImBuf(reference_ibuf);
- IMB_freeImBuf(destination_ibuf);
-}
-
-/*********************** Plane tracking *************************/
-
-typedef double Vec2[2];
-
-static int point_markers_correspondences_on_both_image(MovieTrackingPlaneTrack *plane_track, int frame1, int frame2,
- Vec2 **x1_r, Vec2 **x2_r)
-{
- int i, correspondence_index;
- Vec2 *x1, *x2;
-
- *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
- *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
-
- for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) {
- MovieTrackingTrack *point_track = plane_track->point_tracks[i];
- MovieTrackingMarker *point_marker1, *point_marker2;
-
- point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1);
- point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2);
-
- if (point_marker1 != NULL && point_marker2 != NULL) {
- /* Here conversion from float to double happens. */
- x1[correspondence_index][0] = point_marker1->pos[0];
- x1[correspondence_index][1] = point_marker1->pos[1];
-
- x2[correspondence_index][0] = point_marker2->pos[0];
- x2[correspondence_index][1] = point_marker2->pos[1];
-
- correspondence_index++;
- }
- }
-
- return correspondence_index;
-}
-
-/* NOTE: frame number should be in clip space, not scene space */
-static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame,
- int direction, bool retrack)
-{
- MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
- MovieTrackingPlaneMarker *keyframe_plane_marker = NULL;
- MovieTrackingPlaneMarker new_plane_marker;
- int current_frame, frame_delta = direction > 0 ? 1 : -1;
-
- if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
- /* Find a keyframe in given direction. */
- for (current_frame = start_frame; ; current_frame += frame_delta) {
- MovieTrackingPlaneMarker *next_plane_marker =
- BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta);
-
- if (next_plane_marker == NULL) {
- break;
- }
-
- if ((next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- keyframe_plane_marker = next_plane_marker;
- break;
- }
- }
- }
- else {
- start_plane_marker->flag |= PLANE_MARKER_TRACKED;
- }
-
- new_plane_marker = *start_plane_marker;
- new_plane_marker.flag |= PLANE_MARKER_TRACKED;
-
- for (current_frame = start_frame; ; current_frame += frame_delta) {
- MovieTrackingPlaneMarker *next_plane_marker =
- BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta);
- Vec2 *x1, *x2;
- int i, num_correspondences;
- double H_double[3][3];
- float H[3][3];
-
- /* As soon as we meet keyframed plane, we stop updating the sequence. */
- if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- /* Don't override keyframes if track is in auto-keyframe mode */
- if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
- break;
- }
- }
-
- num_correspondences =
- point_markers_correspondences_on_both_image(plane_track, current_frame, current_frame + frame_delta,
- &x1, &x2);
-
- if (num_correspondences < 4) {
- MEM_freeN(x1);
- MEM_freeN(x2);
-
- break;
- }
-
- libmv_homography2DFromCorrespondencesEuc(x1, x2, num_correspondences, H_double);
-
- copy_m3_m3d(H, H_double);
-
- for (i = 0; i < 4; i++) {
- float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3];
- copy_v2_v2(vec, new_plane_marker.corners[i]);
-
- /* Apply homography */
- mul_v3_m3v3(vec2, H, vec);
-
- /* Normalize. */
- vec2[0] /= vec2[2];
- vec2[1] /= vec2[2];
-
- copy_v2_v2(new_plane_marker.corners[i], vec2);
- }
-
- new_plane_marker.framenr = current_frame + frame_delta;
-
- if (!retrack && keyframe_plane_marker &&
- next_plane_marker &&
- (plane_track->flag & PLANE_TRACK_AUTOKEY))
- {
- float fac = ((float) next_plane_marker->framenr - start_plane_marker->framenr) /
- ((float) keyframe_plane_marker->framenr - start_plane_marker->framenr);
-
- fac = 3 * fac * fac - 2 * fac * fac * fac;
-
- for (i = 0; i < 4; i++) {
- interp_v2_v2v2(new_plane_marker.corners[i], new_plane_marker.corners[i],
- next_plane_marker->corners[i], fac);
- }
- }
-
- BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker);
-
- MEM_freeN(x1);
- MEM_freeN(x2);
- }
-}
-
-/* NOTE: frame number should be in clip space, not scene space */
-void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame)
-{
- track_plane_from_existing_motion(plane_track, start_frame, 1, false);
- track_plane_from_existing_motion(plane_track, start_frame, -1, false);
-}
-
-static MovieTrackingPlaneMarker *find_plane_keyframe(MovieTrackingPlaneTrack *plane_track,
- int start_frame, int direction)
-{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
- int index = plane_marker - plane_track->markers;
- int frame_delta = direction > 0 ? 1 : -1;
-
- while (index >= 0 && index < plane_track->markersnr) {
- if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- return plane_marker;
- }
- plane_marker += frame_delta;
- }
-
- return NULL;
-}
-
-void BKE_tracking_retrack_plane_from_existing_motion_at_segment(MovieTrackingPlaneTrack *plane_track, int start_frame)
-{
- MovieTrackingPlaneMarker *prev_plane_keyframe, *next_plane_keyframe;
-
- prev_plane_keyframe = find_plane_keyframe(plane_track, start_frame, -1);
- next_plane_keyframe = find_plane_keyframe(plane_track, start_frame, 1);
-
- if (prev_plane_keyframe != NULL && next_plane_keyframe != NULL) {
- /* First we track from left keyframe to the right one without any blending. */
- track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
-
- /* And then we track from the right keyframe to the left one, so shape blends in nicely */
- track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, false);
- }
- else if (prev_plane_keyframe != NULL) {
- track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
- }
- else if (next_plane_keyframe != NULL) {
- track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, true);
- }
-}
-
-BLI_INLINE void float_corners_to_double(/*const*/ float corners[4][2], double double_corners[4][2])
-{
- copy_v2db_v2fl(double_corners[0], corners[0]);
- copy_v2db_v2fl(double_corners[1], corners[1]);
- copy_v2db_v2fl(double_corners[2], corners[2]);
- copy_v2db_v2fl(double_corners[3], corners[3]);
-}
-
-void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3])
-{
- Vec2 x1[4], x2[4];
- double H_double[3][3];
-
- float_corners_to_double(reference_corners, x1);
- float_corners_to_double(corners, x2);
-
- libmv_homography2DFromCorrespondencesEuc(x1, x2, 4, H_double);
-
- copy_m3_m3d(H, H_double);
-}
-
-/*********************** Camera solving *************************/
-
-typedef struct MovieReconstructContext {
- struct libmv_Tracks *tracks;
- bool select_keyframes;
- int keyframe1, keyframe2;
- int refine_flags;
-
- struct libmv_Reconstruction *reconstruction;
-
- char object_name[MAX_NAME];
- bool is_camera;
- short motion_flag;
-
- float focal_length;
- float principal_point[2];
- float k1, k2, k3;
-
- int width, height;
-
- float reprojection_error;
-
- TracksMap *tracks_map;
-
- int sfra, efra;
-} MovieReconstructContext;
-
-typedef struct ReconstructProgressData {
- short *stop;
- short *do_update;
- float *progress;
- char *stats_message;
- int message_size;
-} ReconstructProgressData;
-
-/* Create new libmv Tracks structure from blender's tracks list. */
-static struct libmv_Tracks *libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
-{
- int tracknr = 0;
- MovieTrackingTrack *track;
- struct libmv_Tracks *tracks = libmv_tracksNew();
-
- track = tracksbase->first;
- while (track) {
- FCurve *weight_fcurve;
- int a = 0;
-
- weight_fcurve = id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack,
- "weight", 0, NULL);
-
- for (a = 0; a < track->markersnr; a++) {
- MovieTrackingMarker *marker = &track->markers[a];
-
- if ((marker->flag & MARKER_DISABLED) == 0) {
- float weight = track->weight;
-
- if (weight_fcurve) {
- int scene_framenr =
- BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
- weight = evaluate_fcurve(weight_fcurve, scene_framenr);
- }
-
- libmv_tracksInsert(tracks, marker->framenr, tracknr,
- (marker->pos[0] + track->offset[0]) * width,
- (marker->pos[1] + track->offset[1]) * height,
- weight);
- }
- }
-
- track = track->next;
- tracknr++;
- }
-
- return tracks;
-}
-
-/* Retrieve refined camera intrinsics from libmv to blender. */
-static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
-{
- struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
- struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction);
-
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
- double focal_length, principal_x, principal_y, k1, k2, k3;
- int width, height;
-
- libmv_cameraIntrinsicsExtract(libmv_intrinsics, &focal_length, &principal_x, &principal_y,
- &k1, &k2, &k3, &width, &height);
-
- tracking->camera.focal = focal_length;
-
- tracking->camera.principal[0] = principal_x;
- tracking->camera.principal[1] = principal_y / (double)aspy;
-
- tracking->camera.k1 = k1;
- tracking->camera.k2 = k2;
- tracking->camera.k3 = k3;
-}
-
-/* Retrieve reconstructed tracks from libmv to blender.
- * Actually, this also copies reconstructed cameras
- * from libmv to movie clip datablock.
- */
-static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
-{
- struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
- MovieTrackingReconstruction *reconstruction = NULL;
- MovieReconstructedCamera *reconstructed;
- MovieTrackingTrack *track;
- ListBase *tracksbase = NULL;
- int tracknr = 0, a;
- bool ok = true;
- bool origin_set = false;
- int sfra = context->sfra, efra = context->efra;
- float imat[4][4];
-
- if (context->is_camera) {
- tracksbase = &tracking->tracks;
- reconstruction = &tracking->reconstruction;
- }
- else {
- MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, context->object_name);
-
- tracksbase = &object->tracks;
- reconstruction = &object->reconstruction;
- }
-
- unit_m4(imat);
-
- track = tracksbase->first;
- while (track) {
- double pos[3];
-
- if (libmv_reprojectionPointForTrack(libmv_reconstruction, tracknr, pos)) {
- track->bundle_pos[0] = pos[0];
- track->bundle_pos[1] = pos[1];
- track->bundle_pos[2] = pos[2];
-
- track->flag |= TRACK_HAS_BUNDLE;
- track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, tracknr);
- }
- else {
- track->flag &= ~TRACK_HAS_BUNDLE;
- ok = false;
-
- printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name);
- }
-
- track = track->next;
- tracknr++;
- }
-
- if (reconstruction->cameras)
- MEM_freeN(reconstruction->cameras);
-
- reconstruction->camnr = 0;
- reconstruction->cameras = NULL;
- reconstructed = MEM_callocN((efra - sfra + 1) * sizeof(MovieReconstructedCamera),
- "temp reconstructed camera");
-
- for (a = sfra; a <= efra; a++) {
- double matd[4][4];
-
- if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
- int i, j;
- float mat[4][4];
- float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- mat[i][j] = matd[i][j];
- }
-
- /* Ensure first camera has got zero rotation and transform.
- * This is essential for object tracking to work -- this way
- * we'll always know object and environment are properly
- * oriented.
- *
- * There's one weak part tho, which is requirement object
- * motion starts at the same frame as camera motion does,
- * otherwise that;' be a russian roulette whether object is
- * aligned correct or not.
- */
- if (!origin_set) {
- invert_m4_m4(imat, mat);
- unit_m4(mat);
- origin_set = true;
- }
- else {
- mul_m4_m4m4(mat, imat, mat);
- }
-
- copy_m4_m4(reconstructed[reconstruction->camnr].mat, mat);
- reconstructed[reconstruction->camnr].framenr = a;
- reconstructed[reconstruction->camnr].error = error;
- reconstruction->camnr++;
- }
- else {
- ok = false;
- printf("No camera for frame %d\n", a);
- }
- }
-
- if (reconstruction->camnr) {
- int size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
- reconstruction->cameras = MEM_callocN(size, "reconstructed camera");
- memcpy(reconstruction->cameras, reconstructed, size);
- }
-
- if (origin_set) {
- track = tracksbase->first;
- while (track) {
- if (track->flag & TRACK_HAS_BUNDLE)
- mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
-
- track = track->next;
- }
- }
-
- MEM_freeN(reconstructed);
-
- return ok;
-}
-
-/* Retrieve all the libmv data from context to blender's side data blocks. */
-static int reconstruct_retrieve_libmv(MovieReconstructContext *context, MovieTracking *tracking)
-{
- /* take the intrinsics back from libmv */
- reconstruct_retrieve_libmv_intrinsics(context, tracking);
-
- return reconstruct_retrieve_libmv_tracks(context, tracking);
-}
-
-/* Convert blender's refinement flags to libmv's. */
-static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, MovieTrackingObject *object)
-{
- int refine = tracking->settings.refine_camera_intrinsics;
- int flags = 0;
-
- if ((object->flag & TRACKING_OBJECT_CAMERA) == 0)
- return 0;
-
- if (refine & REFINE_FOCAL_LENGTH)
- flags |= LIBMV_REFINE_FOCAL_LENGTH;
-
- if (refine & REFINE_PRINCIPAL_POINT)
- flags |= LIBMV_REFINE_PRINCIPAL_POINT;
-
- if (refine & REFINE_RADIAL_DISTORTION_K1)
- flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
-
- if (refine & REFINE_RADIAL_DISTORTION_K2)
- flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
-
- return flags;
-}
-
-/* Count tracks which has markers at both of keyframes. */
-static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking, MovieTrackingObject *object)
-{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- int tot = 0;
- int frame1 = object->keyframe1, frame2 = object->keyframe2;
- MovieTrackingTrack *track;
-
- track = tracksbase->first;
- while (track) {
- if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame1)) {
- if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame2)) {
- tot++;
- }
- }
-
- track = track->next;
- }
-
- return tot;
-}
-
-/* Perform early check on whether everything is fine to start reconstruction. */
-bool BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObject *object,
- char *error_msg, int error_size)
-{
- if (tracking->settings.motion_flag & TRACKING_MOTION_MODAL) {
- /* TODO: check for number of tracks? */
- return true;
- }
- else if ((tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) == 0) {
- /* automatic keyframe selection does not require any pre-process checks */
- if (reconstruct_count_tracks_on_both_keyframes(tracking, object) < 8) {
- BLI_strncpy(error_msg,
- N_("At least 8 common tracks on both of keyframes are needed for reconstruction"),
- error_size);
-
- return false;
- }
- }
-
-#ifndef WITH_LIBMV
- BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size);
- return false;
-#endif
-
- return true;
-}
-
-/* Create context for camera/object motion reconstruction.
- * Copies all data needed for reconstruction from movie
- * clip datablock, so editing this clip is safe during
- * reconstruction job is in progress.
- */
-MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip, MovieTrackingObject *object,
- int keyframe1, int keyframe2, int width, int height)
-{
- MovieTracking *tracking = &clip->tracking;
- MovieReconstructContext *context = MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
- MovieTrackingCamera *camera = &tracking->camera;
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- float aspy = 1.0f / tracking->camera.pixel_aspect;
- int num_tracks = BLI_countlist(tracksbase);
- int sfra = INT_MAX, efra = INT_MIN;
- MovieTrackingTrack *track;
-
- BLI_strncpy(context->object_name, object->name, sizeof(context->object_name));
- context->is_camera = object->flag & TRACKING_OBJECT_CAMERA;
- context->motion_flag = tracking->settings.motion_flag;
-
- context->select_keyframes =
- (tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) != 0;
-
- context->focal_length = camera->focal;
- context->principal_point[0] = camera->principal[0];
- context->principal_point[1] = camera->principal[1] * aspy;
-
- context->width = width;
- context->height = height;
-
- context->k1 = camera->k1;
- context->k2 = camera->k2;
- context->k3 = camera->k3;
-
- context->tracks_map = tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);
-
- track = tracksbase->first;
- while (track) {
- int first = 0, last = track->markersnr - 1;
- MovieTrackingMarker *first_marker = &track->markers[0];
- MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
-
- /* find first not-disabled marker */
- while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
- first++;
- first_marker++;
- }
-
- /* find last not-disabled marker */
- while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
- last--;
- last_marker--;
- }
-
- if (first < track->markersnr - 1)
- sfra = min_ii(sfra, first_marker->framenr);
-
- if (last >= 0)
- efra = max_ii(efra, last_marker->framenr);
-
- tracks_map_insert(context->tracks_map, track, NULL);
-
- track = track->next;
- }
-
- context->sfra = sfra;
- context->efra = efra;
-
- context->tracks = libmv_tracks_new(clip, tracksbase, width, height * aspy);
- context->keyframe1 = keyframe1;
- context->keyframe2 = keyframe2;
- context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
-
- return context;
-}
-
-/* Free memory used by a reconstruction process. */
-void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
-{
- if (context->reconstruction)
- libmv_reconstructionDestroy(context->reconstruction);
-
- libmv_tracksDestroy(context->tracks);
-
- tracks_map_free(context->tracks_map, NULL);
-
- MEM_freeN(context);
-}
-
-/* Callback which is called from libmv side to update progress in the interface. */
-static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
-{
- ReconstructProgressData *progressdata = customdata;
-
- if (progressdata->progress) {
- *progressdata->progress = progress;
- *progressdata->do_update = TRUE;
- }
-
- BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
-}
-/* FIll in camera intrinsics structure from reconstruction context. */
-static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
- MovieReconstructContext *context)
-{
- camera_intrinsics_options->focal_length = context->focal_length;
-
- camera_intrinsics_options->principal_point_x = context->principal_point[0];
- camera_intrinsics_options->principal_point_y = context->principal_point[1];
-
- camera_intrinsics_options->k1 = context->k1;
- camera_intrinsics_options->k2 = context->k2;
- camera_intrinsics_options->k3 = context->k3;
-
- camera_intrinsics_options->image_width = context->width;
- camera_intrinsics_options->image_height = context->height;
-}
-
-/* Fill in reconstruction options structure from reconstruction context. */
-static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *reconstruction_options,
- MovieReconstructContext *context)
-{
- reconstruction_options->select_keyframes = context->select_keyframes;
-
- reconstruction_options->keyframe1 = context->keyframe1;
- reconstruction_options->keyframe2 = context->keyframe2;
-
- reconstruction_options->refine_intrinsics = context->refine_flags;
-}
-
-/* Solve camera/object motion and reconstruct 3D markers position
- * from a prepared reconstruction context.
- *
- * stop is not actually used at this moment, so reconstruction
- * job could not be stopped.
- *
- * do_update, progress and stat_message are set by reconstruction
- * callback in libmv side and passing to an interface.
- */
-void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *stop, short *do_update,
- float *progress, char *stats_message, int message_size)
-{
- float error;
-
- ReconstructProgressData progressdata;
-
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- libmv_ReconstructionOptions reconstruction_options;
-
- progressdata.stop = stop;
- progressdata.do_update = do_update;
- progressdata.progress = progress;
- progressdata.stats_message = stats_message;
- progressdata.message_size = message_size;
-
- camraIntrincicsOptionsFromContext(&camera_intrinsics_options, context);
- reconstructionOptionsFromContext(&reconstruction_options, context);
-
- if (context->motion_flag & TRACKING_MOTION_MODAL) {
- context->reconstruction = libmv_solveModal(context->tracks,
- &camera_intrinsics_options,
- &reconstruction_options,
- reconstruct_update_solve_cb, &progressdata);
- }
- else {
- context->reconstruction = libmv_solveReconstruction(context->tracks,
- &camera_intrinsics_options,
- &reconstruction_options,
- reconstruct_update_solve_cb, &progressdata);
-
- if (context->select_keyframes) {
- /* store actual keyframes used for reconstruction to update them in the interface later */
- context->keyframe1 = reconstruction_options.keyframe1;
- context->keyframe2 = reconstruction_options.keyframe2;
- }
- }
-
- error = libmv_reprojectionError(context->reconstruction);
-
- context->reprojection_error = error;
-}
-
-/* Finish reconstruction process by copying reconstructed data
- * to an actual movie clip datablock.
- */
-bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
-{
- MovieTrackingReconstruction *reconstruction;
- MovieTrackingObject *object;
-
- tracks_map_merge(context->tracks_map, tracking);
- BKE_tracking_dopesheet_tag_update(tracking);
-
- object = BKE_tracking_object_get_named(tracking, context->object_name);
-
- if (context->is_camera)
- reconstruction = &tracking->reconstruction;
- else
- reconstruction = &object->reconstruction;
-
- /* update keyframe in the interface */
- if (context->select_keyframes) {
- object->keyframe1 = context->keyframe1;
- object->keyframe2 = context->keyframe2;
- }
-
- reconstruction->error = context->reprojection_error;
- reconstruction->flag |= TRACKING_RECONSTRUCTED;
-
- if (!reconstruct_retrieve_libmv(context, tracking))
- return false;
-
- return true;
-}
-
-static void tracking_scale_reconstruction(ListBase *tracksbase, MovieTrackingReconstruction *reconstruction,
- float scale[3])
-{
- MovieTrackingTrack *track;
- int i;
- float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
-
- if (reconstruction->camnr > 0) {
- mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
- }
-
- for (i = 0; i < reconstruction->camnr; i++) {
- MovieReconstructedCamera *camera = &reconstruction->cameras[i];
- mul_v3_v3(camera->mat[3], scale);
- sub_v3_v3(camera->mat[3], first_camera_delta);
- }
-
- for (track = tracksbase->first; track; track = track->next) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- mul_v3_v3(track->bundle_pos, scale);
- sub_v3_v3(track->bundle_pos, first_camera_delta);
- }
- }
-}
-
-/* Apply scale on all reconstructed cameras and bundles,
- * used by camera scale apply operator.
- */
-void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
-{
- MovieTrackingObject *object;
-
- for (object = tracking->objects.first; object; object = object->next) {
- ListBase *tracksbase;
- MovieTrackingReconstruction *reconstruction;
-
- tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
-
- tracking_scale_reconstruction(tracksbase, reconstruction, scale);
- }
-}
-
-/*********************** Feature detection *************************/
-
-/* Check whether point is inside grease pencil stroke. */
-static bool check_point_in_stroke(bGPDstroke *stroke, float x, float y)
-{
- int i, prev;
- int count = 0;
- bGPDspoint *points = stroke->points;
-
- /* Count intersections of horizontal ray coming from the point.
- * Point will be inside layer if and only if number of intersection
- * is uneven.
- *
- * Well, if layer has got self-intersections, this logic wouldn't
- * work, but such situation is crappy anyway.
- */
-
- prev = stroke->totpoints - 1;
-
- for (i = 0; i < stroke->totpoints; i++) {
- if ((points[i].y < y && points[prev].y >= y) || (points[prev].y < y && points[i].y >= y)) {
- float fac = (y - points[i].y) / (points[prev].y - points[i].y);
-
- if (points[i].x + fac * (points[prev].x - points[i].x) < x)
- count++;
- }
-
- prev = i;
- }
-
- return (count % 2) ? true : false;
-}
-
-/* Check whether point is inside any stroke of grease pencil layer. */
-static bool check_point_in_layer(bGPDlayer *layer, float x, float y)
-{
- bGPDframe *frame = layer->frames.first;
-
- while (frame) {
- bGPDstroke *stroke = frame->strokes.first;
-
- while (stroke) {
- if (check_point_in_stroke(stroke, x, y))
- return true;
-
- stroke = stroke->next;
- }
- frame = frame->next;
- }
-
- return false;
-}
-
-/* Get features detected by libmv and create tracks on the clip for them. */
-static void detect_retrieve_libmv_features(MovieTracking *tracking, ListBase *tracksbase,
- struct libmv_Features *features, int framenr, int width, int height,
- bGPDlayer *layer, bool place_outside_layer)
-{
- int a;
-
- a = libmv_countFeatures(features);
- while (a--) {
- MovieTrackingTrack *track;
- double x, y, size, score;
- bool ok = true;
- float xu, yu;
-
- libmv_getFeature(features, a, &x, &y, &score, &size);
-
- xu = x / width;
- yu = y / height;
-
- if (layer)
- ok = check_point_in_layer(layer, xu, yu) != place_outside_layer;
-
- if (ok) {
- track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height);
- track->flag |= SELECT;
- track->pat_flag |= SELECT;
- track->search_flag |= SELECT;
- }
- }
-}
-
-/* Get a gray-scale unsigned char buffer from given image buffer
- * wich will be used for feature detection.
- */
-static unsigned char *detect_get_frame_ucharbuf(ImBuf *ibuf)
-{
- int x, y;
- unsigned char *pixels, *cp;
-
- cp = pixels = MEM_callocN(ibuf->x * ibuf->y * sizeof(unsigned char), "tracking ucharBuf");
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- int pixel = ibuf->x * y + x;
-
- if (ibuf->rect_float) {
- const float *rrgbf = ibuf->rect_float + pixel * 4;
- const float gray_f = 0.2126f * rrgbf[0] + 0.7152f * rrgbf[1] + 0.0722f * rrgbf[2];
-
- *cp = FTOCHAR(gray_f);
- }
- else {
- const unsigned char *rrgb = (unsigned char *)ibuf->rect + pixel * 4;
-
- *cp = 0.2126f * rrgb[0] + 0.7152f * rrgb[1] + 0.0722f * rrgb[2];
- }
-
- cp++;
- }
- }
-
- return pixels;
-}
-
-/* Detect features using FAST detector */
-void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
- int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer,
- bool place_outside_layer)
-{
- struct libmv_Features *features;
- unsigned char *pixels = detect_get_frame_ucharbuf(ibuf);
-
- features = libmv_detectFeaturesFAST(pixels, ibuf->x, ibuf->y, ibuf->x,
- margin, min_trackness, min_distance);
-
- MEM_freeN(pixels);
-
- detect_retrieve_libmv_features(tracking, tracksbase, features,
- framenr, ibuf->x, ibuf->y, layer,
- place_outside_layer);
-
- libmv_featuresDestroy(features);
-}
-
-/*********************** 2D stabilization *************************/
-
-/* Calculate median point of markers of tracks marked as used for
- * 2D stabilization.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
-static bool stabilization_median_point_get(MovieTracking *tracking, int framenr, float median[2])
-{
- bool ok = false;
- float min[2], max[2];
- MovieTrackingTrack *track;
-
- INIT_MINMAX2(min, max);
-
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- minmax_v2v2_v2(min, max, marker->pos);
-
- ok = true;
- }
-
- track = track->next;
- }
-
- median[0] = (max[0] + min[0]) / 2.0f;
- median[1] = (max[1] + min[1]) / 2.0f;
-
- return ok;
-}
-
-/* Calculate stabilization data (translation, scale and rotation) from
- * given median of first and current frame medians, tracking data and
- * frame number.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
-static void stabilization_calculate_data(MovieTracking *tracking, int framenr, int width, int height,
- float firstmedian[2], float median[2],
- float translation[2], float *scale, float *angle)
-{
- MovieTrackingStabilization *stab = &tracking->stabilization;
-
- *scale = (stab->scale - 1.0f) * stab->scaleinf + 1.0f;
- *angle = 0.0f;
-
- translation[0] = (firstmedian[0] - median[0]) * width * (*scale);
- translation[1] = (firstmedian[1] - median[1]) * height * (*scale);
-
- mul_v2_fl(translation, stab->locinf);
-
- if ((stab->flag & TRACKING_STABILIZE_ROTATION) && stab->rot_track && stab->rotinf) {
- MovieTrackingMarker *marker;
- float a[2], b[2];
- float x0 = (float)width / 2.0f, y0 = (float)height / 2.0f;
- float x = median[0] * width, y = median[1] * height;
-
- marker = BKE_tracking_marker_get(stab->rot_track, 1);
- sub_v2_v2v2(a, marker->pos, firstmedian);
- a[0] *= width;
- a[1] *= height;
-
- marker = BKE_tracking_marker_get(stab->rot_track, framenr);
- sub_v2_v2v2(b, marker->pos, median);
- b[0] *= width;
- b[1] *= height;
-
- *angle = -atan2f(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]);
- *angle *= stab->rotinf;
-
- /* convert to rotation around image center */
- translation[0] -= (x0 + (x - x0) * cosf(*angle) - (y - y0) * sinf(*angle) - x) * (*scale);
- translation[1] -= (y0 + (x - x0) * sinf(*angle) + (y - y0) * cosf(*angle) - y) * (*scale);
- }
-}
-
-/* Calculate factor of a scale, which will eliminate black areas
- * appearing on the frame caused by frame translation.
- */
-static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, int width, int height)
-{
- float firstmedian[2];
- MovieTrackingStabilization *stab = &tracking->stabilization;
- float aspect = tracking->camera.pixel_aspect;
-
- /* Early output if stabilization data is already up-to-date. */
- if (stab->ok)
- return stab->scale;
-
- /* See comment in BKE_tracking_stabilization_data_get about first frame. */
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- int sfra = INT_MAX, efra = INT_MIN, cfra;
- float scale = 1.0f;
- MovieTrackingTrack *track;
-
- stab->scale = 1.0f;
-
- /* Calculate frame range of tracks used for stabilization. */
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB ||
- ((stab->flag & TRACKING_STABILIZE_ROTATION) && track == stab->rot_track))
- {
- sfra = min_ii(sfra, track->markers[0].framenr);
- efra = max_ii(efra, track->markers[track->markersnr - 1].framenr);
- }
-
- track = track->next;
- }
-
- /* For every frame we calculate scale factor needed to eliminate black
- * aread and choose largest scale factor as final one.
- */
- for (cfra = sfra; cfra <= efra; cfra++) {
- float median[2];
- float translation[2], angle, tmp_scale;
- int i;
- float mat[4][4];
- float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}};
- float si, co;
-
- stabilization_median_point_get(tracking, cfra, median);
-
- stabilization_calculate_data(tracking, cfra, width, height, firstmedian, median, translation, &tmp_scale, &angle);
-
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, 1.0f, angle, mat);
-
- si = sinf(angle);
- co = cosf(angle);
-
- for (i = 0; i < 4; i++) {
- int j;
- float a[3] = {0.0f, 0.0f, 0.0f}, b[3] = {0.0f, 0.0f, 0.0f};
-
- copy_v3_v3(a, points[i]);
- copy_v3_v3(b, points[(i + 1) % 4]);
-
- mul_m4_v3(mat, a);
- mul_m4_v3(mat, b);
-
- for (j = 0; j < 4; j++) {
- float point[3] = {points[j][0], points[j][1], 0.0f};
- float v1[3], v2[3];
-
- sub_v3_v3v3(v1, b, a);
- sub_v3_v3v3(v2, point, a);
-
- if (cross_v2v2(v1, v2) >= 0.0f) {
- const float rotDx[4][2] = {{1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}, {0.0f, 1.0f}};
- const float rotDy[4][2] = {{0.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}};
-
- float dx = translation[0] * rotDx[j][0] + translation[1] * rotDx[j][1],
- dy = translation[0] * rotDy[j][0] + translation[1] * rotDy[j][1];
-
- float w, h, E, F, G, H, I, J, K, S;
-
- if (j % 2) {
- w = (float)height / 2.0f;
- h = (float)width / 2.0f;
- }
- else {
- w = (float)width / 2.0f;
- h = (float)height / 2.0f;
- }
-
- E = -w * co + h * si;
- F = -h * co - w * si;
-
- if ((i % 2) == (j % 2)) {
- G = -w * co - h * si;
- H = h * co - w * si;
- }
- else {
- G = w * co + h * si;
- H = -h * co + w * si;
- }
-
- I = F - H;
- J = G - E;
- K = G * F - E * H;
-
- S = (-w * I - h * J) / (dx * I + dy * J + K);
-
- scale = max_ff(scale, S);
- }
- }
- }
- }
-
- stab->scale = scale;
-
- if (stab->maxscale > 0.0f)
- stab->scale = min_ff(stab->scale, stab->maxscale);
- }
- else {
- stab->scale = 1.0f;
- }
-
- stab->ok = TRUE;
-
- return stab->scale;
-}
-
-/* Get stabilization data (translation, scaling and angle) for a given frame.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
-void BKE_tracking_stabilization_data_get(MovieTracking *tracking, int framenr, int width, int height,
- float translation[2], float *scale, float *angle)
-{
- float firstmedian[2], median[2];
- MovieTrackingStabilization *stab = &tracking->stabilization;
-
- /* Early output if stabilization is disabled. */
- if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- zero_v2(translation);
- *scale = 1.0f;
- *angle = 0.0f;
-
- return;
- }
-
- /* Even if tracks does not start at frame 1, their position will
- * be estimated at this frame, which will give reasonable result
- * in most of cases.
- *
- * However, it's still better to replace this with real first
- * frame number at which tracks are appearing.
- */
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- stabilization_median_point_get(tracking, framenr, median);
-
- if ((stab->flag & TRACKING_AUTOSCALE) == 0)
- stab->scale = 1.0f;
-
- if (!stab->ok) {
- if (stab->flag & TRACKING_AUTOSCALE)
- stabilization_calculate_autoscale_factor(tracking, width, height);
-
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
-
- stab->ok = TRUE;
- }
- else {
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
- }
- }
- else {
- zero_v2(translation);
- *scale = 1.0f;
- *angle = 0.0f;
- }
-}
-
-/* Stabilize given image buffer using stabilization data for
- * a specified frame number.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
-ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf *ibuf,
- float translation[2], float *scale, float *angle)
-{
- float tloc[2], tscale, tangle;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- ImBuf *tmpibuf;
- int width = ibuf->x, height = ibuf->y;
- float aspect = tracking->camera.pixel_aspect;
- float mat[4][4];
- int j, filter = tracking->stabilization.filter;
- void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL;
- int ibuf_flags;
-
- if (translation)
- copy_v2_v2(tloc, translation);
-
- if (scale)
- tscale = *scale;
-
- /* Perform early output if no stabilization is used. */
- if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- if (translation)
- zero_v2(translation);
-
- if (scale)
- *scale = 1.0f;
-
- if (angle)
- *angle = 0.0f;
-
- return ibuf;
- }
-
- /* Allocate frame for stabilization result. */
- ibuf_flags = 0;
- if (ibuf->rect)
- ibuf_flags |= IB_rect;
- if (ibuf->rect_float)
- ibuf_flags |= IB_rectfloat;
-
- tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
-
- /* Calculate stabilization matrix. */
- BKE_tracking_stabilization_data_get(tracking, framenr, width, height, tloc, &tscale, &tangle);
- BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat);
- invert_m4(mat);
-
- if (filter == TRACKING_FILTER_NEAREST)
- interpolation = nearest_interpolation;
- else if (filter == TRACKING_FILTER_BILINEAR)
- interpolation = bilinear_interpolation;
- else if (filter == TRACKING_FILTER_BICUBIC)
- interpolation = bicubic_interpolation;
- else
- /* fallback to default interpolation method */
- interpolation = nearest_interpolation;
-
- /* This function is only used for display in clip editor and
- * sequencer only, which would only benefit of using threads
- * here.
- *
- * But need to keep an eye on this if the function will be
- * used in other cases.
- */
-#pragma omp parallel for if (tmpibuf->y > 128)
- for (j = 0; j < tmpibuf->y; j++) {
- int i;
- for (i = 0; i < tmpibuf->x; i++) {
- float vec[3] = {i, j, 0.0f};
-
- mul_v3_m4v3(vec, mat, vec);
-
- interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
- }
- }
-
- if (tmpibuf->rect_float)
- tmpibuf->userflags |= IB_RECT_INVALID;
-
- if (translation)
- copy_v2_v2(translation, tloc);
-
- if (scale)
- *scale = tscale;
-
- if (angle)
- *angle = tangle;
-
- return tmpibuf;
-}
-
-/* Get 4x4 transformation matrix which corresponds to
- * stabilization data and used for easy coordinate
- * transformation.
- *
- * NOTE: The reason it is 4x4 matrix is because it's
- * used for OpenGL drawing directly.
- */
-void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect,
- float translation[2], float scale, float angle,
- float mat[4][4])
-{
- float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
- center_mat[4][4], inv_center_mat[4][4],
- aspect_mat[4][4], inv_aspect_mat[4][4];
- float scale_vector[3] = {scale, scale, scale};
-
- unit_m4(translation_mat);
- unit_m4(rotation_mat);
- unit_m4(scale_mat);
- unit_m4(center_mat);
- unit_m4(aspect_mat);
-
- /* aspect ratio correction matrix */
- aspect_mat[0][0] = 1.0f / aspect;
- invert_m4_m4(inv_aspect_mat, aspect_mat);
-
- /* image center as rotation center
- *
- * Rotation matrix is constructing in a way rotaion happens around image center,
- * and it's matter of calculating trasnlation in a way, that applying translation
- * after rotation would make it so rotation happens around median point of tracks
- * used for translation stabilization.
- */
- center_mat[3][0] = (float)width / 2.0f;
- center_mat[3][1] = (float)height / 2.0f;
- invert_m4_m4(inv_center_mat, center_mat);
-
- size_to_mat4(scale_mat, scale_vector); /* scale matrix */
- add_v2_v2(translation_mat[3], translation); /* translation matrix */
- rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
-
- /* compose transformation matrix */
- mul_serie_m4(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat,
- scale_mat, inv_center_mat, NULL);
-}
-
/*********************** Dopesheet functions *************************/
/* ** Channels sort comparators ** */