diff options
Diffstat (limited to 'source/blender/blenkernel/intern/tracking_stabilize.c')
-rw-r--r-- | source/blender/blenkernel/intern/tracking_stabilize.c | 565 |
1 files changed, 365 insertions, 200 deletions
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 4d72d851ae9..df42f253fdf 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -452,6 +452,29 @@ static MovieTrackingMarker *get_tracking_data_point( } } + +/* Define the reference point for rotation/scale measurement and compensation. + * The stabilizator works by assuming the image was distorted by a affine linear + * transform, i.e. it was rotated and stretched around this reference point + * (pivot point) and then shifted laterally. Any scale and orientation changes + * will be picked up relative to this point. And later the image will be + * stabilized by rotating around this point. The result can only be as + * accurate as this pivot point actually matches the real rotation center + * of the actual movements. Thus any scheme to define a pivot point is + * always guesswork. + * + * As a simple default, we use the weighted average of the location markers + * of the current frame as pivot point. TODO It is planned to add further + * options, like e.g. anchoring the pivot point at the canvas. Moreover, + * it is planned to allow for a user controllable offset. + */ +static void setup_pivot(const float ref_pos[2], float r_pivot[2]) +{ + zero_v2(r_pivot); /* TODO: add an animated offset position here. */ + add_v2_v2(r_pivot, ref_pos); +} + + /* Calculate the contribution of a single track at the time position (frame) of * the given marker. Each track has a local reference frame, which is as close * as possible to the global anchor_frame. Thus the translation contribution is @@ -508,22 +531,21 @@ static void translation_contribution(TrackStabilizationBase *track_ref, * in the same framework, we average the scales as logarithms. * * aspect is a total aspect ratio of the undistorted image (includes fame and - * pixel aspect). + * pixel aspect). The function returns a quality factor, which can be used + * to damp the contributions of points in close proximity to the pivot point, + * since such contributions might be dominated by rounding errors and thus + * poison the calculated average. When the quality factor goes towards zero, + * the weight of this contribution should be reduced accordingly. */ -static void rotation_contribution(TrackStabilizationBase *track_ref, - MovieTrackingMarker *marker, - float aspect, - float target_pos[2], - float averaged_translation_contribution[2], - float *result_angle, - float *result_scale) +static float rotation_contribution(TrackStabilizationBase *track_ref, + MovieTrackingMarker *marker, + const float aspect, + const float pivot[2], + float *result_angle, + float *result_scale) { - float len; + float len, quality; float pos[2]; - float pivot[2]; - copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */ - add_v2_v2(pivot, averaged_translation_contribution); - sub_v2_v2(pivot, target_pos); sub_v2_v2v2(pos, marker->pos, pivot); pos[0] *= aspect; @@ -531,9 +553,47 @@ static void rotation_contribution(TrackStabilizationBase *track_ref, *result_angle = atan2f(pos[1],pos[0]); - len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS; + len = len_v2(pos); + + /* prevent points very close to the pivot point from poisoning the result */ + quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS); + len += SCALE_ERROR_LIMIT_BIAS; + *result_scale = len * track_ref->stabilization_scale_base; BLI_assert(0.0 < *result_scale); + + return quality; +} + + +/* Workaround to allow for rotation around an arbitrary pivot point. + * Currently, the public API functions do not support this flexibility. + * Rather, rotation will always be applied around a fixed origin. + * As a workaround, we shift the image after rotation to match the + * desired rotation centre. And since this offset needs to be applied + * after the rotation and scaling, we can collapse it with the + * translation compensation, which is also a lateral shift (offset). + * The offset to apply is intended_pivot - rotated_pivot + */ +static void compensate_rotation_center(const int size, float aspect, + const float angle, + const float scale, + const float pivot[2], + float result_translation[2]) +{ + const float origin[2] = {0.5f*aspect*size, 0.5f*size}; + float intended_pivot[2], rotated_pivot[2]; + float rotation_mat[2][2]; + + copy_v2_v2(intended_pivot, pivot); + copy_v2_v2(rotated_pivot, pivot); + rotate_m2(rotation_mat, +angle); + sub_v2_v2(rotated_pivot, origin); + mul_m2v2(rotation_mat, rotated_pivot); + mul_v2_fl(rotated_pivot, scale); + add_v2_v2(rotated_pivot, origin); + add_v2_v2(result_translation, intended_pivot); + sub_v2_v2(result_translation, rotated_pivot); } @@ -553,6 +613,7 @@ 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) { @@ -561,12 +622,15 @@ static bool average_track_contributions(StabContext *ctx, MovieTrackingTrack *track; MovieTracking *tracking = ctx->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; + float ref_pos[2]; BLI_assert(stab->flag & TRACKING_2D_STABILIZATION); zero_v2(r_translation); *r_scale_step = 0.0f; /* logarithm */ *r_angle = 0.0f; + zero_v2(ref_pos); + ok = false; weight_sum = 0.0f; for (track = tracking->tracks.first; track; track = track->next) { @@ -586,8 +650,10 @@ static bool average_track_contributions(StabContext *ctx, float offset[2]; weight_sum += weight; translation_contribution(stabilization_base, marker, offset); - mul_v2_fl(offset, weight); - add_v2_v2(r_translation, offset); + r_translation[0] += weight * offset[0]; + r_translation[1] += weight * offset[1]; + ref_pos[0] += weight * marker->pos[0]; + ref_pos[1] += weight * marker->pos[1]; ok |= (weight_sum > EPSILON_WEIGHT); } } @@ -596,8 +662,11 @@ static bool average_track_contributions(StabContext *ctx, return false; } + ref_pos[0] /= weight_sum; + ref_pos[1] /= weight_sum; r_translation[0] /= weight_sum; r_translation[1] /= weight_sum; + setup_pivot(ref_pos, r_pivot); if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) { return ok; @@ -619,17 +688,15 @@ static bool average_track_contributions(StabContext *ctx, TrackStabilizationBase *stabilization_base = access_stabilization_baseline_data(ctx, track); BLI_assert(stabilization_base != NULL); - float rotation, scale; - float target_pos[2]; + float rotation, scale, quality; + quality = rotation_contribution(stabilization_base, + marker, + aspect, + r_pivot, + &rotation, + &scale); + weight *= quality; weight_sum += weight; - get_animated_target_pos(ctx, framenr, target_pos); - rotation_contribution(stabilization_base, - marker, - aspect, - target_pos, - r_translation, - &rotation, - &scale); *r_angle += rotation * weight; if (stab->flag & TRACKING_STABILIZE_SCALE) { *r_scale_step += logf(scale) * weight; @@ -656,6 +723,75 @@ static bool average_track_contributions(StabContext *ctx, } +/* Calculate weight center of location tracks for given frame. + * This function performs similar calculations as average_track_contributions(), + * but does not require the tracks to be initialized for stabilisation. Moreover, + * when there is no usable tracking data for the given frame number, data from + * a neighbouring frame is used. Thus this function can be used to calculate + * a starting point on initialization. + */ +static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2]) +{ + bool ok = false; + float weight_sum; + MovieTrackingTrack *track; + MovieTracking *tracking = ctx->tracking; + + zero_v2(r_ref_pos); + weight_sum = 0.0f; + for (track = tracking->tracks.first; track; track = track->next) { + if (track->flag & TRACK_USE_2D_STAB) { + float weight = 0.0f; + MovieTrackingMarker *marker = + get_tracking_data_point(ctx, track, framenr, &weight); + if (marker) { + weight_sum += weight; + r_ref_pos[0] += weight * marker->pos[0]; + r_ref_pos[1] += weight * marker->pos[1]; + ok |= (weight_sum > EPSILON_WEIGHT); + } + } + } + if (ok) { + r_ref_pos[0] /= weight_sum; + r_ref_pos[1] /= weight_sum; + } else { + /* No usable tracking data on any track on this frame. + * Use data from neighbouring frames to extrapolate... + */ + int next_lower = MINAFRAME; + int next_higher = MAXFRAME; + use_values_from_fcurves(ctx, true); + for (track = tracking->tracks.first; track; track = track->next) { + /* Note: we deliberately do not care if this track + * is already initialized for stabilisation */ + if (track->flag & TRACK_USE_2D_STAB) { + int startpoint = search_closest_marker_index(track, framenr); + retrieve_next_higher_usable_frame(ctx, + track, + startpoint, + framenr, + &next_higher); + retrieve_next_lower_usable_frame(ctx, + track, + startpoint, + framenr, + &next_lower); + } + } + if (next_lower >= MINFRAME) { + /* use next usable frame to the left. + * Also default to this frame when we're in a gap */ + average_marker_positions(ctx, next_lower, r_ref_pos); + + } else if (next_higher < MAXFRAME) { + average_marker_positions(ctx, next_higher, r_ref_pos); + } + use_values_from_fcurves(ctx, false); + } +} + + /* Linear interpolation of data retrieved at two measurement points. * This function is used to fill gaps in the middle of the covered area, * at frames without any usable tracks for stabilization. @@ -670,8 +806,9 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, int framenr, int frame_a, int frame_b, - float aspect, - float translation[2], + const float aspect, + float r_translation[2], + float r_pivot[2], float *r_angle, float *r_scale_step) { @@ -679,6 +816,7 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, float trans_a[2], trans_b[2]; float angle_a, angle_b; float scale_a, scale_b; + float pivot_a[2], pivot_b[2]; bool success = false; BLI_assert(frame_a <= frame_b); @@ -688,16 +826,17 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, t = ((float)framenr - frame_a) / (frame_b - frame_a); s = 1.0f - t; - success = average_track_contributions(ctx, frame_a, aspect, trans_a, &angle_a, &scale_a); + success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a); if (!success) { return false; } - success = average_track_contributions(ctx, frame_b, aspect, trans_b, &angle_b, &scale_b); + success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b); if (!success) { return false; } - interp_v2_v2v2(translation, trans_a, trans_b, t); + interp_v2_v2v2(r_translation, trans_a, trans_b, t); + interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t); *r_scale_step = s * scale_a + t * scale_b; *r_angle = s * angle_a + t * angle_b; return true; @@ -802,13 +941,12 @@ static void initialize_track_for_stabilization(StabContext *ctx, MovieTrackingTrack *track, int reference_frame, float aspect, - const float target_pos[2], const float average_translation[2], - float average_angle, - float average_scale_step) + const float pivot[2], + const float average_angle, + const float average_scale_step) { float pos[2], angle, len; - float pivot[2]; TrackStabilizationBase *local_data = access_stabilization_baseline_data(ctx, track); MovieTrackingMarker *marker = @@ -825,9 +963,6 @@ static void initialize_track_for_stabilization(StabContext *ctx, marker->pos); /* Per track baseline value for rotation. */ - copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */ - add_v2_v2(pivot, average_translation); - sub_v2_v2(pivot, target_pos); sub_v2_v2v2(pos, marker->pos, pivot); pos[0] *= aspect; @@ -855,10 +990,9 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) */ int reference_frame = tracking->stabilization.anchor_frame; float average_angle=0, average_scale_step=0; - float average_translation[2]; - float target_pos_at_ref_frame[2]; - zero_v2(target_pos_at_ref_frame); + float average_translation[2], average_pos[2], pivot[2]; zero_v2(average_translation); + zero_v2(pivot); /* Initialize private working data. */ for (track = tracking->tracks.first; track != NULL; track = track->next) { @@ -891,6 +1025,10 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) goto cleanup; } + /* starting point for pivot, before having initialized any track */ + average_marker_positions(ctx, reference_frame, average_pos); + setup_pivot(average_pos, pivot); + for (i = 0; i < track_cnt; ++i) { track = order[i].data; if (reference_frame != order[i].reference_frame) { @@ -899,18 +1037,16 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) reference_frame, aspect, average_translation, + pivot, &average_angle, &average_scale_step); - get_animated_target_pos(ctx, - reference_frame, - target_pos_at_ref_frame); } initialize_track_for_stabilization(ctx, track, reference_frame, aspect, - target_pos_at_ref_frame, average_translation, + pivot, average_angle, average_scale_step); } @@ -936,6 +1072,7 @@ 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) { @@ -953,6 +1090,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, framenr, aspect, r_translation, + r_pivot, r_angle, r_scale_step); if (!success) { @@ -971,6 +1109,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_higher, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -982,6 +1121,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_higher, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -991,6 +1131,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_lower, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -1017,16 +1158,17 @@ static void stabilization_calculate_data(StabContext *ctx, bool do_compensate, float scale_step, float r_translation[2], + float r_pivot[2], float *r_scale, float *r_angle) { - float target_pos[2]; + float target_pos[2], target_scale; float scaleinf = get_animated_scaleinf(ctx, framenr); - *r_scale = (get_animated_target_scale(ctx,framenr) - 1.0f) * scaleinf + 1.0f; - if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) { - *r_scale *= expf(scale_step * scaleinf); /* Averaged in log scale */ + *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */ + } else { + *r_scale = 1.0f; } mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr)); @@ -1039,10 +1181,17 @@ static void stabilization_calculate_data(StabContext *ctx, get_animated_target_pos(ctx, framenr, target_pos); sub_v2_v2(r_translation, target_pos); *r_angle -= get_animated_target_rot(ctx,framenr); + target_scale = get_animated_target_scale(ctx,framenr); + if (target_scale != 0.0f) { + *r_scale /= target_scale; + /* target_scale is an expected/intended reference zoom value */ + } /* Convert from relative to absolute coordinates, square pixels. */ r_translation[0] *= (float)size * aspect; r_translation[1] *= (float)size; + r_pivot[0] *= (float)size * aspect; + r_pivot[1] *= (float)size; /* Output measured data, or inverse of the measured values for * compensation? @@ -1056,25 +1205,61 @@ static void stabilization_calculate_data(StabContext *ctx, } } +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]) +{ + float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], + pivot_mat[4][4], inv_pivot_mat[4][4], + aspect_mat[4][4], inv_aspect_mat[4][4]; + float scale_vector[3] = {scale, scale, 1.0f}; -/* Determine the inner part of the frame, which is always safe to use. - * When enlarging the image by the inverse of this factor, any black areas - * appearing due to frame translation and rotation will be removed. + unit_m4(translation_mat); + unit_m4(rotation_mat); + unit_m4(scale_mat); + unit_m4(aspect_mat); + unit_m4(pivot_mat); + unit_m4(inv_pivot_mat); + + /* aspect ratio correction matrix */ + aspect_mat[0][0] /= pixel_aspect; + invert_m4_m4(inv_aspect_mat, aspect_mat); + + add_v2_v2(pivot_mat[3], pivot); + sub_v2_v2(inv_pivot_mat[3], pivot); + + 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_m4_series(r_mat, aspect_mat, translation_mat, + pivot_mat, scale_mat, rotation_mat, inv_pivot_mat, + inv_aspect_mat); +} + +/* Calculate scale factor necessary to eliminate black image areas + * caused by the compensating movements of the stabilizator. + * This function visits every frame where stabilisation data is + * available and determines the factor for this frame. The overall + * largest factor found is returned as result. * - * NOTE: When calling this function, basic initialization of tracks must be - * done already + * NOTE: all tracks need to be initialized before calling this function. */ -static void stabilization_determine_safe_image_area(StabContext *ctx, - int size, - float image_aspect) +static float calculate_autoscale_factor(StabContext *ctx, + int size, + float aspect) { MovieTrackingStabilization *stab = ctx->stab; float pixel_aspect = ctx->tracking->camera.pixel_aspect; + int height = size, width = aspect*size; int sfra = INT_MAX, efra = INT_MIN, cfra; float scale = 1.0f, scale_step = 0.0f; MovieTrackingTrack *track; - stab->scale = 1.0f; /* Calculate maximal frame range of tracks where stabilization is active. */ for (track = ctx->tracking->tracks.first; track; track = track->next) { @@ -1089,124 +1274,117 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, } } - /* For every frame we calculate scale factor needed to eliminate black border area - * and choose largest scale factor as final one. - */ + use_values_from_fcurves(ctx, true); for (cfra = sfra; cfra <= efra; cfra++) { - float translation[2], angle, tmp_scale; - int i; + float translation[2], pivot[2], angle, tmp_scale; float mat[4][4]; - float points[4][2] = {{0.0f, 0.0f}, - {0.0f, size}, - {image_aspect * size, size}, - {image_aspect * size, 0.0f}}; - float si, co; - bool do_compensate = true; - + const float points[4][2] = {{0.0f, 0.0f}, + {0.0f, height}, + {width, height}, + {width, 0.0f}}; + const bool do_compensate = true; + /* Calculate stabilization parameters for the current frame. */ stabilization_determine_offset_for_frame(ctx, cfra, - image_aspect, + aspect, translation, + pivot, &angle, &scale_step); stabilization_calculate_data(ctx, cfra, size, - image_aspect, + aspect, do_compensate, scale_step, translation, + pivot, &tmp_scale, &angle); - - BKE_tracking_stabilization_data_to_mat4(size * image_aspect, - size, - pixel_aspect, - translation, - 1.0f, - angle, - mat); - - si = sinf(angle); - co = cosf(angle); - + /* Compose transformation matrix. */ + /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have + * to construct transformation matrix using proper pivot point. + * Compensation for that will happen later on. + */ + stabilization_data_to_mat4(pixel_aspect, + pivot, + translation, + tmp_scale, + angle, + mat); /* Investigate the transformed border lines for this frame; * find out, where it cuts the original frame. */ - 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_v2_v2(a, points[i]); - copy_v2_v2(b, points[(i + 1) % 4]); - a[2] = b[2] = 0.0f; - - 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 rot_dx[4][2] = {{1.0f, 0.0f}, - {0.0f, -1.0f}, - {-1.0f, 0.0f}, - {0.0f, 1.0f}}; - const float rot_dy[4][2] = {{0.0f, 1.0f}, - {1.0f, 0.0f}, - {0.0f, -1.0f}, - {-1.0f, 0.0f}}; - - float dx = translation[0] * rot_dx[j][0] + - translation[1] * rot_dx[j][1], - dy = translation[0] * rot_dy[j][0] + - translation[1] * rot_dy[j][1]; - - float w, h, E, F, G, H, I, J, K, S; - - if (j % 2) { - w = (float)size / 2.0f; - h = image_aspect*size / 2.0f; - } - else { - w = image_aspect*size / 2.0f; - h = (float)size / 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 = (dx * I + dy * J + K) / (-w * I - h * J); - - scale = min_ff(scale, S); + for (int edge_index = 0; edge_index < 4; edge_index++) { + /* Calculate coordinates of stabilized frame edge points. + * Use matrix multiplication here so we operate in homogeneous + * coordinates. + */ + float stable_edge_p1[3], stable_edge_p2[3]; + copy_v2_v2(stable_edge_p1, points[edge_index]); + copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]); + stable_edge_p1[2] = stable_edge_p2[2] = 0.0f; + mul_m4_v3(mat, stable_edge_p1); + mul_m4_v3(mat, stable_edge_p2); + /* Now we iterate over all original frame corners (we call them + * 'point' here) to see if there's black area between stabilized + * frame edge and original point. + */ + for (int point_index = 0; point_index < 4; point_index++) { + const float point[3] = {points[point_index][0], + points[point_index][1], + 0.0f}; + /* Calculate vector which goes from first edge point to + * second one. + */ + float stable_edge_vec[3]; + sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1); + /* Calculate vector which connects current frame point to + * first edge point. + */ + float point_to_edge_start_vec[3]; + sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1); + /* Use this two vectors to check whether frame point is inside + * of the stabilized frame or not. + * If the point is inside, there is no black area happening + * and no scaling required for it. + */ + if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) { + /* We are scaling around motion-compensated pivot point. */ + float scale_pivot[2]; + add_v2_v2v2(scale_pivot, pivot, translation); + /* Calculate line which goes via `point` and parallel to + * the stabilized frame edge. This line is coming via + * `point` and `point2` at the end. + */ + float point2[2]; + add_v2_v2v2(point2, point, stable_edge_vec); + /* Calculate actual distance between pivot point and + * the stabilized frame edge. Then calculate distance + * between pivot point and line which goes via actual + * corner and is parallel to the edge. + * + * Dividing one by another will give us required scale + * factor to get rid of black areas. + */ + float real_dist = dist_to_line_v2(scale_pivot, + stable_edge_p1, + stable_edge_p2); + float required_dist = dist_to_line_v2(scale_pivot, + point, + point2); + const float S = required_dist / real_dist; + scale = max_ff(scale, S); } } } } - - stab->scale = scale; - if (stab->maxscale > 0.0f) { - stab->scale = max_ff(stab->scale, 1.0f / stab->maxscale); + scale = min_ff(scale, stab->maxscale); } + use_values_from_fcurves(ctx, false); + + return scale; } @@ -1218,19 +1396,14 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, * turns out to be tricky, hard to maintain and generally not worth the * effort. Thus we'll re-initialize on every frame. */ -static StabContext *init_stabilizer(MovieClip *clip, int width, int height) +static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect) { - MovieTracking *tracking = &clip->tracking; - MovieTrackingStabilization *stab = &tracking->stabilization; - float pixel_aspect = tracking->camera.pixel_aspect; - float aspect = (float)width * pixel_aspect / height; - int size = height; - StabContext *ctx = initialize_stabilization_working_context(clip); BLI_assert(ctx != NULL); initialize_all_tracks(ctx, aspect); - if (stab->flag & TRACKING_AUTOSCALE) { - stabilization_determine_safe_image_area(ctx, size, aspect); + if (ctx->stab->flag & TRACKING_AUTOSCALE) { + ctx->stab->scale = 1.0; + ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect); } /* By default, just use values for the global current frame. */ use_values_from_fcurves(ctx, false); @@ -1275,9 +1448,10 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, float pixel_aspect = tracking->camera.pixel_aspect; float aspect = (float)width * pixel_aspect / height; int size = height; + float pivot[2]; if (enabled) { - ctx = init_stabilizer(clip, width, height); + ctx = init_stabilizer(clip, size, aspect); } if (enabled && @@ -1285,6 +1459,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, framenr, aspect, translation, + pivot, angle, &scale_step)) { @@ -1295,8 +1470,15 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, do_compensate, scale_step, translation, + pivot, scale, angle); + compensate_rotation_center(size, + aspect, + *angle, + *scale, + pivot, + translation); } else { zero_v2(translation); @@ -1426,47 +1608,30 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip, void BKE_tracking_stabilization_data_to_mat4(int buffer_width, int buffer_height, float pixel_aspect, - float translation[2], float scale, float angle, - float mat[4][4]) + float translation[2], + float scale, + float angle, + float r_mat[4][4]) { - float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], - pivot_mat[4][4], inv_pivot_mat[4][4], - aspect_mat[4][4], inv_aspect_mat[4][4]; - float scale_vector[3] = {scale, scale, 1.0f}; - - float pivot[2]; /* XXX this should be a parameter, it is part of the stabilization data */ - - /* Use the motion compensated image center as rotation center. - * This is not 100% correct, but reflects the way the rotation data was - * measured. Actually we'd need a way to find a good pivot, and use that - * both for averaging and for compensation. + /* Since we cannot receive the real pivot point coordinates (API limitation), + * we perform the rotation/scale around the center of frame. + * Then we correct by an additional shift, which was calculated in + * compensate_rotation_center() and "sneaked in" as additional offset + * in the translation parameter. This works, since translation needs to be + * applied after rotation/scale anyway. Thus effectively the image gets + * rotated around the desired pivot point */ /* TODO(sergey) pivot shouldn't be calculated here, rather received * as a parameter. */ - pivot[0] = pixel_aspect * buffer_width / 2.0f - translation[0]; - pivot[1] = (float)buffer_height / 2.0f - translation[1]; - - unit_m4(translation_mat); - unit_m4(rotation_mat); - unit_m4(scale_mat); - unit_m4(aspect_mat); - unit_m4(pivot_mat); - unit_m4(inv_pivot_mat); - - /* aspect ratio correction matrix */ - aspect_mat[0][0] /= pixel_aspect; - invert_m4_m4(inv_aspect_mat, aspect_mat); - - add_v2_v2(pivot_mat[3], pivot); - sub_v2_v2(inv_pivot_mat[3], pivot); - - 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_m4_series(mat, aspect_mat, translation_mat, - pivot_mat, scale_mat, rotation_mat, inv_pivot_mat, - inv_aspect_mat); + float pivot[2]; + pivot[0] = 0.5f * pixel_aspect * buffer_width; + pivot[1] = 0.5f * buffer_height; + /* Compose transformation matrix. */ + stabilization_data_to_mat4(pixel_aspect, + pivot, + translation, + scale, + angle, + r_mat); } |