Blender V4.3
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#include "BLI_utildefines.h"
22
23#include "BLT_translation.hh"
24
25#include "BKE_fcurve.hh"
26#include "BKE_movieclip.h"
27#include "BKE_tracking.h"
28
29#include "RNA_prototypes.hh"
30
31#include "libmv-capi.h"
32#include "tracking_private.h"
33
56
64
65/* Create new libmv Tracks structure from blender's tracks list. */
66static libmv_Tracks *libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
67{
68 int tracknr = 0;
69 MovieTrackingTrack *track;
71
72 track = static_cast<MovieTrackingTrack *>(tracksbase->first);
73 while (track) {
74 const FCurve *weight_fcurve = id_data_find_fcurve(
75 &clip->id, track, &RNA_MovieTrackingTrack, "weight", 0, nullptr);
76
77 for (int a = 0; a < track->markersnr; a++) {
78 MovieTrackingMarker *marker = &track->markers[a];
79
80 if ((marker->flag & MARKER_DISABLED) == 0) {
81 float weight = track->weight;
82
83 if (weight_fcurve) {
84 int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
85 weight = evaluate_fcurve(weight_fcurve, scene_framenr);
86 }
87
89 marker->framenr,
90 tracknr,
91 (marker->pos[0] + track->offset[0]) * width,
92 (marker->pos[1] + track->offset[1]) * height,
93 weight);
94 }
95 }
96
97 track = track->next;
98 tracknr++;
99 }
100
101 return tracks;
102}
103
104/* Retrieve refined camera intrinsics from libmv to blender. */
106 MovieTracking *tracking)
107{
108 libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
110 libmv_reconstruction);
111
112 libmv_CameraIntrinsicsOptions camera_intrinsics_options;
113 libmv_cameraIntrinsicsExtractOptions(libmv_intrinsics, &camera_intrinsics_options);
114
115 tracking_trackingCameraFromIntrinscisOptions(tracking, &camera_intrinsics_options);
116}
117
118/* Retrieve reconstructed tracks from libmv to blender.
119 * Actually, this also copies reconstructed cameras
120 * from libmv to movie clip datablock.
121 */
123 MovieTracking *tracking)
124{
125 libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
126 bool ok = true;
127 bool origin_set = false;
128 int sfra = context->sfra, efra = context->efra;
129 float imat[4][4];
130
131 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking,
132 context->object_name);
133 MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
134
135 unit_m4(imat);
136
137 {
138 int track_index = 0;
139 LISTBASE_FOREACH_INDEX (MovieTrackingTrack *, track, &tracking_object->tracks, track_index) {
140 double pos[3];
141
142 if (libmv_reprojectionPointForTrack(libmv_reconstruction, track_index, pos)) {
143 track->bundle_pos[0] = pos[0];
144 track->bundle_pos[1] = pos[1];
145 track->bundle_pos[2] = pos[2];
146
147 track->flag |= TRACK_HAS_BUNDLE;
148 track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, track_index);
149 }
150 else {
151 track->flag &= ~TRACK_HAS_BUNDLE;
152 ok = false;
153
154 printf("Unable to reconstruct position for track #%d '%s'\n", track_index, track->name);
155 }
156 }
157 }
158
159 if (reconstruction->cameras) {
160 MEM_freeN(reconstruction->cameras);
161 }
162
163 reconstruction->camnr = 0;
164 reconstruction->cameras = nullptr;
165
166 MovieReconstructedCamera *reconstructed_cameras = MEM_cnew_array<MovieReconstructedCamera>(
167 (efra - sfra + 1), "temp reconstructed camera");
168
169 for (int a = sfra; a <= efra; a++) {
170 double matd[4][4];
171
172 if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
173 float mat[4][4];
174 float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);
175
176 /* TODO(sergey): Use transpose utility. */
177 for (int i = 0; i < 4; i++) {
178 for (int j = 0; j < 4; j++) {
179 mat[i][j] = matd[i][j];
180 }
181 }
182
183 /* Ensure first camera has got zero rotation and transform.
184 * This is essential for object tracking to work -- this way
185 * we'll always know object and environment are properly
186 * oriented.
187 *
188 * There's one weak part tho, which is requirement object
189 * motion starts at the same frame as camera motion does,
190 * otherwise that;' be a Russian roulette whether object is
191 * aligned correct or not.
192 */
193 if (!origin_set) {
194 invert_m4_m4(imat, mat);
195 unit_m4(mat);
196 origin_set = true;
197 }
198 else {
199 mul_m4_m4m4(mat, imat, mat);
200 }
201
202 MovieReconstructedCamera *reconstructed_camera =
203 &reconstructed_cameras[reconstruction->camnr];
204 copy_m4_m4(reconstructed_camera->mat, mat);
205 reconstructed_camera->framenr = a;
206 reconstructed_camera->error = error;
207 reconstruction->camnr++;
208 }
209 else {
210 ok = false;
211 printf("No camera for frame %d\n", a);
212 }
213 }
214
215 if (reconstruction->camnr) {
216 const size_t size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
217 reconstruction->cameras = MEM_cnew_array<MovieReconstructedCamera>(reconstruction->camnr,
218 "reconstructed camera");
219 memcpy(reconstruction->cameras, reconstructed_cameras, size);
220 }
221
222 if (origin_set) {
223 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
224 if (track->flag & TRACK_HAS_BUNDLE) {
225 mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
226 }
227 }
228 }
229
230 MEM_freeN(reconstructed_cameras);
231
232 return ok;
233}
234
235/* Retrieve all the libmv data from context to blender's side data blocks. */
237{
238 /* take the intrinsics back from libmv */
239 reconstruct_retrieve_libmv_intrinsics(context, tracking);
240
241 return reconstruct_retrieve_libmv_tracks(context, tracking);
242}
243
244/* Convert blender's refinement flags to libmv's. */
246 MovieTrackingObject *tracking_object)
247{
248 const int refine = tracking->settings.refine_camera_intrinsics;
249 int flags = 0;
250
251 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
252 return 0;
253 }
254
257 }
258
261 }
262
265 }
266
269 }
270
271 return flags;
272}
273
274/* Count tracks which has markers at both of keyframes. */
276{
277 const int frame1 = tracking_object->keyframe1, frame2 = tracking_object->keyframe2;
278
279 int tot = 0;
280 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
283 tot++;
284 }
285 }
286 }
287
288 return tot;
289}
290
292 MovieTrackingObject *tracking_object,
293 char *error_msg,
294 int error_size)
295{
297 /* TODO: check for number of tracks? */
298 return true;
299 }
301 /* automatic keyframe selection does not require any pre-process checks */
302 if (reconstruct_count_tracks_on_both_keyframes(tracking_object) < 8) {
303 BLI_strncpy(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
312 BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size);
313 return false;
314#endif
315
316 return true;
317}
318
320 MovieClip *clip,
321 MovieTrackingObject *tracking_object,
322 int keyframe1,
323 int keyframe2,
324 int width,
325 int height)
326{
327 MovieTracking *tracking = &clip->tracking;
328 MovieReconstructContext *context = MEM_cnew<MovieReconstructContext>(
329 "MovieReconstructContext data");
330 const float aspy = 1.0f / tracking->camera.pixel_aspect;
331 const int num_tracks = BLI_listbase_count(&tracking_object->tracks);
332 int sfra = INT_MAX, efra = INT_MIN;
333
334 STRNCPY(context->object_name, tracking_object->name);
335 context->motion_flag = tracking->settings.motion_flag;
336
337 context->select_keyframes = (tracking->settings.reconstruction_flag &
339
341 tracking, width, height, &context->camera_intrinsics_options);
342
343 context->tracks_map = tracks_map_new(context->object_name, num_tracks);
344
345 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
346 int first = 0, last = track->markersnr - 1;
347 MovieTrackingMarker *first_marker = &track->markers[0];
348 MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
349
350 /* find first not-disabled marker */
351 while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
352 first++;
353 first_marker++;
354 }
355
356 /* find last not-disabled marker */
357 while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
358 last--;
359 last_marker--;
360 }
361
362 if (first <= track->markersnr - 1) {
363 sfra = min_ii(sfra, first_marker->framenr);
364 }
365
366 if (last >= 0) {
367 efra = max_ii(efra, last_marker->framenr);
368 }
369
370 tracks_map_insert(context->tracks_map, track);
371 }
372
373 context->sfra = sfra;
374 context->efra = efra;
375
376 context->tracks = libmv_tracks_new(clip, &tracking_object->tracks, width, height * aspy);
377 context->keyframe1 = keyframe1;
378 context->keyframe2 = keyframe2;
379 context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, tracking_object);
380
381 context->error_message[0] = '\0';
382
383 return context;
384}
385
387 const char *error_message)
388{
389 if (context->error_message[0]) {
390 /* Only keep initial error message, the rest are inducted ones. */
391 return;
392 }
393 STRNCPY(context->error_message, error_message);
394}
395
397{
398 return context->error_message;
399}
400
402{
403 if (context->reconstruction) {
404 libmv_reconstructionDestroy(context->reconstruction);
405 }
406
407 libmv_tracksDestroy(context->tracks);
408
409 tracks_map_free(context->tracks_map);
410
411 MEM_freeN(context);
412}
413
414/* Callback which is called from libmv side to update progress in the interface. */
415static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
416{
417 ReconstructProgressData *progressdata = static_cast<ReconstructProgressData *>(customdata);
418
419 if (progressdata->progress) {
420 *progressdata->progress = progress;
421 *progressdata->do_update = true;
422 }
423
425 progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
426}
427
428/* Fill in reconstruction options structure from reconstruction context. */
431{
432 reconstruction_options->select_keyframes = context->select_keyframes;
433
434 reconstruction_options->keyframe1 = context->keyframe1;
435 reconstruction_options->keyframe2 = context->keyframe2;
436
437 reconstruction_options->refine_intrinsics = context->refine_flags;
438}
439
441 bool *stop,
442 bool *do_update,
443 float *progress,
444 char *stats_message,
445 int message_size)
446{
447 float error;
448
449 ReconstructProgressData progressdata;
450
451 libmv_ReconstructionOptions reconstruction_options;
452
453 progressdata.stop = stop;
454 progressdata.do_update = do_update;
455 progressdata.progress = progress;
456 progressdata.stats_message = stats_message;
457 progressdata.message_size = message_size;
458
459 reconstructionOptionsFromContext(&reconstruction_options, context);
460
461 if (context->motion_flag & TRACKING_MOTION_MODAL) {
462 context->reconstruction = libmv_solveModal(context->tracks,
463 &context->camera_intrinsics_options,
464 &reconstruction_options,
466 &progressdata);
467 }
468 else {
469 context->reconstruction = libmv_solveReconstruction(context->tracks,
470 &context->camera_intrinsics_options,
471 &reconstruction_options,
473 &progressdata);
474
475 if (context->select_keyframes) {
476 /* store actual keyframes used for reconstruction to update them in the interface later */
477 context->keyframe1 = reconstruction_options.keyframe1;
478 context->keyframe2 = reconstruction_options.keyframe2;
479 }
480 }
481
482 error = libmv_reprojectionError(context->reconstruction);
483
484 context->reprojection_error = error;
485}
486
488{
489 if (!libmv_reconstructionIsValid(context->reconstruction)) {
491 context, "Failed to solve the motion: most likely there are no good keyframes");
492 return false;
493 }
494
495 tracks_map_merge(context->tracks_map, tracking);
497
498 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking,
499 context->object_name);
500 MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
501
502 /* update keyframe in the interface */
503 if (context->select_keyframes) {
504 tracking_object->keyframe1 = context->keyframe1;
505 tracking_object->keyframe2 = context->keyframe2;
506 }
507
508 reconstruction->error = context->reprojection_error;
509 reconstruction->flag |= TRACKING_RECONSTRUCTED;
510
511 if (!reconstruct_retrieve_libmv(context, tracking)) {
512 return false;
513 }
514
515 return true;
516}
517
519 MovieTrackingReconstruction *reconstruction,
520 const float scale[3])
521{
522 float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
523
524 if (reconstruction->camnr > 0) {
525 mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
526 }
527
528 for (int i = 0; i < reconstruction->camnr; i++) {
529 MovieReconstructedCamera *camera = &reconstruction->cameras[i];
530 mul_v3_v3(camera->mat[3], scale);
531 sub_v3_v3(camera->mat[3], first_camera_delta);
532 }
533
534 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
535 if (track->flag & TRACK_HAS_BUNDLE) {
536 mul_v3_v3(track->bundle_pos, scale);
537 sub_v3_v3(track->bundle_pos, first_camera_delta);
538 }
539 }
540}
541
543{
544 LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
545 tracking_scale_reconstruction(&object->tracks, &object->reconstruction, scale);
546 }
547}
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:3411
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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 unit_m4(float m[4][4])
Definition rct.c:1127
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])
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])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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
#define MAX_NAME
Definition DNA_defs.h:50
@ TRACK_HAS_BUNDLE
@ MARKER_DISABLED
@ TRACKING_OBJECT_CAMERA
@ REFINE_PRINCIPAL_POINT
@ REFINE_TANGENTIAL_DISTORTION
@ REFINE_RADIAL_DISTORTION
@ REFINE_FOCAL_LENGTH
@ TRACKING_RECONSTRUCTED
@ TRACKING_MOTION_MODAL
@ TRACKING_USE_KEYFRAME_SELECTION
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 Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture 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 or normal between camera
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define printf
static void refine(OpenSubdiv_Evaluator *evaluator)
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_freeN(void *vmemh)
Definition mallocn.cc:105
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
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)