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
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;
70 libmv_Tracks *tracks = libmv_tracksNew();
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
88 libmv_tracksInsert(tracks,
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);
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{
296 if (tracking->settings.motion_flag & TRACKING_MOTION_MODAL) {
297 /* TODO: check for number of tracks? */
298 return true;
299 }
300 if ((tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) == 0) {
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);
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;
510
511 if (!reconstruct_retrieve_libmv(context, tracking)) {
512 return false;
513 }
514
515 return true;
516}
517
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
@ TRACKING_MOTION_MODAL
struct MovieReconstructedCamera MovieReconstructedCamera
@ TRACK_HAS_BUNDLE
@ TRACKING_RECONSTRUCTED
@ MARKER_DISABLED
@ TRACKING_OBJECT_CAMERA
@ REFINE_PRINCIPAL_POINT
@ REFINE_TANGENTIAL_DISTORTION
@ REFINE_RADIAL_DISTORTION
@ REFINE_FOCAL_LENGTH
@ TRACKING_USE_KEYFRAME_SELECTION
Read Guarded memory(de)allocation.
#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
const ProjectiveReconstruction & reconstruction
Definition intersect.cc:198
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static void error(const char *str)
void * first
libmv_CameraIntrinsicsOptions camera_intrinsics_options
libmv_Reconstruction * reconstruction
MovieTrackingReconstruction reconstruction
MovieTrackingMarker * markers
struct MovieTrackingTrack * next
EuclideanReconstruction reconstruction
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)