Blender V4.5
tracking_solver.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <climits>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_movieclip_types.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_vector.h"
20#include "BLI_string.h"
21
22#include "BLT_translation.hh"
23
24#include "BKE_fcurve.hh"
25#include "BKE_movieclip.h"
26#include "BKE_tracking.h"
27
28#include "RNA_prototypes.hh"
29
30#include "libmv-capi.h"
31#include "tracking_private.h"
32
55
63
64/* Create new libmv Tracks structure from blender's tracks list. */
65static libmv_Tracks *libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
66{
67 int tracknr = 0;
68 MovieTrackingTrack *track;
70
71 track = static_cast<MovieTrackingTrack *>(tracksbase->first);
72 while (track) {
73 const FCurve *weight_fcurve = id_data_find_fcurve(
74 &clip->id, track, &RNA_MovieTrackingTrack, "weight", 0, nullptr);
75
76 for (int a = 0; a < track->markersnr; a++) {
77 MovieTrackingMarker *marker = &track->markers[a];
78
79 if ((marker->flag & MARKER_DISABLED) == 0) {
80 float weight = track->weight;
81
82 if (weight_fcurve) {
83 int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
84 weight = evaluate_fcurve(weight_fcurve, scene_framenr);
85 }
86
88 marker->framenr,
89 tracknr,
90 (marker->pos[0] + track->offset[0]) * width,
91 (marker->pos[1] + track->offset[1]) * height,
92 weight);
93 }
94 }
95
96 track = track->next;
97 tracknr++;
98 }
99
100 return tracks;
101}
102
103/* Retrieve refined camera intrinsics from libmv to blender. */
105 MovieTracking *tracking)
106{
107 libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
109 libmv_reconstruction);
110
111 libmv_CameraIntrinsicsOptions camera_intrinsics_options;
112 libmv_cameraIntrinsicsExtractOptions(libmv_intrinsics, &camera_intrinsics_options);
113
114 tracking_trackingCameraFromIntrinscisOptions(tracking, &camera_intrinsics_options);
115}
116
117/* Retrieve reconstructed tracks from libmv to blender.
118 * Actually, this also copies reconstructed cameras
119 * from libmv to movie clip datablock.
120 */
122 MovieTracking *tracking)
123{
124 libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
125 bool ok = true;
126 bool origin_set = false;
127 int sfra = context->sfra, efra = context->efra;
128 float imat[4][4];
129
130 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking,
131 context->object_name);
132 MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
133
134 unit_m4(imat);
135
136 {
137 int track_index = 0;
138 LISTBASE_FOREACH_INDEX (MovieTrackingTrack *, track, &tracking_object->tracks, track_index) {
139 double pos[3];
140
141 if (libmv_reprojectionPointForTrack(libmv_reconstruction, track_index, pos)) {
142 track->bundle_pos[0] = pos[0];
143 track->bundle_pos[1] = pos[1];
144 track->bundle_pos[2] = pos[2];
145
146 track->flag |= TRACK_HAS_BUNDLE;
147 track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, track_index);
148 }
149 else {
150 track->flag &= ~TRACK_HAS_BUNDLE;
151 ok = false;
152
153 printf("Unable to reconstruct position for track #%d '%s'\n", track_index, track->name);
154 }
155 }
156 }
157
158 if (reconstruction->cameras) {
159 MEM_freeN(reconstruction->cameras);
160 }
161
162 reconstruction->camnr = 0;
163 reconstruction->cameras = nullptr;
164
166 (efra - sfra + 1), "temp reconstructed camera");
167
168 for (int a = sfra; a <= efra; a++) {
169 double matd[4][4];
170
171 if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
172 float mat[4][4];
173 float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);
174
175 /* TODO(sergey): Use transpose utility. */
176 for (int i = 0; i < 4; i++) {
177 for (int j = 0; j < 4; j++) {
178 mat[i][j] = matd[i][j];
179 }
180 }
181
182 /* Ensure first camera has got zero rotation and transform.
183 * This is essential for object tracking to work -- this way
184 * we'll always know object and environment are properly
185 * oriented.
186 *
187 * There's one weak part tho, which is requirement object
188 * motion starts at the same frame as camera motion does,
189 * otherwise that;' be a Russian roulette whether object is
190 * aligned correct or not.
191 */
192 if (!origin_set) {
193 invert_m4_m4(imat, mat);
194 unit_m4(mat);
195 origin_set = true;
196 }
197 else {
198 mul_m4_m4m4(mat, imat, mat);
199 }
200
201 MovieReconstructedCamera *reconstructed_camera =
202 &reconstructed_cameras[reconstruction->camnr];
203 copy_m4_m4(reconstructed_camera->mat, mat);
204 reconstructed_camera->framenr = a;
205 reconstructed_camera->error = error;
206 reconstruction->camnr++;
207 }
208 else {
209 ok = false;
210 printf("No camera for frame %d\n", a);
211 }
212 }
213
214 if (reconstruction->camnr) {
215 const size_t size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
216 reconstruction->cameras = MEM_calloc_arrayN<MovieReconstructedCamera>(reconstruction->camnr,
217 "reconstructed camera");
218 memcpy(reconstruction->cameras, reconstructed_cameras, size);
219 }
220
221 if (origin_set) {
222 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
223 if (track->flag & TRACK_HAS_BUNDLE) {
224 mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
225 }
226 }
227 }
228
229 MEM_freeN(reconstructed_cameras);
230
231 return ok;
232}
233
234/* Retrieve all the libmv data from context to blender's side data blocks. */
236{
237 /* take the intrinsics back from libmv */
238 reconstruct_retrieve_libmv_intrinsics(context, tracking);
239
240 return reconstruct_retrieve_libmv_tracks(context, tracking);
241}
242
243/* Convert blender's refinement flags to libmv's. */
245 MovieTrackingObject *tracking_object)
246{
247 const int refine = tracking->settings.refine_camera_intrinsics;
248 int flags = 0;
249
250 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
251 return 0;
252 }
253
254 if (refine & REFINE_FOCAL_LENGTH) {
256 }
257
258 if (refine & REFINE_PRINCIPAL_POINT) {
260 }
261
262 if (refine & REFINE_RADIAL_DISTORTION) {
264 }
265
266 if (refine & REFINE_TANGENTIAL_DISTORTION) {
268 }
269
270 return flags;
271}
272
273/* Count tracks which has markers at both of keyframes. */
275{
276 const int frame1 = tracking_object->keyframe1, frame2 = tracking_object->keyframe2;
277
278 int tot = 0;
279 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
282 tot++;
283 }
284 }
285 }
286
287 return tot;
288}
289
291 MovieTrackingObject *tracking_object,
292 char *error_msg,
293 int error_size)
294{
296 /* TODO: check for number of tracks? */
297 return true;
298 }
300 /* automatic keyframe selection does not require any pre-process checks */
301 if (reconstruct_count_tracks_on_both_keyframes(tracking_object) < 8) {
302 BLI_strncpy(error_msg,
303 N_("At least 8 common tracks on both keyframes are needed for reconstruction"),
304 error_size);
305
306 return false;
307 }
308 }
309
310#ifndef WITH_LIBMV
311 BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size);
312 return false;
313#endif
314
315 return true;
316}
317
319 MovieClip *clip,
320 MovieTrackingObject *tracking_object,
321 int keyframe1,
322 int keyframe2,
323 int width,
324 int height)
325{
326 MovieTracking *tracking = &clip->tracking;
328 "MovieReconstructContext data");
329 const float aspy = 1.0f / tracking->camera.pixel_aspect;
330 const int num_tracks = BLI_listbase_count(&tracking_object->tracks);
331 int sfra = INT_MAX, efra = INT_MIN;
332
333 STRNCPY(context->object_name, tracking_object->name);
334 context->motion_flag = tracking->settings.motion_flag;
335
336 context->select_keyframes = (tracking->settings.reconstruction_flag &
338
340 tracking, width, height, &context->camera_intrinsics_options);
341
342 context->tracks_map = tracks_map_new(context->object_name, num_tracks);
343
344 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
345 int first = 0, last = track->markersnr - 1;
346 MovieTrackingMarker *first_marker = &track->markers[0];
347 MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
348
349 /* find first not-disabled marker */
350 while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
351 first++;
352 first_marker++;
353 }
354
355 /* find last not-disabled marker */
356 while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
357 last--;
358 last_marker--;
359 }
360
361 if (first <= track->markersnr - 1) {
362 sfra = min_ii(sfra, first_marker->framenr);
363 }
364
365 if (last >= 0) {
366 efra = max_ii(efra, last_marker->framenr);
367 }
368
369 tracks_map_insert(context->tracks_map, track);
370 }
371
372 context->sfra = sfra;
373 context->efra = efra;
374
375 context->tracks = libmv_tracks_new(clip, &tracking_object->tracks, width, height * aspy);
376 context->keyframe1 = keyframe1;
377 context->keyframe2 = keyframe2;
378 context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, tracking_object);
379
380 context->error_message[0] = '\0';
381
382 return context;
383}
384
386 const char *error_message)
387{
388 if (context->error_message[0]) {
389 /* Only keep initial error message, the rest are inducted ones. */
390 return;
391 }
392 STRNCPY(context->error_message, error_message);
393}
394
396{
397 return context->error_message;
398}
399
401{
402 if (context->reconstruction) {
403 libmv_reconstructionDestroy(context->reconstruction);
404 }
405
406 libmv_tracksDestroy(context->tracks);
407
408 tracks_map_free(context->tracks_map);
409
410 MEM_freeN(context);
411}
412
413/* Callback which is called from libmv side to update progress in the interface. */
414static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
415{
416 ReconstructProgressData *progressdata = static_cast<ReconstructProgressData *>(customdata);
417
418 if (progressdata->progress) {
419 *progressdata->progress = progress;
420 *progressdata->do_update = true;
421 }
422
424 progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
425}
426
427/* Fill in reconstruction options structure from reconstruction context. */
430{
431 reconstruction_options->select_keyframes = context->select_keyframes;
432
433 reconstruction_options->keyframe1 = context->keyframe1;
434 reconstruction_options->keyframe2 = context->keyframe2;
435
436 reconstruction_options->refine_intrinsics = context->refine_flags;
437}
438
440 bool *stop,
441 bool *do_update,
442 float *progress,
443 char *stats_message,
444 int message_size)
445{
446 float error;
447
448 ReconstructProgressData progressdata;
449
450 libmv_ReconstructionOptions reconstruction_options;
451
452 progressdata.stop = stop;
453 progressdata.do_update = do_update;
454 progressdata.progress = progress;
455 progressdata.stats_message = stats_message;
456 progressdata.message_size = message_size;
457
458 reconstructionOptionsFromContext(&reconstruction_options, context);
459
460 if (context->motion_flag & TRACKING_MOTION_MODAL) {
461 context->reconstruction = libmv_solveModal(context->tracks,
462 &context->camera_intrinsics_options,
463 &reconstruction_options,
465 &progressdata);
466 }
467 else {
468 context->reconstruction = libmv_solveReconstruction(context->tracks,
469 &context->camera_intrinsics_options,
470 &reconstruction_options,
472 &progressdata);
473
474 if (context->select_keyframes) {
475 /* store actual keyframes used for reconstruction to update them in the interface later */
476 context->keyframe1 = reconstruction_options.keyframe1;
477 context->keyframe2 = reconstruction_options.keyframe2;
478 }
479 }
480
481 error = libmv_reprojectionError(context->reconstruction);
482
483 context->reprojection_error = error;
484}
485
487{
488 if (!libmv_reconstructionIsValid(context->reconstruction)) {
490 context, "Failed to solve the motion: most likely there are no good keyframes");
491 return false;
492 }
493
494 tracks_map_merge(context->tracks_map, tracking);
496
497 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking,
498 context->object_name);
499 MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
500
501 /* update keyframe in the interface */
502 if (context->select_keyframes) {
503 tracking_object->keyframe1 = context->keyframe1;
504 tracking_object->keyframe2 = context->keyframe2;
505 }
506
507 reconstruction->error = context->reprojection_error;
508 reconstruction->flag |= TRACKING_RECONSTRUCTED;
509
510 if (!reconstruct_retrieve_libmv(context, tracking)) {
511 return false;
512 }
513
514 return true;
515}
516
518 MovieTrackingReconstruction *reconstruction,
519 const float scale[3])
520{
521 float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
522
523 if (reconstruction->camnr > 0) {
524 mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
525 }
526
527 for (int i = 0; i < reconstruction->camnr; i++) {
528 MovieReconstructedCamera *camera = &reconstruction->cameras[i];
529 mul_v3_v3(camera->mat[3], scale);
530 sub_v3_v3(camera->mat[3], first_camera_delta);
531 }
532
533 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
534 if (track->flag & TRACK_HAS_BUNDLE) {
535 mul_v3_v3(track->bundle_pos, scale);
536 sub_v3_v3(track->bundle_pos, first_camera_delta);
537 }
538 }
539}
540
542{
543 LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
544 tracking_scale_reconstruction(&object->tracks, &object->reconstruction, scale);
545 }
546}
float evaluate_fcurve(const FCurve *fcu, float evaltime)
FCurve * id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr)
struct MovieTrackingObject * BKE_tracking_object_get_named(struct MovieTracking *tracking, const char *name)
Definition tracking.cc:1965
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:713
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking)
Definition tracking.cc:3438
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void unit_m4(float m[4][4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
@ REFINE_PRINCIPAL_POINT
@ REFINE_TANGENTIAL_DISTORTION
@ REFINE_RADIAL_DISTORTION
@ REFINE_FOCAL_LENGTH
@ TRACKING_RECONSTRUCTED
@ MARKER_DISABLED
@ TRACKING_USE_KEYFRAME_SELECTION
@ TRACKING_MOTION_MODAL
@ TRACKING_OBJECT_CAMERA
@ TRACK_HAS_BUNDLE
Read Guarded memory(de)allocation.
bool stop
Definition WM_types.hh:1016
bool do_update
Definition WM_types.hh:1008
float progress
Definition WM_types.hh:1019
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
uint pos
#define printf(...)
#define MAX_NAME
void libmv_cameraIntrinsicsExtractOptions(const libmv_CameraIntrinsics *libmv_intrinsics, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
struct libmv_CameraIntrinsics libmv_CameraIntrinsics
libmv_Reconstruction * libmv_solveModal(const libmv_Tracks *libmv_tracks, const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, const libmv_ReconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
double libmv_reprojectionErrorForImage(const libmv_Reconstruction *libmv_reconstruction, int image)
double libmv_reprojectionError(const libmv_Reconstruction *libmv_reconstruction)
void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction)
int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction)
int libmv_reprojectionCameraForImage(const libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4])
libmv_CameraIntrinsics * libmv_reconstructionExtractIntrinsics(libmv_Reconstruction *libmv_reconstruction)
int libmv_reprojectionPointForTrack(const libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
libmv_Reconstruction * libmv_solveReconstruction(const libmv_Tracks *libmv_tracks, const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, libmv_ReconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
double libmv_reprojectionErrorForTrack(const libmv_Reconstruction *libmv_reconstruction, int track)
@ LIBMV_REFINE_TANGENTIAL_DISTORTION
@ LIBMV_REFINE_FOCAL_LENGTH
@ LIBMV_REFINE_RADIAL_DISTORTION
@ LIBMV_REFINE_PRINCIPAL_POINT
struct libmv_Tracks libmv_Tracks
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void error(const char *str)
void * first
struct MovieTracking tracking
libmv_CameraIntrinsicsOptions camera_intrinsics_options
libmv_Reconstruction * reconstruction
MovieTrackingReconstruction reconstruction
struct MovieReconstructedCamera * cameras
MovieTrackingMarker * markers
struct MovieTrackingTrack * next
MovieTrackingCamera camera
MovieTrackingSettings settings
libmv_Tracks * libmv_tracksNew(void)
Definition stub.cc:84
void libmv_tracksDestroy(libmv_Tracks *)
Definition stub.cc:96
void libmv_tracksInsert(libmv_Tracks *, int, int, double, double, double)
Definition stub.cc:88
i
Definition text_draw.cc:230
ListBase tracks
Definition tracking.cc:70
static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
MovieReconstructContext * BKE_tracking_reconstruction_context_new(MovieClip *clip, MovieTrackingObject *tracking_object, int keyframe1, int keyframe2, int width, int height)
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, bool *stop, bool *do_update, float *progress, char *stats_message, int message_size)
void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
static libmv_Tracks * libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
void BKE_tracking_reconstruction_report_error_message(MovieReconstructContext *context, const char *error_message)
static int reconstruct_count_tracks_on_both_keyframes(MovieTrackingObject *tracking_object)
const char * BKE_tracking_reconstruction_error_message_get(const MovieReconstructContext *context)
static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
static int reconstruct_retrieve_libmv(MovieReconstructContext *context, MovieTracking *tracking)
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, MovieTrackingObject *tracking_object)
static void tracking_scale_reconstruction(ListBase *tracksbase, MovieTrackingReconstruction *reconstruction, const float scale[3])
bool BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObject *tracking_object, char *error_msg, int error_size)
static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *reconstruction_options, MovieReconstructContext *context)
void tracks_map_free(TracksMap *map)
void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking, const int calibration_width, const int calibration_height, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track)
void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
TracksMap * tracks_map_new(const char *object_name, int num_tracks)
void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
#define N_(msgid)