Blender V5.0
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_utf8.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) {
303 error_msg,
304 N_("At least 8 common tracks on both keyframes are needed for reconstruction"),
305 error_size);
306
307 return false;
308 }
309 }
310
311#ifndef WITH_LIBMV
313 error_msg, N_("Blender is compiled without motion tracking library"), error_size);
314 return false;
315#endif
316
317 return true;
318}
319
321 MovieClip *clip,
322 MovieTrackingObject *tracking_object,
323 int keyframe1,
324 int keyframe2,
325 int width,
326 int height)
327{
328 MovieTracking *tracking = &clip->tracking;
330 "MovieReconstructContext data");
331 const float aspy = 1.0f / tracking->camera.pixel_aspect;
332 const int num_tracks = BLI_listbase_count(&tracking_object->tracks);
333 int sfra = INT_MAX, efra = INT_MIN;
334
335 STRNCPY_UTF8(context->object_name, tracking_object->name);
336 context->motion_flag = tracking->settings.motion_flag;
337
338 context->select_keyframes = (tracking->settings.reconstruction_flag &
340
342 tracking, width, height, &context->camera_intrinsics_options);
343
344 context->tracks_map = tracks_map_new(context->object_name, num_tracks);
345
346 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
347 int first = 0, last = track->markersnr - 1;
348 MovieTrackingMarker *first_marker = &track->markers[0];
349 MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
350
351 /* find first not-disabled marker */
352 while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
353 first++;
354 first_marker++;
355 }
356
357 /* find last not-disabled marker */
358 while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
359 last--;
360 last_marker--;
361 }
362
363 if (first <= track->markersnr - 1) {
364 sfra = min_ii(sfra, first_marker->framenr);
365 }
366
367 if (last >= 0) {
368 efra = max_ii(efra, last_marker->framenr);
369 }
370
371 tracks_map_insert(context->tracks_map, track);
372 }
373
374 context->sfra = sfra;
375 context->efra = efra;
376
377 context->tracks = libmv_tracks_new(clip, &tracking_object->tracks, width, height * aspy);
378 context->keyframe1 = keyframe1;
379 context->keyframe2 = keyframe2;
380 context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, tracking_object);
381
382 context->error_message[0] = '\0';
383
384 return context;
385}
386
388 const char *error_message)
389{
390 if (context->error_message[0]) {
391 /* Only keep initial error message, the rest are inducted ones. */
392 return;
393 }
394 STRNCPY_UTF8(context->error_message, error_message);
395}
396
398{
399 return context->error_message;
400}
401
403{
404 if (context->reconstruction) {
405 libmv_reconstructionDestroy(context->reconstruction);
406 }
407
408 libmv_tracksDestroy(context->tracks);
409
410 tracks_map_free(context->tracks_map);
411
412 MEM_freeN(context);
413}
414
415/* Callback which is called from libmv side to update progress in the interface. */
416static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
417{
418 ReconstructProgressData *progressdata = static_cast<ReconstructProgressData *>(customdata);
419
420 if (progressdata->progress) {
421 *progressdata->progress = progress;
422 *progressdata->do_update = true;
423 }
424
426 progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
427}
428
429/* Fill in reconstruction options structure from reconstruction context. */
432{
433 reconstruction_options->select_keyframes = context->select_keyframes;
434
435 reconstruction_options->keyframe1 = context->keyframe1;
436 reconstruction_options->keyframe2 = context->keyframe2;
437
438 reconstruction_options->refine_intrinsics = context->refine_flags;
439}
440
442 bool *stop,
443 bool *do_update,
444 float *progress,
445 char *stats_message,
446 int message_size)
447{
448 float error;
449
450 ReconstructProgressData progressdata;
451
452 libmv_ReconstructionOptions reconstruction_options;
453
454 progressdata.stop = stop;
455 progressdata.do_update = do_update;
456 progressdata.progress = progress;
457 progressdata.stats_message = stats_message;
458 progressdata.message_size = message_size;
459
460 reconstructionOptionsFromContext(&reconstruction_options, context);
461
462 if (context->motion_flag & TRACKING_MOTION_MODAL) {
463 context->reconstruction = libmv_solveModal(context->tracks,
464 &context->camera_intrinsics_options,
465 &reconstruction_options,
467 &progressdata);
468 }
469 else {
470 context->reconstruction = libmv_solveReconstruction(context->tracks,
471 &context->camera_intrinsics_options,
472 &reconstruction_options,
474 &progressdata);
475
476 if (context->select_keyframes) {
477 /* store actual keyframes used for reconstruction to update them in the interface later */
478 context->keyframe1 = reconstruction_options.keyframe1;
479 context->keyframe2 = reconstruction_options.keyframe2;
480 }
481 }
482
483 error = libmv_reprojectionError(context->reconstruction);
484
485 context->reprojection_error = error;
486}
487
489{
490 if (!libmv_reconstructionIsValid(context->reconstruction)) {
492 context, "Failed to solve the motion: most likely there are no good keyframes");
493 return false;
494 }
495
496 tracks_map_merge(context->tracks_map, tracking);
498
499 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking,
500 context->object_name);
501 MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
502
503 /* update keyframe in the interface */
504 if (context->select_keyframes) {
505 tracking_object->keyframe1 = context->keyframe1;
506 tracking_object->keyframe2 = context->keyframe2;
507 }
508
509 reconstruction->error = context->reprojection_error;
510 reconstruction->flag |= TRACKING_RECONSTRUCTED;
511
512 if (!reconstruct_retrieve_libmv(context, tracking)) {
513 return false;
514 }
515
516 return true;
517}
518
520 MovieTrackingReconstruction *reconstruction,
521 const float scale[3])
522{
523 float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
524
525 if (reconstruction->camnr > 0) {
526 mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
527 }
528
529 for (int i = 0; i < reconstruction->camnr; i++) {
530 MovieReconstructedCamera *camera = &reconstruction->cameras[i];
531 mul_v3_v3(camera->mat[3], scale);
532 sub_v3_v3(camera->mat[3], first_camera_delta);
533 }
534
535 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
536 if (track->flag & TRACK_HAS_BUNDLE) {
537 mul_v3_v3(track->bundle_pos, scale);
538 sub_v3_v3(track->bundle_pos, first_camera_delta);
539 }
540 }
541}
542
544{
545 LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
546 tracking_scale_reconstruction(&object->tracks, &object->reconstruction, scale);
547 }
548}
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:1966
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:714
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking)
Definition tracking.cc:3439
#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])
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
#define MAX_NAME
Definition DNA_defs.h:50
@ REFINE_PRINCIPAL_POINT
@ REFINE_TANGENTIAL_DISTORTION
@ REFINE_RADIAL_DISTORTION
@ REFINE_FOCAL_LENGTH
@ TRACK_HAS_BUNDLE
@ TRACKING_USE_KEYFRAME_SELECTION
@ TRACKING_MOTION_MODAL
@ TRACKING_RECONSTRUCTED
@ MARKER_DISABLED
@ TRACKING_OBJECT_CAMERA
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
uint pos
#define printf(...)
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:71
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)