Blender  V2.93
tracking_region_tracker.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_movieclip_types.h"
30 
31 #include "BLI_threads.h"
32 #include "BLI_utildefines.h"
33 
34 #include "BKE_movieclip.h"
35 #include "BKE_tracking.h"
36 
37 #include "IMB_imbuf.h"
38 #include "IMB_imbuf_types.h"
39 
40 #include "libmv-capi.h"
41 #include "tracking_private.h"
42 
43 /* **** utility functions for tracking **** */
44 
45 /* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
46 static void float_rgba_to_gray(const float *rgba,
47  float *gray,
48  int num_pixels,
49  float weight_red,
50  float weight_green,
51  float weight_blue)
52 {
53  for (int i = 0; i < num_pixels; i++) {
54  const float *pixel = rgba + 4 * i;
55 
56  gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
57  }
58 }
59 
60 static void uint8_rgba_to_float_gray(const unsigned char *rgba,
61  float *gray,
62  int num_pixels,
63  float weight_red,
64  float weight_green,
65  float weight_blue)
66 {
67  for (int i = 0; i < num_pixels; i++) {
68  const unsigned char *pixel = rgba + i * 4;
69 
70  gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
71  }
72 }
73 
74 /* Get grayscale float search buffer for given marker and frame. */
75 static float *track_get_search_floatbuf(ImBuf *ibuf,
76  MovieTrackingTrack *track,
77  MovieTrackingMarker *marker,
78  int *r_width,
79  int *r_height)
80 {
81  ImBuf *searchibuf;
82  float *gray_pixels;
83  int width, height;
84 
85  searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
86 
87  if (!searchibuf) {
88  *r_width = 0;
89  *r_height = 0;
90  return NULL;
91  }
92 
93  width = searchibuf->x;
94  height = searchibuf->y;
95 
96  gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
97 
98  if (searchibuf->rect_float) {
100  searchibuf->rect_float, gray_pixels, width * height, 0.2126f, 0.7152f, 0.0722f);
101  }
102  else {
104  (unsigned char *)searchibuf->rect, gray_pixels, width * height, 0.2126f, 0.7152f, 0.0722f);
105  }
106 
107  IMB_freeImBuf(searchibuf);
108 
109  *r_width = width;
110  *r_height = height;
111 
112  return gray_pixels;
113 }
114 
115 /* Get image buffer for a given frame
116  *
117  * Frame is in clip space.
118  */
120  MovieClipUser *user,
121  int clip_flag,
122  int framenr)
123 {
124  ImBuf *ibuf;
125  MovieClipUser new_user = *user;
126 
127  new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
128 
129  ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
130 
131  return ibuf;
132 }
133 
134 /* Get image buffer for previous marker's keyframe. */
136  MovieClipUser *user,
137  int clip_flag,
138  MovieTrackingTrack *track,
139  int curfra,
140  bool backwards,
141  MovieTrackingMarker **r_marker_keyed)
142 {
143  MovieTrackingMarker *marker_keyed;
144  int keyed_framenr;
145 
146  marker_keyed = tracking_get_keyframed_marker(track, curfra, backwards);
147  if (marker_keyed == NULL) {
148  return NULL;
149  }
150 
151  keyed_framenr = marker_keyed->framenr;
152 
153  *r_marker_keyed = marker_keyed;
154 
155  return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
156 }
157 
158 /* Get image buffer which si used as reference for track. */
160  MovieClipUser *user,
161  int clip_flag,
162  MovieTrackingTrack *track,
163  int curfra,
164  bool backwards,
165  MovieTrackingMarker **reference_marker)
166 {
167  ImBuf *ibuf = NULL;
168 
169  if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
171  clip, user, clip_flag, track, curfra, backwards, reference_marker);
172  }
173  else {
174  ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
175 
176  /* use current marker as keyframed position */
177  *reference_marker = BKE_tracking_marker_get(track, curfra);
178  }
179 
180  return ibuf;
181 }
182 
183 /* Fill in libmv tracker options structure with settings need to be used to perform track. */
185  float *mask,
186  const bool is_backwards,
188 {
189  options->direction = is_backwards ? LIBMV_TRACK_REGION_BACKWARD : LIBMV_TRACK_REGION_FORWARD;
190 
191  /* TODO(sergey): Use explicit conversion, so that options are decoupled between the Libmv library
192  * and enumerator values in DNA. */
193  options->motion_model = track->motion_model;
194 
195  options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
196 
197  options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) !=
198  0);
199 
200  options->num_iterations = 50;
201  options->minimum_correlation = track->minimum_correlation;
202  options->sigma = 0.9;
203 
204  if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0) {
205  options->image1_mask = mask;
206  }
207  else {
208  options->image1_mask = NULL;
209  }
210 }
211 
212 /* Perform tracking from a reference_marker to destination_ibuf.
213  * Uses marker as an initial position guess.
214  *
215  * Returns truth if tracker returned success, puts result
216  * to dst_pixel_x and dst_pixel_y.
217  */
218 static bool configure_and_run_tracker(ImBuf *destination_ibuf,
219  MovieTrackingTrack *track,
220  MovieTrackingMarker *reference_marker,
221  MovieTrackingMarker *marker,
222  float *reference_search_area,
223  int reference_search_area_width,
224  int reference_search_area_height,
225  float *mask,
226  const bool is_backward,
227  double dst_pixel_x[5],
228  double dst_pixel_y[5])
229 {
230  /* To convert to the x/y split array format for libmv. */
231  double src_pixel_x[5], src_pixel_y[5];
232 
233  /* Settings for the tracker */
236 
237  float *patch_new;
238 
239  int new_search_area_width, new_search_area_height;
240  int frame_width, frame_height;
241 
242  bool tracked;
243 
244  frame_width = destination_ibuf->x;
245  frame_height = destination_ibuf->y;
246 
247  /* for now track to the same search area dimension as marker has got for current frame
248  * will make all tracked markers in currently tracked segment have the same search area
249  * size, but it's quite close to what is actually needed
250  */
251  patch_new = track_get_search_floatbuf(
252  destination_ibuf, track, marker, &new_search_area_width, &new_search_area_height);
253 
254  /* configure the tracker */
255  tracking_configure_tracker(track, mask, is_backward, &options);
256 
257  /* Convert the marker corners and center into pixel coordinates in the
258  * search/destination images. */
260  frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
262  frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
263 
264  if (patch_new == NULL || reference_search_area == NULL) {
265  return false;
266  }
267 
268  /* run the tracker! */
269  tracked = libmv_trackRegion(&options,
270  reference_search_area,
271  reference_search_area_width,
272  reference_search_area_height,
273  patch_new,
274  new_search_area_width,
275  new_search_area_height,
276  src_pixel_x,
277  src_pixel_y,
278  &result,
279  dst_pixel_x,
280  dst_pixel_y);
281 
282  MEM_freeN(patch_new);
283 
284  return tracked;
285 }
286 
288  MovieTrackingMarker *marker,
289  bool backwards,
290  int *reference_framenr)
291 {
292  const MovieTrackingMarker *first_marker = track->markers;
293  const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
294  MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
295 
296  while (reference >= first_marker && reference <= last_marker &&
297  (reference->flag & MARKER_DISABLED) != 0) {
298  if (backwards) {
299  reference++;
300  }
301  else {
302  reference--;
303  }
304  }
305 
306  if (reference < first_marker || reference > last_marker) {
307  return false;
308  }
309 
310  *reference_framenr = reference->framenr;
311  return (reference->flag & MARKER_DISABLED) == 0;
312 }
313 
314 /* Refine marker's position using previously known keyframe.
315  * Direction of searching for a keyframe depends on backwards flag,
316  * which means if backwards is false, previous keyframe will be as
317  * reference.
318  */
320  MovieTrackingTrack *track,
321  MovieTrackingMarker *marker,
322  bool backwards)
323 {
324  MovieTrackingMarker *reference_marker = NULL;
325  ImBuf *reference_ibuf, *destination_ibuf;
326  float *search_area, *mask = NULL;
327  int frame_width, frame_height;
328  int search_area_height, search_area_width;
329  int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
330  int reference_framenr;
331  MovieClipUser user = {0};
332  double dst_pixel_x[5], dst_pixel_y[5];
333  bool tracked;
334 
335  /* Construct a temporary clip used, used to acquire image buffers. */
337 
338  BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
339 
340  /* Get an image buffer for reference frame, also gets reference marker. */
341  if (!refine_marker_reference_frame_get(track, marker, backwards, &reference_framenr)) {
342  return;
343  }
344 
345  reference_ibuf = tracking_context_get_reference_ibuf(
346  clip, &user, clip_flag, track, reference_framenr, backwards, &reference_marker);
347  if (reference_ibuf == NULL) {
348  return;
349  }
350 
351  /* Could not refine with self. */
352  if (reference_marker == marker) {
353  return;
354  }
355 
356  /* Destination image buffer has got frame number corresponding to refining marker. */
357  destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
358  if (destination_ibuf == NULL) {
359  IMB_freeImBuf(reference_ibuf);
360  return;
361  }
362 
363  /* Get search area from reference image. */
364  search_area = track_get_search_floatbuf(
365  reference_ibuf, track, reference_marker, &search_area_width, &search_area_height);
366 
367  /* If needed, compute track's mask. */
368  if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0) {
369  mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
370  }
371 
372  /* Run the tracker from reference frame to current one. */
373  tracked = configure_and_run_tracker(destination_ibuf,
374  track,
375  reference_marker,
376  marker,
377  search_area,
378  search_area_width,
379  search_area_height,
380  mask,
381  backwards,
382  dst_pixel_x,
383  dst_pixel_y);
384 
385  /* Refine current marker's position if track was successful. */
386  if (tracked) {
388  frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
389  marker->flag |= MARKER_TRACKED;
390  }
391 
392  /* Free memory used for refining */
393  MEM_freeN(search_area);
394  if (mask) {
395  MEM_freeN(mask);
396  }
397  IMB_freeImBuf(reference_ibuf);
398  IMB_freeImBuf(destination_ibuf);
399 }
#define MOVIECLIP_CACHE_SKIP
struct ImBuf * BKE_movieclip_get_ibuf_flag(struct MovieClip *clip, struct MovieClipUser *user, int flag, int cache_flag)
Definition: movieclip.c:1354
void BKE_movieclip_get_size(struct MovieClip *clip, struct MovieClipUser *user, int *width, int *height)
Definition: movieclip.c:1540
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr)
float * BKE_tracking_track_get_mask(int frame_width, int frame_height, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker)
Definition: tracking.c:1303
struct ImBuf * BKE_tracking_get_search_imbuf(struct ImBuf *ibuf, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, bool anchored, bool disable_channels)
Definition: tracking.c:2861
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1523
@ MCLIP_TIMECODE_FLAGS
@ TRACK_ALGORITHM_FLAG_USE_NORMALIZATION
@ TRACK_ALGORITHM_FLAG_USE_BRUTE
@ TRACK_ALGORITHM_FLAG_USE_MASK
@ MARKER_TRACKED
@ MARKER_DISABLED
@ TRACK_MATCH_KEYFRAME
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
CCL_NAMESPACE_BEGIN struct Options options
@ LIBMV_TRACK_REGION_FORWARD
@ LIBMV_TRACK_REGION_BACKWARD
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
unsigned int * rect
float * rect_float
MovieTrackingMarker * markers
int libmv_trackRegion(const libmv_TrackRegionOptions *, const float *, int, int, const float *, int, int, const double *x1, const double *y1, libmv_TrackRegionResult *result, double *x2, double *y2)
Definition: stub.cc:39
void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards)
static float * track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, int *r_width, int *r_height)
static ImBuf * tracking_context_get_frame_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, int framenr)
static bool refine_marker_reference_frame_get(MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards, int *reference_framenr)
static ImBuf * tracking_context_get_keyframed_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, MovieTrackingTrack *track, int curfra, bool backwards, MovieTrackingMarker **r_marker_keyed)
static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels, float weight_red, float weight_green, float weight_blue)
static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels, float weight_red, float weight_green, float weight_blue)
static ImBuf * tracking_context_get_reference_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, MovieTrackingTrack *track, int curfra, bool backwards, MovieTrackingMarker **reference_marker)
static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrack *track, MovieTrackingMarker *reference_marker, MovieTrackingMarker *marker, float *reference_search_area, int reference_search_area_width, int reference_search_area_height, float *mask, const bool is_backward, double dst_pixel_x[5], double dst_pixel_y[5])
void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask, const bool is_backwards, libmv_TrackRegionOptions *options)
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])
MovieTrackingMarker * tracking_get_keyframed_marker(MovieTrackingTrack *track, int current_frame, bool backwards)
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])
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)