Blender  V3.3
tracking_stabilize.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. All rights reserved. */
3 
10 #include <limits.h>
11 
12 #include "DNA_anim_types.h"
13 #include "DNA_movieclip_types.h"
14 #include "DNA_scene_types.h"
15 #include "RNA_access.h"
16 #include "RNA_prototypes.h"
17 
18 #include "BLI_ghash.h"
19 #include "BLI_listbase.h"
20 #include "BLI_math.h"
21 #include "BLI_math_vector.h"
22 #include "BLI_sort_utils.h"
23 #include "BLI_task.h"
24 #include "BLI_utildefines.h"
25 
26 #include "BKE_fcurve.h"
27 #include "BKE_movieclip.h"
28 #include "BKE_tracking.h"
29 
30 #include "IMB_colormanagement.h"
31 #include "IMB_imbuf.h"
32 #include "IMB_imbuf_types.h"
33 #include "MEM_guardedalloc.h"
34 
35 /* == Parameterization constants == */
36 
37 /* When measuring the scale changes relative to the rotation pivot point, it
38  * might happen accidentally that a probe point (tracking point), which doesn't
39  * actually move on a circular path, gets very close to the pivot point, causing
40  * the measured scale contribution to go toward infinity. We damp this undesired
41  * effect by adding a bias (floor) to the measured distances, which will
42  * dominate very small distances and thus cause the corresponding track's
43  * contribution to diminish.
44  * Measurements happen in normalized (0...1) coordinates within a frame.
45  */
46 static float SCALE_ERROR_LIMIT_BIAS = 0.01f;
47 
48 /* When to consider a track as completely faded out.
49  * This is used in conjunction with the "disabled" flag of the track
50  * to determine start positions, end positions and gaps
51  */
52 static float EPSILON_WEIGHT = 0.005f;
53 
54 /* == private working data == */
55 
56 /* Per track baseline for stabilization, defined at reference frame.
57  * A track's reference frame is chosen as close as possible to the (global)
58  * anchor_frame. Baseline holds the constant part of each track's contribution
59  * to the observed movement; it is calculated at initialization pass, using the
60  * measurement value at reference frame plus the average contribution to fill
61  * the gap between global anchor_frame and the reference frame for this track.
62  * This struct with private working data is associated to the local call context
63  * via `StabContext::private_track_data`
64  */
65 typedef struct TrackStabilizationBase {
67 
68  /* measured relative to translated pivot */
70 
71  /* measured relative to translated pivot */
73 
77 
78 /* Tracks are reordered for initialization, starting as close as possible to
79  * anchor_frame
80  */
81 typedef struct TrackInitOrder {
86 
87 /* Per frame private working data, for accessing possibly animated values. */
88 typedef struct StabContext {
101 
103  MovieTrackingTrack *track)
104 {
105  return BLI_ghash_lookup(ctx->private_track_data, track);
106 }
107 
109  MovieTrackingTrack *track,
110  TrackStabilizationBase *private_data)
111 {
112  BLI_ghash_insert(ctx->private_track_data, track, private_data);
113 }
114 
116 {
117  if (val != NULL) {
118  MEM_freeN(val);
119  }
120 }
121 
122 /* == access animated values for given frame == */
123 
124 static FCurve *retrieve_stab_animation(MovieClip *clip, const char *data_path, int idx)
125 {
126  return id_data_find_fcurve(&clip->id,
127  &clip->tracking.stabilization,
128  &RNA_MovieTrackingStabilization,
129  data_path,
130  idx,
131  NULL);
132 }
133 
135 {
136  return id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack, "weight_stab", 0, NULL);
137 }
138 
139 static float fetch_from_fcurve(FCurve *animationCurve,
140  int framenr,
141  StabContext *ctx,
142  float default_value)
143 {
144  if (ctx && ctx->use_animation && animationCurve) {
145  int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip, framenr);
146  return evaluate_fcurve(animationCurve, scene_framenr);
147  }
148  return default_value;
149 }
150 
151 static float get_animated_locinf(StabContext *ctx, int framenr)
152 {
153  return fetch_from_fcurve(ctx->locinf, framenr, ctx, ctx->stab->locinf);
154 }
155 
156 static float get_animated_rotinf(StabContext *ctx, int framenr)
157 {
158  return fetch_from_fcurve(ctx->rotinf, framenr, ctx, ctx->stab->rotinf);
159 }
160 
161 static float get_animated_scaleinf(StabContext *ctx, int framenr)
162 {
163  return fetch_from_fcurve(ctx->scaleinf, framenr, ctx, ctx->stab->scaleinf);
164 }
165 
166 static void get_animated_target_pos(StabContext *ctx, int framenr, float target_pos[2])
167 {
168  target_pos[0] = fetch_from_fcurve(ctx->target_pos[0], framenr, ctx, ctx->stab->target_pos[0]);
169  target_pos[1] = fetch_from_fcurve(ctx->target_pos[1], framenr, ctx, ctx->stab->target_pos[1]);
170 }
171 
172 static float get_animated_target_rot(StabContext *ctx, int framenr)
173 {
174  return fetch_from_fcurve(ctx->target_rot, framenr, ctx, ctx->stab->target_rot);
175 }
176 
177 static float get_animated_target_scale(StabContext *ctx, int framenr)
178 {
179  return fetch_from_fcurve(ctx->target_scale, framenr, ctx, ctx->stab->scale);
180 }
181 
182 static float get_animated_weight(StabContext *ctx, MovieTrackingTrack *track, int framenr)
183 {
185  if (working_data && working_data->track_weight_curve) {
186  int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip, framenr);
187  return evaluate_fcurve(working_data->track_weight_curve, scene_framenr);
188  }
189  /* Use weight at global 'current frame' as fallback default. */
190  return track->weight_stab;
191 }
192 
193 static void use_values_from_fcurves(StabContext *ctx, bool toggle)
194 {
195  if (ctx != NULL) {
196  ctx->use_animation = toggle;
197  }
198 }
199 
200 /* Prepare per call private working area.
201  * Used for access to possibly animated values: retrieve available F-Curves.
202  */
204 {
205  StabContext *ctx = MEM_callocN(sizeof(StabContext), "2D stabilization animation runtime data");
206  ctx->clip = clip;
207  ctx->tracking = &clip->tracking;
208  ctx->stab = &clip->tracking.stabilization;
209  ctx->private_track_data = BLI_ghash_ptr_new("2D stabilization per track private working data");
210  ctx->locinf = retrieve_stab_animation(clip, "influence_location", 0);
211  ctx->rotinf = retrieve_stab_animation(clip, "influence_rotation", 0);
212  ctx->scaleinf = retrieve_stab_animation(clip, "influence_scale", 0);
213  ctx->target_pos[0] = retrieve_stab_animation(clip, "target_pos", 0);
214  ctx->target_pos[1] = retrieve_stab_animation(clip, "target_pos", 1);
215  ctx->target_rot = retrieve_stab_animation(clip, "target_rot", 0);
216  ctx->target_scale = retrieve_stab_animation(clip, "target_zoom", 0);
217  ctx->use_animation = true;
218  return ctx;
219 }
220 
230 {
231  if (ctx != NULL) {
233  MEM_freeN(ctx);
234  }
235 }
236 
238 {
240  return (working_data != NULL && working_data->is_init_for_stabilization);
241 }
242 
244 {
245  return (track->flag & TRACK_USE_2D_STAB) && is_init_for_stabilization(ctx, track);
246 }
247 
249  MovieTrackingTrack *track,
250  MovieTrackingMarker *marker)
251 {
252  return (marker->flag & MARKER_DISABLED) ||
253  (EPSILON_WEIGHT > get_animated_weight(ctx, track, marker->framenr));
254 }
255 
256 static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame)
257 {
258  const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, ref_frame);
259  return marker - track->markers;
260 }
261 
263  StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_higher)
264 {
266  int end = track->markersnr;
267  BLI_assert(0 <= i && i < end);
268 
269  while (i < end &&
270  (markers[i].framenr < ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
271  i++;
272  }
273  if (i < end && markers[i].framenr < *next_higher) {
274  BLI_assert(markers[i].framenr >= ref_frame);
275  *next_higher = markers[i].framenr;
276  }
277 }
278 
280  StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_lower)
281 {
283  BLI_assert(0 <= i && i < track->markersnr);
284  while (i >= 0 &&
285  (markers[i].framenr > ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
286  i--;
287  }
288  if (0 <= i && markers[i].framenr > *next_lower) {
289  BLI_assert(markers[i].framenr <= ref_frame);
290  *next_lower = markers[i].framenr;
291  }
292 }
293 
294 /* Find closest frames with usable stabilization data.
295  * A frame counts as _usable_ when there is at least one track marked for
296  * translation stabilization, which has an enabled tracking marker at this very
297  * frame. We search both for the next lower and next higher position, to allow
298  * the caller to interpolate gaps and to extrapolate at the ends of the
299  * definition range. */
301  int framenr,
302  int *next_lower,
303  int *next_higher)
304 {
306  if (is_usable_for_stabilization(ctx, track)) {
307  int startpoint = search_closest_marker_index(track, framenr);
308  retrieve_next_higher_usable_frame(ctx, track, startpoint, framenr, next_higher);
309  retrieve_next_lower_usable_frame(ctx, track, startpoint, framenr, next_lower);
310  }
311  }
312 }
313 
314 /* Find active (enabled) marker closest to the reference frame. */
316  MovieTrackingTrack *track,
317  int ref_frame)
318 {
319  int next_lower = MINAFRAME;
320  int next_higher = MAXFRAME;
321  int i = search_closest_marker_index(track, ref_frame);
322  retrieve_next_higher_usable_frame(ctx, track, i, ref_frame, &next_higher);
323  retrieve_next_lower_usable_frame(ctx, track, i, ref_frame, &next_lower);
324 
325  if ((next_higher - ref_frame) < (ref_frame - next_lower)) {
326  return BKE_tracking_marker_get_exact(track, next_higher);
327  }
328 
329  return BKE_tracking_marker_get_exact(track, next_lower);
330 }
331 
332 /* Retrieve tracking data, if available and applicable for this frame.
333  * The returned weight value signals the validity; data recorded for this
334  * tracking marker on the exact requested frame is output with the full weight
335  * of this track, while gaps in the data sequence cause the weight to go to zero.
336  */
338  MovieTrackingTrack *track,
339  int framenr,
340  float *r_weight)
341 {
342  MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
343  if (marker != NULL && !(marker->flag & MARKER_DISABLED)) {
344  *r_weight = get_animated_weight(ctx, track, framenr);
345  return marker;
346  }
347 
348  /* No marker at this frame (=gap) or marker disabled. */
349  *r_weight = 0.0f;
350  return NULL;
351 }
352 
353 /* Define the reference point for rotation/scale measurement and compensation.
354  * The stabilizer works by assuming the image was distorted by a affine linear
355  * transform, i.e. it was rotated and stretched around this reference point
356  * (pivot point) and then shifted laterally. Any scale and orientation changes
357  * will be picked up relative to this point. And later the image will be
358  * stabilized by rotating around this point. The result can only be as
359  * accurate as this pivot point actually matches the real rotation center
360  * of the actual movements. Thus any scheme to define a pivot point is
361  * always guesswork.
362  *
363  * As a simple default, we use the weighted average of the location markers
364  * of the current frame as pivot point. TODO: It is planned to add further
365  * options, like e.g. anchoring the pivot point at the canvas. Moreover,
366  * it is planned to allow for a user controllable offset.
367  */
368 static void setup_pivot(const float ref_pos[2], float r_pivot[2])
369 {
370  zero_v2(r_pivot); /* TODO: add an animated offset position here. */
371  add_v2_v2(r_pivot, ref_pos);
372 }
373 
374 /* Calculate the contribution of a single track at the time position (frame) of
375  * the given marker. Each track has a local reference frame, which is as close
376  * as possible to the global anchor_frame. Thus the translation contribution is
377  * comprised of the offset relative to the image position at that reference
378  * frame, plus a guess of the contribution for the time span between the
379  * anchor_frame and the local reference frame of this track. The constant part
380  * of this contribution is precomputed initially. At the anchor_frame, by
381  * definition the contribution of all tracks is zero, keeping the frame in place.
382  *
383  * track_ref is per track baseline contribution at reference frame; filled in at
384  * initialization
385  * marker is tracking data to use as contribution for current frame.
386  * result_offset is a total cumulated contribution of this track,
387  * relative to the stabilization anchor_frame,
388  * in normalized (0...1) coordinates.
389  */
391  MovieTrackingMarker *marker,
392  float result_offset[2])
393 {
394  add_v2_v2v2(result_offset, track_ref->stabilization_offset_base, marker->pos);
395 }
396 
397 /* Similar to the ::translation_contribution(), the rotation contribution is
398  * comprised of the contribution by this individual track, and the averaged
399  * contribution from anchor_frame to the ref point of this track.
400  * - Contribution is in terms of angles, -pi < angle < +pi, and all averaging
401  * happens in this domain.
402  * - Yet the actual measurement happens as vector between pivot and the current
403  * tracking point
404  * - Currently we use the center of frame as approximation for the rotation pivot
405  * point.
406  * - Moreover, the pivot point has to be compensated for the already determined
407  * shift offset, in order to get the pure rotation around the pivot.
408  * To turn this into a _contribution_, the likewise corrected angle at the
409  * reference frame has to be subtracted, to get only the pure angle difference
410  * this tracking point has captured.
411  * - To get from vectors to angles, we have to go through an arcus tangens,
412  * which involves the issue of the definition range: the resulting angles will
413  * flip by 360deg when the measured vector passes from the 2nd to the third
414  * quadrant, thus messing up the average calculation. Since _any_ tracking
415  * point might be used, these problems are quite common in practice.
416  * - Thus we perform the subtraction of the reference and the addition of the
417  * baseline contribution in polar coordinates as simple addition of angles;
418  * since these parts are fixed, we can bake them into a rotation matrix.
419  * With this approach, the border of the arcus tangens definition range will
420  * be reached only, when the _whole_ contribution approaches +- 180deg,
421  * meaning we've already tilted the frame upside down. This situation is way
422  * less common and can be tolerated.
423  * - As an additional feature, when activated, also changes in image scale
424  * relative to the rotation center can be picked up. To handle those values
425  * in the same framework, we average the scales as logarithms.
426  *
427  * aspect is a total aspect ratio of the undistorted image (includes fame and
428  * pixel aspect). The function returns a quality factor, which can be used
429  * to damp the contributions of points in close proximity to the pivot point,
430  * since such contributions might be dominated by rounding errors and thus
431  * poison the calculated average. When the quality factor goes towards zero,
432  * the weight of this contribution should be reduced accordingly.
433  */
435  MovieTrackingMarker *marker,
436  const float aspect,
437  const float pivot[2],
438  float *result_angle,
439  float *result_scale)
440 {
441  float len, quality;
442  float pos[2];
443  sub_v2_v2v2(pos, marker->pos, pivot);
444 
445  pos[0] *= aspect;
447 
448  *result_angle = atan2f(pos[1], pos[0]);
449 
450  len = len_v2(pos);
451 
452  /* prevent points very close to the pivot point from poisoning the result */
455 
456  *result_scale = len * track_ref->stabilization_scale_base;
457  BLI_assert(0.0 < *result_scale);
458 
459  return quality;
460 }
461 
462 /* Workaround to allow for rotation around an arbitrary pivot point.
463  * Currently, the public API functions do not support this flexibility.
464  * Rather, rotation will always be applied around a fixed origin.
465  * As a workaround, we shift the image after rotation to match the
466  * desired rotation center. And since this offset needs to be applied
467  * after the rotation and scaling, we can collapse it with the
468  * translation compensation, which is also a lateral shift (offset).
469  * The offset to apply is intended_pivot - rotated_pivot
470  */
471 static void compensate_rotation_center(const int size,
472  float aspect,
473  const float angle,
474  const float scale,
475  const float pivot[2],
476  float result_translation[2])
477 {
478  const float origin[2] = {0.5f * aspect * size, 0.5f * size};
479  float intended_pivot[2], rotated_pivot[2];
480  float rotation_mat[2][2];
481 
482  copy_v2_v2(intended_pivot, pivot);
483  copy_v2_v2(rotated_pivot, pivot);
484  angle_to_mat2(rotation_mat, +angle);
485  sub_v2_v2(rotated_pivot, origin);
486  mul_m2_v2(rotation_mat, rotated_pivot);
487  mul_v2_fl(rotated_pivot, scale);
488  add_v2_v2(rotated_pivot, origin);
489  add_v2_v2(result_translation, intended_pivot);
490  sub_v2_v2(result_translation, rotated_pivot);
491 }
492 
493 /* Weighted average of the per track cumulated contributions at given frame.
494  * Returns truth if all desired calculations could be done and all averages are
495  * available.
496  *
497  * NOTE: Even if the result is not `true`, the returned translation and angle
498  * are always sensible and as good as can be. Especially in the
499  * initialization phase we might not be able to get any average (yet) or
500  * get only a translation value. Since initialization visits tracks in a
501  * specific order, starting from anchor_frame, the result is logically
502  * correct non the less. But under normal operation conditions,
503  * a result of `false` should disable the stabilization function
504  */
506  int framenr,
507  float aspect,
508  float r_translation[2],
509  float r_pivot[2],
510  float *r_angle,
511  float *r_scale_step)
512 {
513  bool ok;
514  float weight_sum;
515  MovieTracking *tracking = ctx->tracking;
516  MovieTrackingStabilization *stab = &tracking->stabilization;
517  float ref_pos[2];
519 
520  zero_v2(r_translation);
521  *r_scale_step = 0.0f; /* logarithm */
522  *r_angle = 0.0f;
523 
524  zero_v2(ref_pos);
525 
526  ok = false;
527  weight_sum = 0.0f;
528  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
529  if (!is_init_for_stabilization(ctx, track)) {
530  continue;
531  }
532  if (track->flag & TRACK_USE_2D_STAB) {
533  float weight = 0.0f;
534  MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
535  if (marker) {
537  track);
538  BLI_assert(stabilization_base != NULL);
539  float offset[2];
540  weight_sum += weight;
541  translation_contribution(stabilization_base, marker, offset);
542  r_translation[0] += weight * offset[0];
543  r_translation[1] += weight * offset[1];
544  ref_pos[0] += weight * marker->pos[0];
545  ref_pos[1] += weight * marker->pos[1];
546  ok |= (weight_sum > EPSILON_WEIGHT);
547  }
548  }
549  }
550  if (!ok) {
551  return false;
552  }
553 
554  ref_pos[0] /= weight_sum;
555  ref_pos[1] /= weight_sum;
556  r_translation[0] /= weight_sum;
557  r_translation[1] /= weight_sum;
558  setup_pivot(ref_pos, r_pivot);
559 
560  if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
561  return ok;
562  }
563 
564  ok = false;
565  weight_sum = 0.0f;
566  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
567  if (!is_init_for_stabilization(ctx, track)) {
568  continue;
569  }
570  if (track->flag & TRACK_USE_2D_STAB_ROT) {
571  float weight = 0.0f;
572  MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
573  if (marker) {
575  track);
576  BLI_assert(stabilization_base != NULL);
577  float rotation, scale, quality;
578  quality = rotation_contribution(
579  stabilization_base, marker, aspect, r_pivot, &rotation, &scale);
580  const float quality_weight = weight * quality;
581  weight_sum += quality_weight;
582  *r_angle += rotation * quality_weight;
583  if (stab->flag & TRACKING_STABILIZE_SCALE) {
584  *r_scale_step += logf(scale) * quality_weight;
585  }
586  else {
587  *r_scale_step = 0;
588  }
589  /* NOTE: Use original marker weight and not the scaled one with the proximity here to allow
590  * simple stabilization setups when there is a single track in a close proximity of the
591  * center. */
592  ok |= (weight > EPSILON_WEIGHT);
593  }
594  }
595  }
596  if (ok) {
597  *r_scale_step /= weight_sum;
598  *r_angle /= weight_sum;
599  }
600  else {
601  /* We reach this point because translation could be calculated,
602  * but rotation/scale found no data to work on.
603  */
604  *r_scale_step = 0.0f;
605  *r_angle = 0.0f;
606  }
607  return true;
608 }
609 
610 /* Calculate weight center of location tracks for given frame.
611  * This function performs similar calculations as average_track_contributions(),
612  * but does not require the tracks to be initialized for stabilization. Moreover,
613  * when there is no usable tracking data for the given frame number, data from
614  * a neighboring frame is used. Thus this function can be used to calculate
615  * a starting point on initialization.
616  */
617 static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
618 {
619  bool ok = false;
620  float weight_sum;
621  MovieTracking *tracking = ctx->tracking;
622 
623  zero_v2(r_ref_pos);
624  weight_sum = 0.0f;
625  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
626  if (track->flag & TRACK_USE_2D_STAB) {
627  float weight = 0.0f;
628  MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
629  if (marker) {
630  weight_sum += weight;
631  r_ref_pos[0] += weight * marker->pos[0];
632  r_ref_pos[1] += weight * marker->pos[1];
633  ok |= (weight_sum > EPSILON_WEIGHT);
634  }
635  }
636  }
637  if (ok) {
638  r_ref_pos[0] /= weight_sum;
639  r_ref_pos[1] /= weight_sum;
640  }
641  else {
642  /* No usable tracking data on any track on this frame.
643  * Use data from neighboring frames to extrapolate...
644  */
645  int next_lower = MINAFRAME;
646  int next_higher = MAXFRAME;
647  use_values_from_fcurves(ctx, true);
648  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
649  /* NOTE: we deliberately do not care if this track
650  * is already initialized for stabilization. */
651  if (track->flag & TRACK_USE_2D_STAB) {
652  int startpoint = search_closest_marker_index(track, framenr);
653  retrieve_next_higher_usable_frame(ctx, track, startpoint, framenr, &next_higher);
654  retrieve_next_lower_usable_frame(ctx, track, startpoint, framenr, &next_lower);
655  }
656  }
657  if (next_lower >= MINFRAME) {
658  /* use next usable frame to the left.
659  * Also default to this frame when we're in a gap */
660  average_marker_positions(ctx, next_lower, r_ref_pos);
661  }
662  else if (next_higher < MAXFRAME) {
663  average_marker_positions(ctx, next_higher, r_ref_pos);
664  }
665  use_values_from_fcurves(ctx, false);
666  }
667 }
668 
669 /* Linear interpolation of data retrieved at two measurement points.
670  * This function is used to fill gaps in the middle of the covered area,
671  * at frames without any usable tracks for stabilization.
672  *
673  * framenr is a position to interpolate for.
674  * frame_a is a valid measurement point below framenr
675  * frame_b is a valid measurement point above framenr
676  * Returns truth if both measurements could actually be retrieved.
677  * Otherwise output parameters remain unaltered
678  */
680  int framenr,
681  int frame_a,
682  int frame_b,
683  const float aspect,
684  float r_translation[2],
685  float r_pivot[2],
686  float *r_angle,
687  float *r_scale_step)
688 {
689  float t, s;
690  float trans_a[2], trans_b[2];
691  float angle_a, angle_b;
692  float scale_a, scale_b;
693  float pivot_a[2], pivot_b[2];
694  bool success = false;
695 
696  BLI_assert(frame_a <= frame_b);
697  BLI_assert(frame_a <= framenr);
698  BLI_assert(framenr <= frame_b);
699 
700  t = ((float)framenr - frame_a) / (frame_b - frame_a);
701  s = 1.0f - t;
702 
703  success = average_track_contributions(
704  ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
705  if (!success) {
706  return false;
707  }
708  success = average_track_contributions(
709  ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
710  if (!success) {
711  return false;
712  }
713 
714  interp_v2_v2v2(r_translation, trans_a, trans_b, t);
715  interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
716  *r_scale_step = s * scale_a + t * scale_b;
717  *r_angle = s * angle_a + t * angle_b;
718  return true;
719 }
720 
721 /* Reorder tracks starting with those providing a tracking data frame
722  * closest to the global anchor_frame. Tracks with a gap at anchor_frame or
723  * starting farer away from anchor_frame altogether will be visited later.
724  * This allows to build up baseline contributions incrementally.
725  *
726  * order is an array for sorting the tracks. Must be of suitable size to hold
727  * all tracks.
728  * Returns number of actually usable tracks, can be less than the overall number
729  * of tracks.
730  *
731  * NOTE: After returning, the order array holds entries up to the number of
732  * usable tracks, appropriately sorted starting with the closest tracks.
733  * Initialization includes disabled tracks, since they might be enabled
734  * through automation later.
735  */
737 {
738  size_t tracknr = 0;
739  MovieTracking *tracking = ctx->tracking;
740  int anchor_frame = tracking->stabilization.anchor_frame;
741 
742  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
743  MovieTrackingMarker *marker;
744  order[tracknr].data = track;
745  marker = get_closest_marker(ctx, track, anchor_frame);
746  if (marker != NULL && (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT))) {
747  order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
748  order[tracknr].reference_frame = marker->framenr;
749  tracknr++;
750  }
751  }
752  if (tracknr) {
753  qsort(order, tracknr, sizeof(TrackInitOrder), BLI_sortutil_cmp_int);
754  }
755  return tracknr;
756 }
757 
758 /* Setup the constant part of this track's contribution to the determined frame
759  * movement. Tracks usually don't provide tracking data for every frame. Thus,
760  * for determining data at a given frame, we split up the contribution into a
761  * part covered by actual measurements on this track, and the initial gap
762  * between this track's reference frame and the global anchor_frame.
763  * The (missing) data for the gap can be substituted by the average offset
764  * observed by the other tracks covering the gap. This approximation doesn't
765  * introduce wrong data, but it records data with incorrect weight. A totally
766  * correct solution would require us to average the contribution per frame, and
767  * then integrate stepwise over all frames -- which of course would be way more
768  * expensive, especially for longer clips. To the contrary, our solution
769  * cumulates the total contribution per track and averages afterwards over all
770  * tracks; it can thus be calculated just based on the data of a single frame,
771  * plus the "baseline" for the reference frame, which is what we are computing
772  * here.
773  *
774  * Since we're averaging _contributions_, we have to calculate the _difference_
775  * of the measured position at current frame and the position at the reference
776  * frame. But the "reference" part of this difference is constant and can thus
777  * be packed together with the baseline contribution into a single precomputed
778  * vector per track.
779  *
780  * In case of the rotation contribution, the principle is the same, but we have
781  * to compensate for the already determined translation and measure the pure
782  * rotation, simply because this is how we model the offset: shift plus rotation
783  * around the shifted rotation center. To circumvent problems with the
784  * definition range of the arcus tangens function, we perform this baseline
785  * addition and reference angle subtraction in polar coordinates and bake this
786  * operation into a precomputed rotation matrix.
787  *
788  * track is a track to be initialized to initialize
789  * reference_frame is a local frame for this track, the closest pick to the
790  * global anchor_frame.
791  * aspect is a total aspect ratio of the undistorted image (includes fame and
792  * pixel aspect).
793  * target_pos is a possibly animated target position as set by the user for
794  * the reference_frame
795  * average_translation is a value observed by the _other_ tracks for the gap
796  * between reference_frame and anchor_frame. This
797  * average must not contain contributions of frames
798  * not yet initialized
799  * average_angle in a similar way, the rotation value observed by the
800  * _other_ tracks.
801  * average_scale_step is an image scale factor observed on average by the other
802  * tracks for this frame. This value is recorded and
803  * averaged as logarithm. The recorded scale changes
804  * are damped for very small contributions, to limit
805  * the effect of probe points approaching the pivot
806  * too closely.
807  *
808  * NOTE: when done, this track is marked as initialized
809  */
811  MovieTrackingTrack *track,
812  int reference_frame,
813  float aspect,
814  const float average_translation[2],
815  const float pivot[2],
816  const float average_angle,
817  const float average_scale_step)
818 {
819  float pos[2], angle, len;
821  MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, reference_frame);
822  /* Logic for initialization order ensures there *is* a marker on that
823  * very frame.
824  */
825  BLI_assert(marker != NULL);
826  BLI_assert(local_data != NULL);
827 
828  /* Per track baseline value for translation. */
829  sub_v2_v2v2(local_data->stabilization_offset_base, average_translation, marker->pos);
830 
831  /* Per track baseline value for rotation. */
832  sub_v2_v2v2(pos, marker->pos, pivot);
833 
834  pos[0] *= aspect;
835  angle = average_angle - atan2f(pos[1], pos[0]);
837 
838  /* Per track baseline value for zoom. */
840  local_data->stabilization_scale_base = expf(average_scale_step) / len;
841 
842  local_data->is_init_for_stabilization = true;
843 }
844 
845 static void init_all_tracks(StabContext *ctx, float aspect)
846 {
847  size_t track_len = 0;
848  MovieClip *clip = ctx->clip;
849  MovieTracking *tracking = ctx->tracking;
851 
852  /* Attempt to start initialization at anchor_frame.
853  * By definition, offset contribution is zero there.
854  */
855  int reference_frame = tracking->stabilization.anchor_frame;
856  float average_angle = 0, average_scale_step = 0;
857  float average_translation[2], average_pos[2], pivot[2];
858  zero_v2(average_translation);
859  zero_v2(pivot);
860 
861  /* Initialize private working data. */
862  LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
864  if (!local_data) {
865  local_data = MEM_callocN(sizeof(TrackStabilizationBase),
866  "2D stabilization per track baseline data");
867  attach_stabilization_baseline_data(ctx, track, local_data);
868  }
869  BLI_assert(local_data != NULL);
870  local_data->track_weight_curve = retrieve_track_weight_animation(clip, track);
871  local_data->is_init_for_stabilization = false;
872 
873  track_len++;
874  }
875  if (!track_len) {
876  return;
877  }
878 
879  order = MEM_mallocN(track_len * sizeof(TrackInitOrder), "stabilization track order");
880  if (!order) {
881  return;
882  }
883 
885  if (track_len == 0) {
886  goto cleanup;
887  }
888 
889  /* starting point for pivot, before having initialized any track */
890  average_marker_positions(ctx, reference_frame, average_pos);
891  setup_pivot(average_pos, pivot);
892 
893  for (int i = 0; i < track_len; i++) {
894  MovieTrackingTrack *track = order[i].data;
895  if (reference_frame != order[i].reference_frame) {
896  reference_frame = order[i].reference_frame;
898  reference_frame,
899  aspect,
900  average_translation,
901  pivot,
902  &average_angle,
903  &average_scale_step);
904  }
906  track,
907  reference_frame,
908  aspect,
909  average_translation,
910  pivot,
911  average_angle,
912  average_scale_step);
913  }
914 
915 cleanup:
916  MEM_freeN(order);
917 }
918 
919 /* Retrieve the measurement of frame movement by averaging contributions of
920  * active tracks.
921  *
922  * translation is a measurement in normalized 0..1 coordinates.
923  * angle is a measurement in radians -pi..+pi counter clockwise relative to
924  * translation compensated frame center
925  * scale_step is a measurement of image scale changes, in logarithmic scale
926  * (zero means scale == 1)
927  * Returns calculation enabled and all data retrieved as expected for this frame.
928  *
929  * NOTE: when returning `false`, output parameters are reset to neutral values.
930  */
932  int framenr,
933  float aspect,
934  float r_translation[2],
935  float r_pivot[2],
936  float *r_angle,
937  float *r_scale_step)
938 {
939  bool success = false;
940 
941  /* Early output if stabilization is disabled. */
942  if ((ctx->stab->flag & TRACKING_2D_STABILIZATION) == 0) {
943  zero_v2(r_translation);
944  *r_scale_step = 0.0f;
945  *r_angle = 0.0f;
946  return false;
947  }
948 
949  success = average_track_contributions(
950  ctx, framenr, aspect, r_translation, r_pivot, r_angle, r_scale_step);
951  if (!success) {
952  /* Try to hold extrapolated settings beyond the definition range
953  * and to interpolate in gaps without any usable tracking data
954  * to prevent sudden jump to image zero position.
955  */
956  int next_lower = MINAFRAME;
957  int next_higher = MAXFRAME;
958  use_values_from_fcurves(ctx, true);
959  find_next_working_frames(ctx, framenr, &next_lower, &next_higher);
960  if (next_lower >= MINFRAME && next_higher < MAXFRAME) {
962  framenr,
963  next_lower,
964  next_higher,
965  aspect,
966  r_translation,
967  r_pivot,
968  r_angle,
969  r_scale_step);
970  }
971  else if (next_higher < MAXFRAME) {
972  /* Before start of stabilized range: extrapolate start point
973  * settings.
974  */
975  success = average_track_contributions(
976  ctx, next_higher, aspect, r_translation, r_pivot, r_angle, r_scale_step);
977  }
978  else if (next_lower >= MINFRAME) {
979  /* After end of stabilized range: extrapolate end point settings. */
980  success = average_track_contributions(
981  ctx, next_lower, aspect, r_translation, r_pivot, r_angle, r_scale_step);
982  }
983  use_values_from_fcurves(ctx, false);
984  }
985  return success;
986 }
987 
988 /* Calculate stabilization data (translation, scale and rotation) from given raw
989  * measurements. Result is in absolute image dimensions (expanded image, square
990  * pixels), includes automatic or manual scaling and compensates for a target
991  * frame position, if given.
992  *
993  * size is a size of the expanded image, the width in pixels is size * aspect.
994  * aspect is a ratio (width / height) of the effective canvas (square pixels).
995  * do_compensate denotes whether to actually output values necessary to
996  * _compensate_ the determined frame movement.
997  * Otherwise, the effective target movement is returned.
998  */
1000  int framenr,
1001  int size,
1002  float aspect,
1003  bool do_compensate,
1004  float scale_step,
1005  float r_translation[2],
1006  float r_pivot[2],
1007  float *r_scale,
1008  float *r_angle)
1009 {
1010  float target_pos[2], target_scale;
1011  float scaleinf = get_animated_scaleinf(ctx, framenr);
1012 
1013  if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
1014  *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
1015  }
1016  else {
1017  *r_scale = 1.0f;
1018  }
1019 
1020  mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
1021  *r_angle *= get_animated_rotinf(ctx, framenr);
1022 
1023  /* Compensate for a target frame position.
1024  * This allows to follow tracking / panning shots in a semi manual fashion,
1025  * when animating the settings for the target frame position.
1026  */
1027  get_animated_target_pos(ctx, framenr, target_pos);
1028  sub_v2_v2(r_translation, target_pos);
1029  *r_angle -= get_animated_target_rot(ctx, framenr);
1030  target_scale = get_animated_target_scale(ctx, framenr);
1031  if (target_scale != 0.0f) {
1032  *r_scale /= target_scale;
1033  /* target_scale is an expected/intended reference zoom value */
1034  }
1035 
1036  /* Convert from relative to absolute coordinates, square pixels. */
1037  r_translation[0] *= (float)size * aspect;
1038  r_translation[1] *= (float)size;
1039  r_pivot[0] *= (float)size * aspect;
1040  r_pivot[1] *= (float)size;
1041 
1042  /* Output measured data, or inverse of the measured values for
1043  * compensation?
1044  */
1045  if (do_compensate) {
1046  mul_v2_fl(r_translation, -1.0f);
1047  *r_angle *= -1.0f;
1048  if (*r_scale != 0.0f) {
1049  *r_scale = 1.0f / *r_scale;
1050  }
1051  }
1052 }
1053 
1054 static void stabilization_data_to_mat4(float pixel_aspect,
1055  const float pivot[2],
1056  const float translation[2],
1057  float scale,
1058  float angle,
1059  float r_mat[4][4])
1060 {
1061  float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], pivot_mat[4][4],
1062  inv_pivot_mat[4][4], aspect_mat[4][4], inv_aspect_mat[4][4];
1063  const float scale_vector[3] = {scale, scale, 1.0f};
1064 
1065  unit_m4(translation_mat);
1066  unit_m4(rotation_mat);
1067  unit_m4(scale_mat);
1068  unit_m4(aspect_mat);
1069  unit_m4(pivot_mat);
1070  unit_m4(inv_pivot_mat);
1071 
1072  /* aspect ratio correction matrix */
1073  aspect_mat[0][0] /= pixel_aspect;
1074  invert_m4_m4(inv_aspect_mat, aspect_mat);
1075 
1076  add_v2_v2(pivot_mat[3], pivot);
1077  sub_v2_v2(inv_pivot_mat[3], pivot);
1078 
1079  size_to_mat4(scale_mat, scale_vector); /* scale matrix */
1080  add_v2_v2(translation_mat[3], translation); /* translation matrix */
1081  rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
1082 
1083  /* Compose transformation matrix. */
1084  mul_m4_series(r_mat,
1085  aspect_mat,
1086  translation_mat,
1087  pivot_mat,
1088  scale_mat,
1089  rotation_mat,
1090  inv_pivot_mat,
1091  inv_aspect_mat);
1092 }
1093 
1094 /* Calculate scale factor necessary to eliminate black image areas
1095  * caused by the compensating movements of the stabilizer.
1096  * This function visits every frame where stabilization data is
1097  * available and determines the factor for this frame. The overall
1098  * largest factor found is returned as result.
1099  *
1100  * NOTE: all tracks need to be initialized before calling this function.
1101  */
1102 static float calculate_autoscale_factor(StabContext *ctx, int size, float aspect)
1103 {
1104  MovieTrackingStabilization *stab = ctx->stab;
1105  float pixel_aspect = ctx->tracking->camera.pixel_aspect;
1106  int height = size, width = aspect * size;
1107 
1108  int sfra = INT_MAX, efra = INT_MIN;
1109  float scale = 1.0f, scale_step = 0.0f;
1110 
1111  /* Calculate maximal frame range of tracks where stabilization is active. */
1112  LISTBASE_FOREACH (MovieTrackingTrack *, track, &ctx->tracking->tracks) {
1113  if ((track->flag & TRACK_USE_2D_STAB) ||
1114  ((stab->flag & TRACKING_STABILIZE_ROTATION) && (track->flag & TRACK_USE_2D_STAB_ROT))) {
1115  int first_frame = track->markers[0].framenr;
1116  int last_frame = track->markers[track->markersnr - 1].framenr;
1117  sfra = min_ii(sfra, first_frame);
1118  efra = max_ii(efra, last_frame);
1119  }
1120  }
1121 
1122  use_values_from_fcurves(ctx, true);
1123  for (int cfra = sfra; cfra <= efra; cfra++) {
1124  float translation[2], pivot[2], angle, tmp_scale;
1125  float mat[4][4];
1126  const float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}};
1127  const bool do_compensate = true;
1128  /* Calculate stabilization parameters for the current frame. */
1130  ctx, cfra, aspect, translation, pivot, &angle, &scale_step);
1132  cfra,
1133  size,
1134  aspect,
1135  do_compensate,
1136  scale_step,
1137  translation,
1138  pivot,
1139  &tmp_scale,
1140  &angle);
1141  /* Compose transformation matrix. */
1142  /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
1143  * to construct transformation matrix using proper pivot point.
1144  * Compensation for that will happen later on.
1145  */
1146  stabilization_data_to_mat4(pixel_aspect, pivot, translation, tmp_scale, angle, mat);
1147  /* Investigate the transformed border lines for this frame;
1148  * find out, where it cuts the original frame.
1149  */
1150  for (int edge_index = 0; edge_index < 4; edge_index++) {
1151  /* Calculate coordinates of stabilized frame edge points.
1152  * Use matrix multiplication here so we operate in homogeneous
1153  * coordinates.
1154  */
1155  float stable_edge_p1[3], stable_edge_p2[3];
1156  copy_v2_v2(stable_edge_p1, points[edge_index]);
1157  copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
1158  stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
1159  mul_m4_v3(mat, stable_edge_p1);
1160  mul_m4_v3(mat, stable_edge_p2);
1161  /* Now we iterate over all original frame corners (we call them
1162  * 'point' here) to see if there's black area between stabilized
1163  * frame edge and original point.
1164  */
1165  for (int point_index = 0; point_index < 4; point_index++) {
1166  const float point[3] = {points[point_index][0], points[point_index][1], 0.0f};
1167  /* Calculate vector which goes from first edge point to
1168  * second one.
1169  */
1170  float stable_edge_vec[3];
1171  sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
1172  /* Calculate vector which connects current frame point to
1173  * first edge point.
1174  */
1175  float point_to_edge_start_vec[3];
1176  sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
1177  /* Use this two vectors to check whether frame point is inside
1178  * of the stabilized frame or not.
1179  * If the point is inside, there is no black area happening
1180  * and no scaling required for it.
1181  */
1182  if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
1183  /* We are scaling around motion-compensated pivot point. */
1184  float scale_pivot[2];
1185  add_v2_v2v2(scale_pivot, pivot, translation);
1186  /* Calculate line which goes via `point` and parallel to
1187  * the stabilized frame edge. This line is coming via
1188  * `point` and `point2` at the end.
1189  */
1190  float point2[2];
1191  add_v2_v2v2(point2, point, stable_edge_vec);
1192  /* Calculate actual distance between pivot point and
1193  * the stabilized frame edge. Then calculate distance
1194  * between pivot point and line which goes via actual
1195  * corner and is parallel to the edge.
1196  *
1197  * Dividing one by another will give us required scale
1198  * factor to get rid of black areas.
1199  */
1200  float real_dist = dist_to_line_v2(scale_pivot, stable_edge_p1, stable_edge_p2);
1201  float required_dist = dist_to_line_v2(scale_pivot, point, point2);
1202  const float S = required_dist / real_dist;
1203  scale = max_ff(scale, S);
1204  }
1205  }
1206  }
1207  }
1208  if (stab->maxscale > 0.0f) {
1209  scale = min_ff(scale, stab->maxscale);
1210  }
1211  use_values_from_fcurves(ctx, false);
1212 
1213  return scale;
1214 }
1215 
1216 /* Prepare working data and determine reference point for each track.
1217  *
1218  * NOTE: These calculations _could_ be cached and reused for all frames of the
1219  * same clip. However, since proper initialization depends on (weight)
1220  * animation and setup of tracks, ensuring consistency of cached init data
1221  * turns out to be tricky, hard to maintain and generally not worth the
1222  * effort. Thus we'll re-initialize on every frame.
1223  */
1224 static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
1225 {
1227  BLI_assert(ctx != NULL);
1228  init_all_tracks(ctx, aspect);
1229  if (ctx->stab->flag & TRACKING_AUTOSCALE) {
1230  ctx->stab->scale = 1.0;
1231  ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
1232  }
1233  /* By default, just use values for the global current frame. */
1234  use_values_from_fcurves(ctx, false);
1235  return ctx;
1236 }
1237 
1238 /* === public interface functions === */
1239 
1241  int framenr,
1242  int width,
1243  int height,
1244  float translation[2],
1245  float *scale,
1246  float *angle)
1247 {
1248  StabContext *ctx = NULL;
1249  MovieTracking *tracking = &clip->tracking;
1250  bool enabled = (tracking->stabilization.flag & TRACKING_2D_STABILIZATION);
1251  /* Might become a parameter of a stabilization compositor node. */
1252  bool do_compensate = true;
1253  float scale_step = 0.0f;
1254  float pixel_aspect = tracking->camera.pixel_aspect;
1255  float aspect = (float)width * pixel_aspect / height;
1256  int size = height;
1257  float pivot[2];
1258 
1259  if (enabled) {
1260  ctx = init_stabilizer(clip, size, aspect);
1261  }
1262 
1264  ctx, framenr, aspect, translation, pivot, angle, &scale_step)) {
1266  ctx, framenr, size, aspect, do_compensate, scale_step, translation, pivot, scale, angle);
1267  compensate_rotation_center(size, aspect, *angle, *scale, pivot, translation);
1268  }
1269  else {
1270  zero_v2(translation);
1271  *scale = 1.0f;
1272  *angle = 0.0f;
1273  }
1275 }
1276 
1277 typedef void (*interpolation_func)(const struct ImBuf *, struct ImBuf *, float, float, int, int);
1278 
1282  float (*mat)[4];
1283 
1286 
1288  void *__restrict userdata, const int j, const TaskParallelTLS *__restrict UNUSED(tls))
1289 {
1291  ImBuf *ibuf = data->ibuf;
1292  ImBuf *tmpibuf = data->tmpibuf;
1293  float(*mat)[4] = data->mat;
1294 
1295  interpolation_func interpolation = data->interpolation;
1296 
1297  for (int i = 0; i < tmpibuf->x; i++) {
1298  float vec[3] = {i, j, 0.0f};
1299 
1300  mul_v3_m4v3(vec, mat, vec);
1301 
1302  interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
1303  }
1304 }
1305 
1307  MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
1308 {
1309  float tloc[2], tscale, tangle;
1310  MovieTracking *tracking = &clip->tracking;
1311  MovieTrackingStabilization *stab = &tracking->stabilization;
1312  ImBuf *tmpibuf;
1313  int width = ibuf->x, height = ibuf->y;
1314  float pixel_aspect = tracking->camera.pixel_aspect;
1315  float mat[4][4];
1316  int filter = tracking->stabilization.filter;
1317  interpolation_func interpolation = NULL;
1318  int ibuf_flags;
1319 
1320  if (translation) {
1321  copy_v2_v2(tloc, translation);
1322  }
1323 
1324  if (scale) {
1325  tscale = *scale;
1326  }
1327 
1328  /* Perform early output if no stabilization is used. */
1329  if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
1330  if (translation) {
1331  zero_v2(translation);
1332  }
1333 
1334  if (scale) {
1335  *scale = 1.0f;
1336  }
1337 
1338  if (angle) {
1339  *angle = 0.0f;
1340  }
1341 
1342  return ibuf;
1343  }
1344 
1345  /* Allocate frame for stabilization result, copy alpha mode and color-space. */
1346  ibuf_flags = 0;
1347  if (ibuf->rect) {
1348  ibuf_flags |= IB_rect;
1349  }
1350  if (ibuf->rect_float) {
1351  ibuf_flags |= IB_rectfloat;
1352  }
1353 
1354  tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
1355  IMB_colormanagegent_copy_settings(ibuf, tmpibuf);
1356 
1357  /* Calculate stabilization matrix. */
1358  BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
1360  ibuf->x, ibuf->y, pixel_aspect, tloc, tscale, tangle, mat);
1361 
1362  /* The following code visits each nominal target grid position
1363  * and picks interpolated data "backwards" from source.
1364  * thus we need the inverse of the transformation to apply. */
1365  invert_m4(mat);
1366 
1368  interpolation = nearest_interpolation;
1369  }
1370  else if (filter == TRACKING_FILTER_BILINEAR) {
1371  interpolation = bilinear_interpolation;
1372  }
1373  else if (filter == TRACKING_FILTER_BICUBIC) {
1374  interpolation = bicubic_interpolation;
1375  }
1376  else {
1377  /* fallback to default interpolation method */
1378  interpolation = nearest_interpolation;
1379  }
1380 
1382  .ibuf = ibuf,
1383  .tmpibuf = tmpibuf,
1384  .mat = mat,
1385  .interpolation = interpolation,
1386  };
1387 
1388  TaskParallelSettings settings;
1390  settings.use_threading = (tmpibuf->y > 128);
1392  0, tmpibuf->y, &data, tracking_stabilize_frame_interpolation_cb, &settings);
1393 
1394  if (tmpibuf->rect_float) {
1395  tmpibuf->userflags |= IB_RECT_INVALID;
1396  }
1397 
1398  if (translation) {
1399  copy_v2_v2(translation, tloc);
1400  }
1401 
1402  if (scale) {
1403  *scale = tscale;
1404  }
1405 
1406  if (angle) {
1407  *angle = tangle;
1408  }
1409 
1410  return tmpibuf;
1411 }
1412 
1414  int buffer_height,
1415  float pixel_aspect,
1416  float translation[2],
1417  float scale,
1418  float angle,
1419  float r_mat[4][4])
1420 {
1421  /* Since we cannot receive the real pivot point coordinates (API limitation),
1422  * we perform the rotation/scale around the center of frame.
1423  * Then we correct by an additional shift, which was calculated in
1424  * compensate_rotation_center() and "sneaked in" as additional offset
1425  * in the translation parameter. This works, since translation needs to be
1426  * applied after rotation/scale anyway. Thus effectively the image gets
1427  * rotated around the desired pivot point
1428  */
1429  /* TODO(sergey): pivot shouldn't be calculated here, rather received
1430  * as a parameter.
1431  */
1432  float pivot[2];
1433  pivot[0] = 0.5f * pixel_aspect * buffer_width;
1434  pivot[1] = 0.5f * buffer_height;
1435  /* Compose transformation matrix. */
1436  stabilization_data_to_mat4(pixel_aspect, pivot, translation, scale, angle, r_mat);
1437 }
typedef float(TangentPoint)[2]
float evaluate_fcurve(struct FCurve *fcu, float evaltime)
Definition: fcurve.c:2135
struct FCurve * id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven)
Definition: fcurve.c:201
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr)
struct MovieTrackingMarker * BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1457
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1424
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:278
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1206
void unit_m4(float m[4][4])
Definition: rct.c:1090
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void size_to_mat4(float R[4][4], const float size[3])
Definition: math_matrix.c:2111
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
#define mul_m4_series(...)
void mul_m2_v2(const float M[2][2], float v[2])
Definition: math_matrix.c:785
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void rotate_m4(float mat[4][4], char axis, float angle)
Definition: math_matrix.c:2325
void angle_to_mat2(float R[2][2], float angle)
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
int BLI_sortutil_cmp_int(const void *a_, const void *b_)
Definition: sort_utils.c:52
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNUSED(x)
#define MINFRAME
#define MINAFRAME
#define MAXFRAME
@ TRACKING_AUTOSCALE
@ TRACKING_STABILIZE_SCALE
@ TRACKING_STABILIZE_ROTATION
@ TRACKING_2D_STABILIZATION
@ TRACKING_FILTER_BICUBIC
@ TRACKING_FILTER_NEAREST
@ TRACKING_FILTER_BILINEAR
@ MARKER_DISABLED
@ TRACK_USE_2D_STAB
@ TRACK_USE_2D_STAB_ROT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint order
void IMB_colormanagegent_copy_settings(struct ImBuf *ibuf_src, struct ImBuf *ibuf_dst)
void nearest_interpolation(const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout)
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
Contains defines and structs used throughout the imbuf module.
@ IB_RECT_INVALID
@ IB_rectfloat
@ IB_rect
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
#define logf(x)
Definition: cuda/compat.h:105
#define expf(x)
Definition: cuda/compat.h:106
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
uint pos
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
const vector< Marker > & markers
bool enabled
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const float *float_buffer, unsigned char *byte_output, float *float_output, int width, int height, int components, float u, float v, bool wrap_x, bool wrap_y)
Definition: math_interp.c:248
BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const float *float_buffer, unsigned char *byte_output, float *float_output, int width, int height, int components, float u, float v)
Definition: math_interp.c:78
#define atan2f(x, y)
Definition: metal/compat.h:227
T abs(const T &a)
int userflags
unsigned char planes
unsigned int * rect
float * rect_float
struct MovieTracking tracking
MovieTrackingMarker * markers
MovieTrackingStabilization stabilization
MovieTrackingCamera camera
MovieTrackingStabilization * stab
FCurve * target_pos[2]
FCurve * target_scale
FCurve * target_rot
GHash * private_track_data
MovieClip * clip
MovieTracking * tracking
MovieTrackingTrack * data
float stabilization_rotation_base[2][2]
void BKE_tracking_stabilization_data_to_mat4(int buffer_width, int buffer_height, float pixel_aspect, float translation[2], float scale, float angle, float r_mat[4][4])
static void retrieve_next_lower_usable_frame(StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_lower)
static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
struct TrackingStabilizeFrameInterpolationData TrackingStabilizeFrameInterpolationData
static void discard_stabilization_baseline_data(void *val)
static int establish_track_initialization_order(StabContext *ctx, TrackInitOrder *order)
static float get_animated_target_scale(StabContext *ctx, int framenr)
static FCurve * retrieve_track_weight_animation(MovieClip *clip, MovieTrackingTrack *track)
void BKE_tracking_stabilization_data_get(MovieClip *clip, int framenr, int width, int height, float translation[2], float *scale, float *angle)
static float get_animated_target_rot(StabContext *ctx, int framenr)
ImBuf * BKE_tracking_stabilize_frame(MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
static FCurve * retrieve_stab_animation(MovieClip *clip, const char *data_path, int idx)
static float get_animated_rotinf(StabContext *ctx, int framenr)
static bool average_track_contributions(StabContext *ctx, int framenr, float aspect, float r_translation[2], float r_pivot[2], float *r_angle, float *r_scale_step)
static MovieTrackingMarker * get_closest_marker(StabContext *ctx, MovieTrackingTrack *track, int ref_frame)
struct TrackStabilizationBase TrackStabilizationBase
static StabContext * init_stabilizer(MovieClip *clip, int size, float aspect)
static void stabilization_calculate_data(StabContext *ctx, int framenr, int size, float aspect, bool do_compensate, float scale_step, float r_translation[2], float r_pivot[2], float *r_scale, float *r_angle)
struct TrackInitOrder TrackInitOrder
static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata, const int j, const TaskParallelTLS *__restrict UNUSED(tls))
static bool stabilization_determine_offset_for_frame(StabContext *ctx, int framenr, float aspect, float r_translation[2], float r_pivot[2], float *r_angle, float *r_scale_step)
static bool is_init_for_stabilization(StabContext *ctx, MovieTrackingTrack *track)
static bool is_usable_for_stabilization(StabContext *ctx, MovieTrackingTrack *track)
static bool is_effectively_disabled(StabContext *ctx, MovieTrackingTrack *track, MovieTrackingMarker *marker)
static void use_values_from_fcurves(StabContext *ctx, bool toggle)
static bool interpolate_averaged_track_contributions(StabContext *ctx, int framenr, int frame_a, int frame_b, const float aspect, float r_translation[2], float r_pivot[2], float *r_angle, float *r_scale_step)
static void get_animated_target_pos(StabContext *ctx, int framenr, float target_pos[2])
static float get_animated_locinf(StabContext *ctx, int framenr)
static void init_all_tracks(StabContext *ctx, float aspect)
static float get_animated_scaleinf(StabContext *ctx, int framenr)
static float get_animated_weight(StabContext *ctx, MovieTrackingTrack *track, int framenr)
static float SCALE_ERROR_LIMIT_BIAS
static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame)
static void find_next_working_frames(StabContext *ctx, int framenr, int *next_lower, int *next_higher)
static void attach_stabilization_baseline_data(StabContext *ctx, MovieTrackingTrack *track, TrackStabilizationBase *private_data)
static void setup_pivot(const float ref_pos[2], float r_pivot[2])
static float calculate_autoscale_factor(StabContext *ctx, int size, float aspect)
static float EPSILON_WEIGHT
static void stabilization_data_to_mat4(float pixel_aspect, const float pivot[2], const float translation[2], float scale, float angle, float r_mat[4][4])
static float fetch_from_fcurve(FCurve *animationCurve, int framenr, StabContext *ctx, float default_value)
void(* interpolation_func)(const struct ImBuf *, struct ImBuf *, float, float, int, int)
static StabContext * init_stabilization_working_context(MovieClip *clip)
static void retrieve_next_higher_usable_frame(StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_higher)
static float rotation_contribution(TrackStabilizationBase *track_ref, MovieTrackingMarker *marker, const float aspect, const float pivot[2], float *result_angle, float *result_scale)
static void compensate_rotation_center(const int size, float aspect, const float angle, const float scale, const float pivot[2], float result_translation[2])
static MovieTrackingMarker * get_tracking_data_point(StabContext *ctx, MovieTrackingTrack *track, int framenr, float *r_weight)
static void discard_stabilization_working_context(StabContext *ctx)
static void init_track_for_stabilization(StabContext *ctx, MovieTrackingTrack *track, int reference_frame, float aspect, const float average_translation[2], const float pivot[2], const float average_angle, const float average_scale_step)
static TrackStabilizationBase * access_stabilization_baseline_data(StabContext *ctx, MovieTrackingTrack *track)
static void translation_contribution(TrackStabilizationBase *track_ref, MovieTrackingMarker *marker, float result_offset[2])
struct StabContext StabContext