Blender V5.0
tracking_util.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
12#include <cstddef>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_movieclip_types.h"
17
18#include "BLI_ghash.h"
19#include "BLI_listbase.h"
20#include "BLI_math_color.h"
21#include "BLI_math_vector.h"
22#include "BLI_string.h"
23#include "BLI_string_utils.hh"
24#include "BLI_threads.h"
25
26#include "BLT_translation.hh"
27
28#include "BKE_movieclip.h"
29#include "BKE_tracking.h"
30
31#include "IMB_imbuf.hh"
32#include "IMB_imbuf_types.hh"
33
34#include "tracking_private.h"
35
36#include "libmv-capi.h"
37
38/* Uncomment this to have caching-specific debug prints. */
39// #define DEBUG_CACHE
40
41#ifdef DEBUG_CACHE
42# define CACHE_PRINTF(...) printf(__VA_ARGS__)
43#else
44# define CACHE_PRINTF(...)
45#endif
46
47/* -------------------------------------------------------------------- */
50
51TracksMap *tracks_map_new(const char *object_name, int num_tracks)
52{
53 TracksMap *map = MEM_callocN<TracksMap>("TrackingsMap");
54
55 STRNCPY(map->object_name, object_name);
56
57 map->num_tracks = num_tracks;
58
59 map->tracks = MEM_calloc_arrayN<MovieTrackingTrack>(num_tracks, "TrackingsMap tracks");
60
61 map->hash = BLI_ghash_ptr_new("TracksMap hash");
62
64
65 return map;
66}
67
69{
70 return map->num_tracks;
71}
72
74{
75 MovieTrackingTrack new_track = *track;
76
77 new_track.markers = static_cast<MovieTrackingMarker *>(MEM_dupallocN(new_track.markers));
78
79 map->tracks[map->ptr] = new_track;
80
81 BLI_ghash_insert(map->hash, &map->tracks[map->ptr], track);
82
83 map->ptr++;
84}
85
87{
88 MovieTrackingTrack *track;
89 ListBase tracks = {nullptr, nullptr}, new_tracks = {nullptr, nullptr};
90 ListBase *old_tracks;
91
92 MovieTrackingObject *tracking_object = BKE_tracking_object_get_named(tracking, map->object_name);
93 if (!tracking_object) {
94 /* object was deleted by user, create new one */
95 tracking_object = BKE_tracking_object_add(tracking, map->object_name);
96 }
97
98 old_tracks = &tracking_object->tracks;
99
100 /* duplicate currently operating tracks to temporary list.
101 * this is needed to keep names in unique state and it's faster to change names
102 * of currently operating tracks (if needed)
103 */
104 for (int a = 0; a < map->num_tracks; a++) {
105 MovieTrackingTrack *old_track;
106 bool mapped_to_old = false;
107
108 track = &map->tracks[a];
109
110 /* find original of operating track in list of previously displayed tracks */
111 old_track = static_cast<MovieTrackingTrack *>(BLI_ghash_lookup(map->hash, track));
112 if (old_track) {
113 if (BLI_findindex(old_tracks, old_track) != -1) {
114 BLI_remlink(old_tracks, old_track);
115
117
118 /* Copy flags like selection back to the track map. */
119 track->flag = old_track->flag;
120 track->pat_flag = old_track->pat_flag;
121 track->search_flag = old_track->search_flag;
122
123 /* Copy all the rest settings back from the map to the actual tracks. */
124 MEM_freeN(old_track->markers);
125 *old_track = *track;
126 old_track->markers = static_cast<MovieTrackingMarker *>(MEM_dupallocN(old_track->markers));
127
129
130 BLI_addtail(&tracks, old_track);
131
132 mapped_to_old = true;
133 }
134 }
135
136 if (mapped_to_old == false) {
138
139 /* Update old-new track mapping */
140 BLI_ghash_reinsert(map->hash, track, new_track, nullptr, nullptr);
141
142 BLI_addtail(&tracks, new_track);
143 }
144 }
145
146 /* move all tracks, which aren't operating */
147 track = static_cast<MovieTrackingTrack *>(old_tracks->first);
148 while (track) {
149 MovieTrackingTrack *next = track->next;
150 BLI_addtail(&new_tracks, track);
151 track = next;
152 }
153
154 /* now move all tracks which are currently operating and keep their names unique */
155 track = static_cast<MovieTrackingTrack *>(tracks.first);
156 while (track) {
157 MovieTrackingTrack *next = track->next;
158
159 BLI_remlink(&tracks, track);
160
161 track->next = track->prev = nullptr;
162 BLI_addtail(&new_tracks, track);
163
164 BLI_uniquename(&new_tracks,
165 track,
167 '.',
169 sizeof(track->name));
170
171 track = next;
172 }
173
174 *old_tracks = new_tracks;
175}
176
178{
179 BLI_ghash_free(map->hash, nullptr, nullptr);
180
181 for (int i = 0; i < map->num_tracks; i++) {
183 }
184
185 MEM_freeN(map->tracks);
186
187 BLI_spin_end(&map->spin_lock);
188
189 MEM_freeN(map);
190}
191
193
194/* -------------------------------------------------------------------- */
197
198/* Three coordinate frames: Frame, Search, and Marker
199 * Two units: Pixels, Unified
200 * Notation: {coordinate frame}_{unit}; for example, "search_pixel" are search
201 * window relative coordinates in pixels, and "frame_unified" are unified 0..1
202 * coordinates relative to the entire frame.
203 */
204static void unified_to_pixel(int frame_width,
205 int frame_height,
206 const float unified_coords[2],
207 float pixel_coords[2])
208{
209 pixel_coords[0] = unified_coords[0] * frame_width;
210 pixel_coords[1] = unified_coords[1] * frame_height;
211}
212
214 const float marker_unified_coords[2],
215 float frame_unified_coords[2])
216{
217 frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0];
218 frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1];
219}
220
222 int frame_height,
223 const MovieTrackingMarker *marker,
224 const float marker_unified_coords[2],
225 float frame_pixel_coords[2])
226{
227 marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords);
228 unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords);
229}
230
232 int frame_height,
233 const MovieTrackingMarker *marker,
234 float frame_pixel[2])
235{
236 /* Get the lower left coordinate of the search window and snap to pixel coordinates */
238 frame_width, frame_height, marker, marker->search_min, frame_pixel);
239 frame_pixel[0] = int(frame_pixel[0]);
240 frame_pixel[1] = int(frame_pixel[1]);
241}
242
243static void pixel_to_unified(int frame_width,
244 int frame_height,
245 const float pixel_coords[2],
246 float unified_coords[2])
247{
248 unified_coords[0] = pixel_coords[0] / frame_width;
249 unified_coords[1] = pixel_coords[1] / frame_height;
250}
251
252static void marker_unified_to_search_pixel(int frame_width,
253 int frame_height,
254 const MovieTrackingMarker *marker,
255 const float marker_unified[2],
256 float search_pixel[2])
257{
258 float frame_pixel[2];
259 float search_origin_frame_pixel[2];
260
262 frame_width, frame_height, marker, marker_unified, frame_pixel);
264 frame_width, frame_height, marker, search_origin_frame_pixel);
265 sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel);
266}
267
268static void search_pixel_to_marker_unified(int frame_width,
269 int frame_height,
270 const MovieTrackingMarker *marker,
271 const float search_pixel[2],
272 float marker_unified[2])
273{
274 float frame_unified[2];
275 float search_origin_frame_pixel[2];
276
278 frame_width, frame_height, marker, search_origin_frame_pixel);
279 add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
280 pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);
281
282 /* marker pos is in frame unified */
283 sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
284}
285
287 int frame_height,
288 const MovieTrackingMarker *marker,
289 double search_pixel_x[5],
290 double search_pixel_y[5])
291{
292 float unified_coords[2];
293 float pixel_coords[2];
294
295 /* Convert the corners into search space coordinates. */
296 for (int i = 0; i < 4; i++) {
298 frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords);
299 search_pixel_x[i] = pixel_coords[0] - 0.5f;
300 search_pixel_y[i] = pixel_coords[1] - 0.5f;
301 }
302
303 /* Convert the center position (aka "pos"); this is the origin */
304 unified_coords[0] = 0.0f;
305 unified_coords[1] = 0.0f;
306 marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords);
307
308 search_pixel_x[4] = pixel_coords[0] - 0.5f;
309 search_pixel_y[4] = pixel_coords[1] - 0.5f;
310}
311
313 int frame_height,
314 MovieTrackingMarker *marker,
315 const double search_pixel_x[5],
316 const double search_pixel_y[5])
317{
318 float marker_unified[2];
319 float search_pixel[2];
320
321 /* Convert the corners into search space coordinates. */
322 for (int i = 0; i < 4; i++) {
323 search_pixel[0] = search_pixel_x[i] + 0.5;
324 search_pixel[1] = search_pixel_y[i] + 0.5;
326 frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]);
327 }
328
329 /* Convert the center position (aka "pos"); this is the origin */
330 search_pixel[0] = search_pixel_x[4] + 0.5;
331 search_pixel[1] = search_pixel_y[4] + 0.5;
332 search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified);
333
334 /* If the tracker tracked nothing, then "marker_unified" would be zero.
335 * Otherwise, the entire patch shifted, and that delta should be applied to
336 * all the coordinates.
337 */
338 for (int i = 0; i < 4; i++) {
339 marker->pattern_corners[i][0] -= marker_unified[0];
340 marker->pattern_corners[i][1] -= marker_unified[1];
341 }
342
343 marker->pos[0] += marker_unified[0];
344 marker->pos[1] += marker_unified[1];
345}
346
347void tracking_principal_point_normalized_to_pixel(const float principal_point_normalized[2],
348 const int frame_width,
349 const int frame_height,
350 float r_principal_point_pixel[2])
351{
352 const float frame_center_x = float(frame_width) / 2;
353 const float frame_center_y = float(frame_height) / 2;
354
355 r_principal_point_pixel[0] = frame_center_x + principal_point_normalized[0] * frame_center_x;
356 r_principal_point_pixel[1] = frame_center_y + principal_point_normalized[1] * frame_center_y;
357}
358
359void tracking_principal_point_pixel_to_normalized(const float principal_point_pixel[2],
360 const int frame_width,
361 const int frame_height,
362 float r_principal_point_normalized[2])
363{
364 const float frame_center_x = float(frame_width) / 2;
365 const float frame_center_y = float(frame_height) / 2;
366
367 r_principal_point_normalized[0] = (principal_point_pixel[0] - frame_center_x) / frame_center_x;
368 r_principal_point_normalized[1] = (principal_point_pixel[1] - frame_center_y) / frame_center_y;
369}
370
372
373/* -------------------------------------------------------------------- */
376
378 const MovieTrackingMarker *ref_marker,
379 bool before,
380 bool overwrite)
381{
382 MovieTrackingMarker marker_new;
383
384 marker_new = *ref_marker;
385 marker_new.flag &= ~MARKER_TRACKED;
386 marker_new.flag |= MARKER_DISABLED;
387
388 if (before) {
389 marker_new.framenr--;
390 }
391 else {
392 marker_new.framenr++;
393 }
394
395 if (overwrite || !BKE_tracking_track_has_marker_at_frame(track, marker_new.framenr)) {
396 BKE_tracking_marker_insert(track, &marker_new);
397 }
398}
399
401 const MovieTrackingCamera *camera, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
402{
403 switch (camera->distortion_model) {
405 camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
406 camera_intrinsics_options->polynomial_k1 = camera->k1;
407 camera_intrinsics_options->polynomial_k2 = camera->k2;
408 camera_intrinsics_options->polynomial_k3 = camera->k3;
409 camera_intrinsics_options->polynomial_p1 = 0.0;
410 camera_intrinsics_options->polynomial_p2 = 0.0;
411 return;
412
414 camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
415 camera_intrinsics_options->division_k1 = camera->division_k1;
416 camera_intrinsics_options->division_k2 = camera->division_k2;
417 return;
418
420 camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE;
421 camera_intrinsics_options->nuke_k1 = camera->nuke_k1;
422 camera_intrinsics_options->nuke_k2 = camera->nuke_k2;
423 return;
425 camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_BROWN;
426 camera_intrinsics_options->brown_k1 = camera->brown_k1;
427 camera_intrinsics_options->brown_k2 = camera->brown_k2;
428 camera_intrinsics_options->brown_k3 = camera->brown_k3;
429 camera_intrinsics_options->brown_k4 = camera->brown_k4;
430 camera_intrinsics_options->brown_p1 = camera->brown_p1;
431 camera_intrinsics_options->brown_p2 = camera->brown_p2;
432 return;
433 }
434
435 /* Unknown distortion model, which might be due to opening newer file in older Blender.
436 * Fall back to a known and supported model with 0 distortion. */
437 camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
438 camera_intrinsics_options->polynomial_k1 = 0.0;
439 camera_intrinsics_options->polynomial_k2 = 0.0;
440 camera_intrinsics_options->polynomial_k3 = 0.0;
441 camera_intrinsics_options->polynomial_p1 = 0.0;
442 camera_intrinsics_options->polynomial_p2 = 0.0;
443}
444
446 const libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieTrackingCamera *camera)
447{
448 switch (camera_intrinsics_options->distortion_model) {
451 camera->k1 = camera_intrinsics_options->polynomial_k1;
452 camera->k2 = camera_intrinsics_options->polynomial_k2;
453 camera->k3 = camera_intrinsics_options->polynomial_k3;
454 return;
455
458 camera->division_k1 = camera_intrinsics_options->division_k1;
459 camera->division_k2 = camera_intrinsics_options->division_k2;
460 return;
461
464 camera->nuke_k1 = camera_intrinsics_options->nuke_k1;
465 camera->nuke_k2 = camera_intrinsics_options->nuke_k2;
466 return;
469 camera->brown_k1 = camera_intrinsics_options->brown_k1;
470 camera->brown_k2 = camera_intrinsics_options->brown_k2;
471 camera->brown_k3 = camera_intrinsics_options->brown_k3;
472 camera->brown_k4 = camera_intrinsics_options->brown_k4;
473 camera->brown_p1 = camera_intrinsics_options->brown_p1;
474 camera->brown_p2 = camera_intrinsics_options->brown_p2;
475 return;
476 }
477
478 /* Libmv returned distortion model which is not known to Blender. This is a logical error in code
479 * and Blender side is to be updated to match Libmv. */
480 BLI_assert_msg(0, "Unknown distortion model");
481}
482
484 MovieTracking *tracking,
485 const int calibration_width,
486 const int calibration_height,
487 libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
488{
489 MovieTrackingCamera *camera = &tracking->camera;
490 const float aspy = 1.0f / tracking->camera.pixel_aspect;
491
492 float principal_px[2];
494 camera->principal_point, calibration_width, calibration_height, principal_px);
495
496 camera_intrinsics_options->focal_length = camera->focal;
497
498 camera_intrinsics_options->principal_point_x = principal_px[0];
499 camera_intrinsics_options->principal_point_y = principal_px[1] * aspy;
500
501 distortion_model_parameters_from_tracking(camera, camera_intrinsics_options);
502
503 camera_intrinsics_options->image_width = calibration_width;
504 camera_intrinsics_options->image_height = int(calibration_height * aspy);
505}
506
508 MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
509{
510 MovieTrackingCamera *camera = &tracking->camera;
511
512 camera->focal = camera_intrinsics_options->focal_length;
513
514 /* NOTE: The image size stored in the `camera_intrinsics_options` is aspect-ratio corrected,
515 * so there is no need to "un-apply" it from the principal point. */
516 const float principal_px[2] = {float(camera_intrinsics_options->principal_point_x),
517 float(camera_intrinsics_options->principal_point_y)};
518
520 camera_intrinsics_options->image_width,
521 camera_intrinsics_options->image_height,
522 camera->principal_point);
523
524 distortion_model_parameters_from_options(camera_intrinsics_options, camera);
525}
526
528 int current_frame,
529 bool backwards)
530{
531 MovieTrackingMarker *marker_keyed = nullptr;
532 MovieTrackingMarker *marker_keyed_fallback = nullptr;
533 int a = BKE_tracking_marker_get(track, current_frame) - track->markers;
534
535 while (a >= 0 && a < track->markersnr) {
536 int next = backwards ? a + 1 : a - 1;
537 bool is_keyframed = false;
538 MovieTrackingMarker *cur_marker = &track->markers[a];
539 MovieTrackingMarker *next_marker = nullptr;
540
541 if (next >= 0 && next < track->markersnr) {
542 next_marker = &track->markers[next];
543 }
544
545 if ((cur_marker->flag & MARKER_DISABLED) == 0) {
546 /* If it'll happen so we didn't find a real keyframe marker,
547 * fall back to the first marker in current tracked segment
548 * as a keyframe. */
549 if (next_marker == nullptr) {
550 /* Could happen when trying to get reference marker for the fist
551 * one on the segment which isn't surrounded by disabled markers.
552 *
553 * There's no really good choice here, just use the reference
554 * marker which looks correct.. */
555 if (marker_keyed_fallback == nullptr) {
556 marker_keyed_fallback = cur_marker;
557 }
558 }
559 else if (next_marker->flag & MARKER_DISABLED) {
560 if (marker_keyed_fallback == nullptr) {
561 marker_keyed_fallback = cur_marker;
562 }
563 }
564
565 is_keyframed |= (cur_marker->flag & MARKER_TRACKED) == 0;
566 }
567
568 if (is_keyframed) {
569 marker_keyed = cur_marker;
570
571 break;
572 }
573
574 a = next;
575 }
576
577 if (marker_keyed == nullptr) {
578 marker_keyed = marker_keyed_fallback;
579 }
580
581 return marker_keyed;
582}
583
585
586/* -------------------------------------------------------------------- */
589
591 int clip_index,
592 int frame)
593{
594 MovieClip *clip;
595 MovieClipUser user;
596 ImBuf *ibuf;
597 int scene_frame;
598
599 BLI_assert(clip_index < accessor->num_clips);
600
601 clip = accessor->clips[clip_index];
602 scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
603 BKE_movieclip_user_set_frame(&user, scene_frame);
605 user.render_flag = 0;
606 ibuf = BKE_movieclip_get_ibuf(clip, &user);
607
608 return ibuf;
609}
610
612{
613 ImBuf *grayscale = IMB_allocImBuf(ibuf->x, ibuf->y, 32, 0);
614
615 BLI_assert(ELEM(ibuf->channels, 3, 4));
616
617 /* TODO(sergey): Bummer, currently IMB API only allows to create 4 channels
618 * float buffer, so we do it manually here.
619 *
620 * Will generalize it later.
621 */
622 const size_t num_pixels = size_t(grayscale->x) * size_t(grayscale->y);
623 grayscale->channels = 1;
624 float *rect_float = MEM_calloc_arrayN<float>(num_pixels, "tracking grayscale image");
625 if (rect_float != nullptr) {
626 IMB_assign_float_buffer(grayscale, rect_float, IB_TAKE_OWNERSHIP);
627
628 for (int i = 0; i < grayscale->x * grayscale->y; i++) {
629 const float *pixel = ibuf->float_buffer.data + ibuf->channels * i;
630
631 rect_float[i] = 0.2126f * pixel[0] + 0.7152f * pixel[1] + 0.0722f * pixel[2];
632 }
633 }
634
635 return grayscale;
636}
637
638static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image)
639{
640 BLI_assert(ibuf->float_buffer.data != nullptr);
641 float_image->buffer = ibuf->float_buffer.data;
642 float_image->width = ibuf->x;
643 float_image->height = ibuf->y;
644 float_image->channels = ibuf->channels;
645}
646
648{
649 ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
650 size_t num_total_channels = size_t(ibuf->x) * size_t(ibuf->y) * float_image->channels;
651 ibuf->channels = float_image->channels;
652 float *rect_float = MEM_calloc_arrayN<float>(num_total_channels, "tracking grayscale image");
653 if (rect_float != nullptr) {
655
656 memcpy(rect_float, float_image->buffer, num_total_channels * sizeof(float));
657 }
658 return ibuf;
659}
660
662 int clip_index,
663 int frame,
664 libmv_InputMode input_mode,
665 int downscale,
666 const libmv_Region *region,
668{
669 /* First try to get fully processed image from the cache. */
670 CACHE_PRINTF("Calculate new buffer for frame %d\n", frame);
671 /* And now we do post-processing of the original frame. */
672 ImBuf *orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame);
673 if (orig_ibuf == nullptr) {
674 return nullptr;
675 }
676 ImBuf *final_ibuf;
677 /* Cut a region if requested. */
678 if (region != nullptr) {
679 int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1];
680
681 /* If the requested region goes outside of the actual frame we still
682 * return the requested region size, but only fill it's partially with
683 * the data we can.
684 */
685 int clamped_origin_x = max_ii(int(region->min[0]), 0),
686 clamped_origin_y = max_ii(int(region->min[1]), 0);
687 int dst_offset_x = clamped_origin_x - int(region->min[0]),
688 dst_offset_y = clamped_origin_y - int(region->min[1]);
689 int clamped_width = width - dst_offset_x, clamped_height = height - dst_offset_y;
690 clamped_width = min_ii(clamped_width, orig_ibuf->x - clamped_origin_x);
691 clamped_height = min_ii(clamped_height, orig_ibuf->y - clamped_origin_y);
692
693 final_ibuf = IMB_allocImBuf(width, height, 32, IB_float_data);
694
695 if (orig_ibuf->float_buffer.data != nullptr) {
696 IMB_rectcpy(final_ibuf,
697 orig_ibuf,
698 dst_offset_x,
699 dst_offset_y,
700 clamped_origin_x,
701 clamped_origin_y,
702 clamped_width,
703 clamped_height);
704 }
705 else {
706 /* TODO(sergey): We don't do any color space or alpha conversion
707 * here. Probably Libmv is better to work in the linear space,
708 * but keep sRGB space here for compatibility for now.
709 */
710 for (int y = 0; y < clamped_height; y++) {
711 for (int x = 0; x < clamped_width; x++) {
712 int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y;
713 int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y;
714 int dst_index = (dst_y * width + dst_x) * 4,
715 src_index = (src_y * orig_ibuf->x + src_x) * 4;
716 rgba_uchar_to_float(final_ibuf->float_buffer.data + dst_index,
717 orig_ibuf->byte_buffer.data + src_index);
718 }
719 }
720 }
721 }
722 else {
723 /* Libmv only works with float images,
724 *
725 * This would likely make it so loads of float buffers are being stored
726 * in the cache which is nice on the one hand (faster re-use of the
727 * frames) but on the other hand it bumps the memory usage up.
728 */
730 IMB_float_from_byte(orig_ibuf);
732 final_ibuf = orig_ibuf;
733 }
734 /* Downscale if needed. */
735 if (downscale > 0) {
736 if (final_ibuf == orig_ibuf) {
737 final_ibuf = IMB_dupImBuf(orig_ibuf);
738 }
739 IMB_scale(final_ibuf,
740 orig_ibuf->x / (1 << downscale),
741 orig_ibuf->y / (1 << downscale),
743 false);
744 }
745 /* Apply possible transformation. */
746 if (transform != nullptr) {
747 libmv_FloatImage input_image, output_image;
748 ibuf_to_float_image(final_ibuf, &input_image);
749 libmv_frameAccessorgetTransformRun(transform, &input_image, &output_image);
750 if (final_ibuf != orig_ibuf) {
751 IMB_freeImBuf(final_ibuf);
752 }
753 final_ibuf = float_image_to_ibuf(&output_image);
754 libmv_floatImageDestroy(&output_image);
755 }
756 /* Transform number of channels. */
757 if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
758 BLI_assert(ELEM(orig_ibuf->channels, 3, 4));
759 /* pass */
760 }
761 else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
762 BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO);
763 if (final_ibuf->channels != 1) {
764 ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf);
765 if (final_ibuf != orig_ibuf) {
766 /* We dereference original frame later. */
767 IMB_freeImBuf(final_ibuf);
768 }
769 final_ibuf = grayscale_ibuf;
770 }
771 }
772 /* It's possible processing still didn't happen at this point,
773 * but we really need a copy of the buffer to be transformed
774 * and to be put to the cache.
775 */
776 if (final_ibuf == orig_ibuf) {
777 final_ibuf = IMB_dupImBuf(orig_ibuf);
778 }
779 IMB_freeImBuf(orig_ibuf);
780 return final_ibuf;
781}
782
784 int clip_index,
785 int frame,
786 libmv_InputMode input_mode,
787 int downscale,
788 const libmv_Region *region,
790 float **destination,
791 int *width,
792 int *height,
793 int *channels)
794{
795 TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
796 ImBuf *ibuf;
797
798 BLI_assert(clip_index >= 0 && clip_index < accessor->num_clips);
799
800 ibuf = accessor_get_ibuf(accessor, clip_index, frame, input_mode, downscale, region, transform);
801
802 if (ibuf) {
803 *destination = ibuf->float_buffer.data;
804 *width = ibuf->x;
805 *height = ibuf->y;
806 *channels = ibuf->channels;
807 }
808 else {
809 *destination = nullptr;
810 *width = 0;
811 *height = 0;
812 *channels = 0;
813 }
814
815 return ibuf;
816}
817
819{
820 ImBuf *ibuf = (ImBuf *)cache_key;
821 IMB_freeImBuf(ibuf);
822}
823
825 int clip_index,
826 int frame,
827 int track_index,
828 const libmv_Region *region,
829 float **r_destination,
830 int *r_width,
831 int *r_height)
832{
833 /* Perform sanity checks first. */
834 TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
835 BLI_assert(clip_index < accessor->num_clips);
836 BLI_assert(track_index < accessor->num_tracks);
837 MovieTrackingTrack *track = accessor->tracks[track_index];
838 /* Early output, track does not use mask. */
839 if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
840 return nullptr;
841 }
842 MovieClip *clip = accessor->clips[clip_index];
843 /* Construct fake user so we can access movie clip. */
844 MovieClipUser user;
845 int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
846 BKE_movieclip_user_set_frame(&user, scene_frame);
848 user.render_flag = 0;
849 /* Get frame width and height so we can convert stroke coordinates
850 * and other things from normalized to pixel space.
851 */
852 int frame_width, frame_height;
853 BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
854 /* Actual mask sampling. */
856 const float region_min[2] = {
857 region->min[0] - marker->pos[0] * frame_width,
858 region->min[1] - marker->pos[1] * frame_height,
859 };
860 const float region_max[2] = {
861 region->max[0] - marker->pos[0] * frame_width,
862 region->max[1] - marker->pos[1] * frame_height,
863 };
864 *r_destination = tracking_track_get_mask_for_region(
865 frame_width, frame_height, region_min, region_max, track);
866 *r_width = region->max[0] - region->min[0];
867 *r_height = region->max[1] - region->min[1];
868 return *r_destination;
869}
870
872{
873 if (cache_key != nullptr) {
874 float *mask = (float *)cache_key;
876 }
877}
878
880 int num_clips,
882 int num_tracks)
883{
884 TrackingImageAccessor *accessor = MEM_callocN<TrackingImageAccessor>("tracking image accessor");
885
886 BLI_assert(num_clips <= MAX_ACCESSOR_CLIP);
887
888 memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
889 accessor->num_clips = num_clips;
890
891 accessor->tracks = MEM_calloc_arrayN<MovieTrackingTrack *>(num_tracks, "image accessor tracks");
892 memcpy(accessor->tracks, tracks, num_tracks * sizeof(MovieTrackingTrack *));
893 accessor->num_tracks = num_tracks;
894
900
901 BLI_spin_init(&accessor->cache_lock);
902
903 return accessor;
904}
905
907{
909 BLI_spin_end(&accessor->cache_lock);
910 MEM_freeN(accessor->tracks);
911 MEM_freeN(accessor);
912}
913
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
void BKE_movieclip_get_size(struct MovieClip *clip, const struct MovieClipUser *user, int *r_width, int *r_height)
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr)
struct ImBuf * BKE_movieclip_get_ibuf(struct MovieClip *clip, const struct MovieClipUser *user)
struct MovieTrackingTrack * BKE_tracking_track_duplicate(struct MovieTrackingTrack *track)
Definition tracking.cc:566
struct MovieTrackingObject * BKE_tracking_object_get_named(struct MovieTracking *tracking, const char *name)
Definition tracking.cc:1966
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct MovieTrackingMarker * BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1391
void BKE_tracking_track_free(struct MovieTrackingTrack *track)
Definition tracking.cc:596
bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:709
struct MovieTrackingObject * BKE_tracking_object_add(struct MovieTracking *tracking, const char *name)
Definition tracking.cc:1897
struct MovieTrackingMarker * BKE_tracking_marker_insert(struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker)
Definition tracking.cc:1235
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:712
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
@ LOCK_MOVIECLIP
Definition BLI_threads.h:68
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#define ELEM(...)
#define CTX_DATA_(context, msgid)
#define BLT_I18NCONTEXT_ID_MOVIECLIP
@ MCLIP_PROXY_RENDER_SIZE_FULL
@ TRACKING_DISTORTION_MODEL_DIVISION
@ TRACKING_DISTORTION_MODEL_POLYNOMIAL
@ TRACKING_DISTORTION_MODEL_NUKE
@ TRACKING_DISTORTION_MODEL_BROWN
@ MARKER_TRACKED
@ MARKER_DISABLED
@ TRACK_ALGORITHM_FLAG_USE_MASK
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_rectcpy(ImBuf *dbuf, const ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
Definition rectop.cc:444
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:465
void IMB_float_from_byte(ImBuf *ibuf)
@ IB_TAKE_OWNERSHIP
@ IB_float_data
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
nullptr float
#define offsetof(t, d)
void libmv_FrameAccessorDestroy(libmv_FrameAccessor *frame_accessor)
void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, const libmv_FloatImage *input_image, libmv_FloatImage *output_image)
libmv_FrameAccessor * libmv_FrameAccessorNew(libmv_FrameAccessorUserData *user_data, libmv_GetImageCallback get_image_callback, libmv_ReleaseImageCallback release_image_callback, libmv_GetMaskForTrackCallback get_mask_for_track_callback, libmv_ReleaseMaskCallback release_mask_callback)
@ LIBMV_DISTORTION_MODEL_POLYNOMIAL
@ LIBMV_DISTORTION_MODEL_NUKE
@ LIBMV_DISTORTION_MODEL_BROWN
@ LIBMV_DISTORTION_MODEL_DIVISION
struct libmv_FrameTransform libmv_FrameTransform
void * libmv_CacheKey
struct libmv_FrameAccessorUserData libmv_FrameAccessorUserData
@ LIBMV_IMAGE_MODE_RGBA
@ LIBMV_IMAGE_MODE_MONO
void libmv_floatImageDestroy(libmv_FloatImage *image)
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_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
const char * name
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
void * first
MovieTrackingMarker * markers
struct MovieTrackingTrack * next
struct MovieTrackingTrack * prev
MovieTrackingCamera camera
struct MovieTrackingTrack ** tracks
struct MovieClip * clips[MAX_ACCESSOR_CLIP]
struct libmv_FrameAccessor * libmv_accessor
char object_name[MAX_NAME]
struct GHash * hash
MovieTrackingTrack * tracks
SpinLock spin_lock
i
Definition text_draw.cc:230
float * tracking_track_get_mask_for_region(const int frame_width, const int frame_height, const float region_min[2], const float region_max[2], const MovieTrackingTrack *track)
Definition tracking.cc:1136
ListBase tracks
Definition tracking.cc:71
#define MAX_ACCESSOR_CLIP
static void accessor_release_image_callback(libmv_CacheKey cache_key)
static libmv_CacheKey accessor_get_image_callback(libmv_FrameAccessorUserData *user_data, int clip_index, int frame, libmv_InputMode input_mode, int downscale, const libmv_Region *region, const libmv_FrameTransform *transform, float **destination, int *width, int *height, int *channels)
static void pixel_to_unified(int frame_width, int frame_height, const float pixel_coords[2], float unified_coords[2])
static void unified_to_pixel(int frame_width, int frame_height, const float unified_coords[2], float pixel_coords[2])
static libmv_CacheKey accessor_get_mask_for_track_callback(libmv_FrameAccessorUserData *user_data, int clip_index, int frame, int track_index, const libmv_Region *region, float **r_destination, int *r_width, int *r_height)
void tracking_marker_insert_disabled(MovieTrackingTrack *track, const MovieTrackingMarker *ref_marker, bool before, bool overwrite)
static void search_pixel_to_marker_unified(int frame_width, int frame_height, const MovieTrackingMarker *marker, const float search_pixel[2], float marker_unified[2])
int tracks_map_get_size(TracksMap *map)
static ImBuf * accessor_get_preprocessed_ibuf(TrackingImageAccessor *accessor, int clip_index, int frame)
void tracking_principal_point_pixel_to_normalized(const float principal_point_pixel[2], const int frame_width, const int frame_height, float r_principal_point_normalized[2])
static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image)
static void marker_unified_to_frame_pixel_coordinates(int frame_width, int frame_height, const MovieTrackingMarker *marker, const float marker_unified_coords[2], float frame_pixel_coords[2])
void tracks_map_free(TracksMap *map)
static void marker_unified_to_search_pixel(int frame_width, int frame_height, const MovieTrackingMarker *marker, const float marker_unified[2], float search_pixel[2])
void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking, const int calibration_width, const int calibration_height, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
static ImBuf * make_grayscale_ibuf_copy(ImBuf *ibuf)
void tracking_get_marker_coords_for_tracking(int frame_width, int frame_height, const MovieTrackingMarker *marker, double search_pixel_x[5], double search_pixel_y[5])
TrackingImageAccessor * tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP], int num_clips, MovieTrackingTrack **tracks, int num_tracks)
static void distortion_model_parameters_from_options(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieTrackingCamera *camera)
static void marker_to_frame_unified(const MovieTrackingMarker *marker, const float marker_unified_coords[2], float frame_unified_coords[2])
void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track)
#define CACHE_PRINTF(...)
static ImBuf * float_image_to_ibuf(libmv_FloatImage *float_image)
void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
static void distortion_model_parameters_from_tracking(const MovieTrackingCamera *camera, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
void tracking_image_accessor_destroy(TrackingImageAccessor *accessor)
TracksMap * tracks_map_new(const char *object_name, int num_tracks)
static ImBuf * accessor_get_ibuf(TrackingImageAccessor *accessor, int clip_index, int frame, libmv_InputMode input_mode, int downscale, const libmv_Region *region, const libmv_FrameTransform *transform)
MovieTrackingMarker * tracking_get_keyframed_marker(MovieTrackingTrack *track, int current_frame, bool backwards)
static void accessor_release_mask_callback(libmv_CacheKey cache_key)
void tracking_set_marker_coords_from_tracking(int frame_width, int frame_height, MovieTrackingMarker *marker, const double search_pixel_x[5], const double search_pixel_y[5])
void tracking_get_search_origin_frame_pixel(int frame_width, int frame_height, const MovieTrackingMarker *marker, float frame_pixel[2])
void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
void tracking_principal_point_normalized_to_pixel(const float principal_point_normalized[2], const int frame_width, const int frame_height, float r_principal_point_pixel[2])