1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2011 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include "atomic_ops.h"
25 #include <stdlib.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_movieclip_types.h"
30 #include "DNA_object_types.h" /* SELECT */
31
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_task.h"
35 #include "BLI_threads.h"
36 #include "BLI_utildefines.h"
37
38 #include "BKE_movieclip.h"
39 #include "BKE_tracking.h"
40
41 #include "libmv-capi.h"
42 #include "tracking_private.h"
43
44 typedef struct AutoTrackOptions {
45 int clip_index; /** Index of the clip this track belongs to. */
46 int track_index; /* Index of the track in AutoTrack tracks structure. */
47 MovieTrackingTrack *track; /* Pointer to an original track/ */
48 libmv_TrackRegionOptions track_region_options; /* Options for the region tracker. */
49 bool use_keyframe_match; /* Keyframe pattern matching. */
50
51 /* TODO(sergey): A bit awkward to keep it in here, only used to
52 * place a disabled marker once the tracking fails,
53 * Either find a clearer way to do it or call it track context
54 * or state, not options.
55 */
56 bool is_failed;
57 int failed_frame;
58 } AutoTrackOptions;
59
60 typedef struct AutoTrackContext {
61 MovieClip *clips[MAX_ACCESSOR_CLIP];
62 int num_clips;
63
64 MovieClipUser user;
65 int frame_width, frame_height;
66
67 struct libmv_AutoTrack *autotrack;
68 TrackingImageAccessor *image_accessor;
69
70 int num_tracks; /* Number of tracks being tracked. */
71 AutoTrackOptions *options; /* Per-tracking track options. */
72
73 /* Array of all tracks, indexed by track_index. */
74 MovieTrackingTrack **tracks;
75
76 bool backwards;
77 bool sequence;
78 int first_frame;
79 int sync_frame;
80 bool first_sync;
81 SpinLock spin_lock;
82
83 bool step_ok;
84 } AutoTrackContext;
85
normalized_to_libmv_frame(const float normalized[2],const int frame_dimensions[2],float result[2])86 static void normalized_to_libmv_frame(const float normalized[2],
87 const int frame_dimensions[2],
88 float result[2])
89 {
90 result[0] = normalized[0] * frame_dimensions[0] - 0.5f;
91 result[1] = normalized[1] * frame_dimensions[1] - 0.5f;
92 }
93
normalized_relative_to_libmv_frame(const float normalized[2],const float origin[2],const int frame_dimensions[2],float result[2])94 static void normalized_relative_to_libmv_frame(const float normalized[2],
95 const float origin[2],
96 const int frame_dimensions[2],
97 float result[2])
98 {
99 result[0] = (normalized[0] + origin[0]) * frame_dimensions[0] - 0.5f;
100 result[1] = (normalized[1] + origin[1]) * frame_dimensions[1] - 0.5f;
101 }
102
libmv_frame_to_normalized(const float frame_coord[2],const int frame_dimensions[2],float result[2])103 static void libmv_frame_to_normalized(const float frame_coord[2],
104 const int frame_dimensions[2],
105 float result[2])
106 {
107 result[0] = (frame_coord[0] + 0.5f) / frame_dimensions[0];
108 result[1] = (frame_coord[1] + 0.5f) / frame_dimensions[1];
109 }
110
libmv_frame_to_normalized_relative(const float frame_coord[2],const float origin[2],const int frame_dimensions[2],float result[2])111 static void libmv_frame_to_normalized_relative(const float frame_coord[2],
112 const float origin[2],
113 const int frame_dimensions[2],
114 float result[2])
115 {
116 result[0] = (frame_coord[0] - origin[0]) / frame_dimensions[0];
117 result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1];
118 }
119
dna_marker_to_libmv_marker(MovieTrackingTrack * track,MovieTrackingMarker * marker,int clip,int track_index,int frame_width,int frame_height,bool backwards,libmv_Marker * libmv_marker)120 static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
121 /*const*/ MovieTrackingMarker *marker,
122 int clip,
123 int track_index,
124 int frame_width,
125 int frame_height,
126 bool backwards,
127 libmv_Marker *libmv_marker)
128 {
129 const int frame_dimensions[2] = {frame_width, frame_height};
130 libmv_marker->clip = clip;
131 libmv_marker->frame = marker->framenr;
132 libmv_marker->track = track_index;
133
134 normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
135 for (int i = 0; i < 4; i++) {
136 normalized_relative_to_libmv_frame(
137 marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
138 }
139
140 normalized_relative_to_libmv_frame(
141 marker->search_min, marker->pos, frame_dimensions, libmv_marker->search_region_min);
142
143 normalized_relative_to_libmv_frame(
144 marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max);
145
146 /* TODO(sergey): All the markers does have 1.0 weight. */
147 libmv_marker->weight = 1.0f;
148
149 if (marker->flag & MARKER_TRACKED) {
150 libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
151 }
152 else {
153 libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
154 }
155 libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
156 libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
157 libmv_marker->model_id = 0;
158
159 /* TODO(sergey): We currently don't support reference marker from
160 * different clip.
161 */
162 libmv_marker->reference_clip = clip;
163
164 if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
165 MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker(
166 track, marker->framenr, backwards);
167 libmv_marker->reference_frame = keyframe_marker->framenr;
168 }
169 else {
170 libmv_marker->reference_frame = backwards ? marker->framenr - 1 : marker->framenr;
171 }
172
173 libmv_marker->disabled_channels =
174 ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
175 ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
176 ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
177 }
178
libmv_marker_to_dna_marker(libmv_Marker * libmv_marker,int frame_width,int frame_height,MovieTrackingMarker * marker)179 static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
180 int frame_width,
181 int frame_height,
182 MovieTrackingMarker *marker)
183 {
184 const int frame_dimensions[2] = {frame_width, frame_height};
185 marker->framenr = libmv_marker->frame;
186
187 libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
188 for (int i = 0; i < 4; i++) {
189 libmv_frame_to_normalized_relative(libmv_marker->patch[i],
190 libmv_marker->center,
191 frame_dimensions,
192 marker->pattern_corners[i]);
193 }
194
195 libmv_frame_to_normalized_relative(
196 libmv_marker->search_region_min, libmv_marker->center, frame_dimensions, marker->search_min);
197
198 libmv_frame_to_normalized_relative(
199 libmv_marker->search_region_max, libmv_marker->center, frame_dimensions, marker->search_max);
200
201 marker->flag = 0;
202 if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
203 marker->flag |= MARKER_TRACKED;
204 }
205 else {
206 marker->flag &= ~MARKER_TRACKED;
207 }
208 }
209
check_track_trackable(const MovieClip * clip,MovieTrackingTrack * track,const MovieClipUser * user)210 static bool check_track_trackable(const MovieClip *clip,
211 MovieTrackingTrack *track,
212 const MovieClipUser *user)
213 {
214 if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) {
215 int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
216 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
217 return (marker->flag & MARKER_DISABLED) == 0;
218 }
219 return false;
220 }
221
222 /* Returns false if marker crossed margin area from frame bounds. */
tracking_check_marker_margin(libmv_Marker * libmv_marker,int margin,int frame_width,int frame_height)223 static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
224 int margin,
225 int frame_width,
226 int frame_height)
227 {
228 float patch_min[2], patch_max[2];
229 float margin_left, margin_top, margin_right, margin_bottom;
230
231 INIT_MINMAX2(patch_min, patch_max);
232 minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
233 minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
234 minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
235 minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
236
237 margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
238 margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
239 margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
240 margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
241
242 if (libmv_marker->center[0] < margin_left ||
243 libmv_marker->center[0] > frame_width - margin_right ||
244 libmv_marker->center[1] < margin_bottom ||
245 libmv_marker->center[1] > frame_height - margin_top) {
246 return false;
247 }
248
249 return true;
250 }
251
252 /* Provide Libmv side of auto track all information about given tracks. */
fill_autotrack_tracks(const int frame_width,const int frame_height,const ListBase * tracksbase,const bool backwards,struct libmv_AutoTrack * autotrack)253 static void fill_autotrack_tracks(const int frame_width,
254 const int frame_height,
255 const ListBase *tracksbase,
256 const bool backwards,
257 struct libmv_AutoTrack *autotrack)
258 {
259 /* Count number of markers to be put to a context. */
260 size_t num_trackable_markers = 0;
261 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
262 for (int i = 0; i < track->markersnr; i++) {
263 const MovieTrackingMarker *marker = track->markers + i;
264 if ((marker->flag & MARKER_DISABLED) == 0) {
265 num_trackable_markers++;
266 }
267 }
268 }
269 /* Early output if we don't have any markers. */
270 if (num_trackable_markers == 0) {
271 return;
272 }
273 /* Allocate memory for all the markers. */
274 libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers,
275 "libmv markers array");
276 /* Fill in markers array. */
277 int track_index = 0, num_filled_libmv_markers = 0;
278 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
279 for (int i = 0; i < track->markersnr; i++) {
280 MovieTrackingMarker *marker = track->markers + i;
281 if ((marker->flag & MARKER_DISABLED) != 0) {
282 continue;
283 }
284 dna_marker_to_libmv_marker(track,
285 marker,
286 0,
287 track_index,
288 frame_width,
289 frame_height,
290 backwards,
291 &libmv_markers[num_filled_libmv_markers++]);
292 }
293 /* Put all markers to autotrack at once. */
294 track_index++;
295 }
296 /* Add all markers to autotrack. */
297 libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers);
298 /* Free temporary memory. */
299 MEM_freeN(libmv_markers);
300 }
301
create_per_track_tracking_options(const MovieClip * clip,const MovieClipUser * user,const ListBase * tracksbase,AutoTrackContext * context)302 static void create_per_track_tracking_options(const MovieClip *clip,
303 const MovieClipUser *user,
304 const ListBase *tracksbase,
305 AutoTrackContext *context)
306 {
307 /* Count number of trackable tracks. */
308 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
309 if (check_track_trackable(clip, track, user)) {
310 context->num_tracks++;
311 }
312 }
313 /* Allocate required memory. */
314 context->options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
315 "auto track options");
316 /* Fill in all the settings. */
317 int i = 0, track_index = 0;
318 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
319 if (!check_track_trackable(clip, track, user)) {
320 track_index++;
321 continue;
322 }
323 AutoTrackOptions *options = &context->options[i++];
324 /* TODO(sergey): Single clip only for now. */
325 options->clip_index = 0;
326 options->track_index = track_index;
327 options->track = track;
328 tracking_configure_tracker(track, NULL, &options->track_region_options);
329 options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
330 context->tracks[track_index] = track;
331 track_index++;
332 }
333 }
334
BKE_autotrack_context_new(MovieClip * clip,MovieClipUser * user,const bool backwards,const bool sequence)335 AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
336 MovieClipUser *user,
337 const bool backwards,
338 const bool sequence)
339 {
340 AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context");
341 MovieTracking *tracking = &clip->tracking;
342 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
343 int frame_width, frame_height;
344 /* get size of frame to convert normalized coordinates to a picture ones. */
345 BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
346 /* TODO(sergey): Currently using only a single clip. */
347 context->clips[0] = clip;
348 context->num_clips = 1;
349 context->user = *user;
350 context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
351 context->user.render_flag = 0;
352 context->frame_width = frame_width;
353 context->frame_height = frame_height;
354 context->backwards = backwards;
355 context->sequence = sequence;
356 context->first_frame = user->framenr;
357 context->sync_frame = user->framenr;
358 context->first_sync = true;
359 BLI_spin_init(&context->spin_lock);
360 const int num_total_tracks = BLI_listbase_count(tracksbase);
361 context->tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
362 "auto track pointers");
363 /* Initialize image accessor. */
364 context->image_accessor = tracking_image_accessor_new(
365 context->clips, 1, context->tracks, num_total_tracks, user->framenr);
366 /* Initialize auto track context and provide all information about currently
367 * tracked markers.
368 */
369 context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor);
370 fill_autotrack_tracks(frame_width, frame_height, tracksbase, backwards, context->autotrack);
371 /* Create per-track tracking options. */
372 create_per_track_tracking_options(clip, user, tracksbase, context);
373 return context;
374 }
375
autotrack_context_step_cb(void * __restrict userdata,const int track,const TaskParallelTLS * __restrict UNUSED (tls))376 static void autotrack_context_step_cb(void *__restrict userdata,
377 const int track,
378 const TaskParallelTLS *__restrict UNUSED(tls))
379 {
380 AutoTrackContext *context = userdata;
381 const int frame_delta = context->backwards ? -1 : 1;
382
383 AutoTrackOptions *options = &context->options[track];
384 if (options->is_failed) {
385 return;
386 }
387 libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker;
388 libmv_TrackRegionResult libmv_result;
389 const int frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[options->clip_index],
390 context->user.framenr);
391 BLI_spin_lock(&context->spin_lock);
392 const bool has_marker = libmv_autoTrackGetMarker(
393 context->autotrack, options->clip_index, frame, options->track_index, &libmv_current_marker);
394 BLI_spin_unlock(&context->spin_lock);
395 /* Check whether we've got marker to sync with. */
396 if (!has_marker) {
397 return;
398 }
399 /* Check whether marker is going outside of allowed frame margin. */
400 if (!tracking_check_marker_margin(&libmv_current_marker,
401 options->track->margin,
402 context->frame_width,
403 context->frame_height)) {
404 return;
405 }
406 libmv_tracked_marker = libmv_current_marker;
407 libmv_tracked_marker.frame = frame + frame_delta;
408 /* Update reference frame. */
409 if (options->use_keyframe_match) {
410 libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame;
411 libmv_autoTrackGetMarker(context->autotrack,
412 options->clip_index,
413 libmv_tracked_marker.reference_frame,
414 options->track_index,
415 &libmv_reference_marker);
416 }
417 else {
418 libmv_tracked_marker.reference_frame = frame;
419 libmv_reference_marker = libmv_current_marker;
420 }
421 /* Perform actual tracking. */
422 if (libmv_autoTrackMarker(context->autotrack,
423 &options->track_region_options,
424 &libmv_tracked_marker,
425 &libmv_result)) {
426 BLI_spin_lock(&context->spin_lock);
427 libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
428 BLI_spin_unlock(&context->spin_lock);
429 }
430 else {
431 options->is_failed = true;
432 options->failed_frame = frame + frame_delta;
433 }
434
435 /* Note: Atomic is probably not actually needed here, I doubt we could get
436 * any other result than a true bool anyway.
437 * But for sake of consistency, and since it costs nothing...
438 */
439 atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true);
440 }
441
BKE_autotrack_context_step(AutoTrackContext * context)442 bool BKE_autotrack_context_step(AutoTrackContext *context)
443 {
444 const int frame_delta = context->backwards ? -1 : 1;
445 context->step_ok = false;
446
447 TaskParallelSettings settings;
448 BLI_parallel_range_settings_defaults(&settings);
449 settings.use_threading = (context->num_tracks > 1);
450 BLI_task_parallel_range(0, context->num_tracks, context, autotrack_context_step_cb, &settings);
451
452 /* Advance the frame. */
453 BLI_spin_lock(&context->spin_lock);
454 context->user.framenr += frame_delta;
455 BLI_spin_unlock(&context->spin_lock);
456 return context->step_ok;
457 }
458
BKE_autotrack_context_sync(AutoTrackContext * context)459 void BKE_autotrack_context_sync(AutoTrackContext *context)
460 {
461 int newframe, frame_delta = context->backwards ? -1 : 1;
462
463 BLI_spin_lock(&context->spin_lock);
464 newframe = context->user.framenr;
465 for (int frame = context->sync_frame;
466 frame != (context->backwards ? newframe - 1 : newframe + 1);
467 frame += frame_delta) {
468 MovieTrackingMarker marker;
469 libmv_Marker libmv_marker;
470 int clip = 0;
471 for (int track = 0; track < context->num_tracks; track++) {
472 AutoTrackOptions *options = &context->options[track];
473 int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
474 context->clips[options->clip_index], frame);
475 if (options->is_failed) {
476 if (options->failed_frame == track_frame) {
477 MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact(
478 options->track, context->backwards ? frame + 1 : frame - 1);
479 if (prev_marker) {
480 marker = *prev_marker;
481 marker.framenr = track_frame;
482 marker.flag |= MARKER_DISABLED;
483 BKE_tracking_marker_insert(options->track, &marker);
484 continue;
485 }
486 }
487 if ((context->backwards && options->failed_frame > track_frame) ||
488 (!context->backwards && options->failed_frame < track_frame)) {
489 continue;
490 }
491 }
492 if (libmv_autoTrackGetMarker(
493 context->autotrack, clip, track_frame, options->track_index, &libmv_marker)) {
494 libmv_marker_to_dna_marker(
495 &libmv_marker, context->frame_width, context->frame_height, &marker);
496 if (context->first_sync && frame == context->sync_frame) {
497 tracking_marker_insert_disabled(options->track, &marker, !context->backwards, false);
498 }
499 BKE_tracking_marker_insert(options->track, &marker);
500 tracking_marker_insert_disabled(options->track, &marker, context->backwards, false);
501 }
502 }
503 }
504 BLI_spin_unlock(&context->spin_lock);
505
506 for (int clip = 0; clip < context->num_clips; clip++) {
507 MovieTracking *tracking = &context->clips[clip]->tracking;
508 BKE_tracking_dopesheet_tag_update(tracking);
509 }
510
511 context->sync_frame = newframe;
512 context->first_sync = false;
513 }
514
BKE_autotrack_context_sync_user(AutoTrackContext * context,MovieClipUser * user)515 void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
516 {
517 user->framenr = context->sync_frame;
518 }
519
BKE_autotrack_context_finish(AutoTrackContext * context)520 void BKE_autotrack_context_finish(AutoTrackContext *context)
521 {
522 for (int clip_index = 0; clip_index < context->num_clips; clip_index++) {
523 MovieClip *clip = context->clips[clip_index];
524 ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
525
526 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
527 if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
528 for (int track = 0; track < context->num_tracks; track++) {
529 if (BKE_tracking_plane_track_has_point_track(plane_track,
530 context->options[track].track)) {
531 BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
532 break;
533 }
534 }
535 }
536 }
537 }
538 }
539
BKE_autotrack_context_free(AutoTrackContext * context)540 void BKE_autotrack_context_free(AutoTrackContext *context)
541 {
542 libmv_autoTrackDestroy(context->autotrack);
543 tracking_image_accessor_destroy(context->image_accessor);
544 MEM_freeN(context->options);
545 MEM_freeN(context->tracks);
546 BLI_spin_end(&context->spin_lock);
547 MEM_freeN(context);
548 }
549