/* Calculate factor of a scale, which will eliminate black areas * appearing on the frame caused by frame translation. */ static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, int width, int height) { float firstmedian[2]; MovieTrackingStabilization *stab = &tracking->stabilization; float aspect = tracking->camera.pixel_aspect; /* Early output if stabilization data is already up-to-date. */ if (stab->ok) return stab->scale; /* See comment in BKE_tracking_stabilization_data_get about first frame. */ if (stabilization_median_point_get(tracking, 1, firstmedian)) { int sfra = INT_MAX, efra = INT_MIN, cfra; float scale = 1.0f; MovieTrackingTrack *track; stab->scale = 1.0f; /* Calculate frame range of tracks used for stabilization. */ track = tracking->tracks.first; while (track) { if (track->flag & TRACK_USE_2D_STAB || ((stab->flag & TRACKING_STABILIZE_ROTATION) && track == stab->rot_track)) { sfra = min_ii(sfra, track->markers[0].framenr); efra = max_ii(efra, track->markers[track->markersnr - 1].framenr); } track = track->next; } /* For every frame we calculate scale factor needed to eliminate black * area and choose largest scale factor as final one. */ for (cfra = sfra; cfra <= efra; cfra++) { float median[2]; float translation[2], angle, tmp_scale; int i; float mat[4][4]; float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}}; float si, co; stabilization_median_point_get(tracking, cfra, median); stabilization_calculate_data(tracking, cfra, width, height, firstmedian, median, translation, &tmp_scale, &angle); BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, 1.0f, angle, mat); si = sinf(angle); co = cosf(angle); for (i = 0; i < 4; i++) { int j; float a[3] = {0.0f, 0.0f, 0.0f}, b[3] = {0.0f, 0.0f, 0.0f}; copy_v3_v3(a, points[i]); copy_v3_v3(b, points[(i + 1) % 4]); mul_m4_v3(mat, a); mul_m4_v3(mat, b); for (j = 0; j < 4; j++) { float point[3] = {points[j][0], points[j][1], 0.0f}; float v1[3], v2[3]; sub_v3_v3v3(v1, b, a); sub_v3_v3v3(v2, point, a); if (cross_v2v2(v1, v2) >= 0.0f) { const float rotDx[4][2] = {{1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}, {0.0f, 1.0f}}; const float rotDy[4][2] = {{0.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}}; float dx = translation[0] * rotDx[j][0] + translation[1] * rotDx[j][1], dy = translation[0] * rotDy[j][0] + translation[1] * rotDy[j][1]; float w, h, E, F, G, H, I, J, K, S; if (j % 2) { w = (float)height / 2.0f; h = (float)width / 2.0f; } else { w = (float)width / 2.0f; h = (float)height / 2.0f; } E = -w * co + h * si; F = -h * co - w * si; if ((i % 2) == (j % 2)) { G = -w * co - h * si; H = h * co - w * si; } else { G = w * co + h * si; H = -h * co + w * si; } I = F - H; J = G - E; K = G * F - E * H; S = (-w * I - h * J) / (dx * I + dy * J + K); scale = max_ff(scale, S); } } } } stab->scale = scale; if (stab->maxscale > 0.0f) stab->scale = min_ff(stab->scale, stab->maxscale); } else { stab->scale = 1.0f; } stab->ok = true; return stab->scale; }
void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) { MovieClip *clip = ED_space_clip_get_clip(sc); Scene *scene = CTX_data_scene(C); ImBuf *ibuf = NULL; int width, height; float zoomx, zoomy; ED_space_clip_get_size(sc, &width, &height); ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy); /* if no clip, nothing to do */ if (!clip) { ED_region_grid_draw(ar, zoomx, zoomy); return; } if (sc->flag & SC_SHOW_STABLE) { float smat[4][4], ismat[4][4]; ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc, &sc->scale, &sc->angle); if (ibuf) { float translation[2]; float aspect = clip->tracking.camera.pixel_aspect; if (width != ibuf->x) mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x); else copy_v2_v2(translation, sc->loc); BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, sc->scale, sc->angle, sc->stabmat); unit_m4(smat); smat[0][0] = 1.0f / width; smat[1][1] = 1.0f / height; invert_m4_m4(ismat, smat); mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL); } } else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) { ibuf = ED_space_clip_get_buffer(sc); zero_v2(sc->loc); sc->scale = 1.0f; unit_m4(sc->stabmat); unit_m4(sc->unistabmat); } if (ibuf) { draw_movieclip_buffer(C, sc, ar, ibuf, width, height, zoomx, zoomy); IMB_freeImBuf(ibuf); } else if (sc->flag & SC_MUTE_FOOTAGE) { draw_movieclip_muted(ar, width, height, zoomx, zoomy); } else { ED_region_grid_draw(ar, zoomx, zoomy); } if (width && height) { draw_stabilization_border(sc, ar, width, height, zoomx, zoomy); draw_tracking_tracks(sc, scene, ar, clip, width, height, zoomx, zoomy); draw_distortion(sc, ar, clip, width, height, zoomx, zoomy); } }
/* Stabilize given image buffer using stabilization data for * a specified frame number. * * NOTE: frame number should be in clip space, not scene space */ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle) { float tloc[2], tscale, tangle; MovieTrackingStabilization *stab = &tracking->stabilization; ImBuf *tmpibuf; int width = ibuf->x, height = ibuf->y; float aspect = tracking->camera.pixel_aspect; float mat[4][4]; int j, filter = tracking->stabilization.filter; void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL; int ibuf_flags; if (translation) copy_v2_v2(tloc, translation); if (scale) tscale = *scale; /* Perform early output if no stabilization is used. */ if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) { if (translation) zero_v2(translation); if (scale) *scale = 1.0f; if (angle) *angle = 0.0f; return ibuf; } /* Allocate frame for stabilization result. */ ibuf_flags = 0; if (ibuf->rect) ibuf_flags |= IB_rect; if (ibuf->rect_float) ibuf_flags |= IB_rectfloat; tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags); /* Calculate stabilization matrix. */ BKE_tracking_stabilization_data_get(tracking, framenr, width, height, tloc, &tscale, &tangle); BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat); invert_m4(mat); if (filter == TRACKING_FILTER_NEAREST) interpolation = nearest_interpolation; else if (filter == TRACKING_FILTER_BILINEAR) interpolation = bilinear_interpolation; else if (filter == TRACKING_FILTER_BICUBIC) interpolation = bicubic_interpolation; else /* fallback to default interpolation method */ interpolation = nearest_interpolation; /* This function is only used for display in clip editor and * sequencer only, which would only benefit of using threads * here. * * But need to keep an eye on this if the function will be * used in other cases. */ #pragma omp parallel for if (tmpibuf->y > 128) for (j = 0; j < tmpibuf->y; j++) { int i; for (i = 0; i < tmpibuf->x; i++) { float vec[3] = {i, j, 0.0f}; mul_v3_m4v3(vec, mat, vec); interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j); } } if (tmpibuf->rect_float) tmpibuf->userflags |= IB_RECT_INVALID; if (translation) copy_v2_v2(translation, tloc); if (scale) *scale = tscale; if (angle) *angle = tangle; return tmpibuf; }