2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2011 Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation,
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/blenkernel/intern/tracking_region_tracker.c
31 * This file contains implementation of blender-side region tracker
32 * which is used for 2D feature tracking.
35 #include "MEM_guardedalloc.h"
37 #include "DNA_movieclip_types.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_threads.h"
42 #include "BKE_tracking.h"
43 #include "BKE_movieclip.h"
45 #include "IMB_imbuf_types.h"
46 #include "IMB_imbuf.h"
48 #include "libmv-capi.h"
49 #include "tracking_private.h"
51 /* **** utility functions for tracking **** */
53 /* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
54 static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels,
55 float weight_red, float weight_green, float weight_blue)
59 for (i = 0; i < num_pixels; i++) {
60 const float *pixel = rgba + 4 * i;
62 gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
66 static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels,
67 float weight_red, float weight_green, float weight_blue)
71 for (i = 0; i < num_pixels; i++) {
72 const unsigned char *pixel = rgba + i * 4;
74 gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
78 /* Get grayscale float search buffer for given marker and frame. */
79 static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
80 int *width_r, int *height_r)
86 searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
94 width = searchibuf->x;
95 height = searchibuf->y;
97 gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
99 if (searchibuf->rect_float) {
100 float_rgba_to_gray(searchibuf->rect_float, gray_pixels, width * height,
101 0.2126f, 0.7152f, 0.0722f);
104 uint8_rgba_to_float_gray((unsigned char *)searchibuf->rect, gray_pixels, width * height,
105 0.2126f, 0.7152f, 0.0722f);
108 IMB_freeImBuf(searchibuf);
116 /* Get image buffer for a given frame
118 * Frame is in clip space.
120 static ImBuf *tracking_context_get_frame_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, int framenr)
123 MovieClipUser new_user = *user;
125 new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
127 ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
132 /* Get image buffer for previous marker's keyframe. */
133 static ImBuf *tracking_context_get_keyframed_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
134 MovieTrackingTrack *track, int curfra, bool backwards,
135 MovieTrackingMarker **marker_keyed_r)
137 MovieTrackingMarker *marker_keyed;
140 marker_keyed = tracking_get_keyframed_marker(track, curfra, backwards);
141 if (marker_keyed == NULL) {
145 keyed_framenr = marker_keyed->framenr;
147 *marker_keyed_r = marker_keyed;
149 return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
152 /* Get image buffer which si used as referece for track. */
153 static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
154 MovieTrackingTrack *track, int curfra, bool backwards,
155 MovieTrackingMarker **reference_marker)
159 if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
160 ibuf = tracking_context_get_keyframed_ibuf(clip, user, clip_flag, track, curfra, backwards, reference_marker);
163 ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
165 /* use current marker as keyframed position */
166 *reference_marker = BKE_tracking_marker_get(track, curfra);
172 /* Fill in libmv tracker options structure with settings need to be used to perform track. */
173 void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
174 libmv_TrackRegionOptions *options)
176 options->motion_model = track->motion_model;
178 options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
180 options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) != 0);
182 options->num_iterations = 50;
183 options->minimum_correlation = track->minimum_correlation;
184 options->sigma = 0.9;
186 if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
187 options->image1_mask = mask;
189 options->image1_mask = NULL;
192 /* Peform tracking from a reference_marker to destination_ibuf.
193 * Uses marker as an initial position guess.
195 * Returns truth if tracker returned success, puts result
196 * to dst_pixel_x and dst_pixel_y.
198 static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrack *track,
199 MovieTrackingMarker *reference_marker, MovieTrackingMarker *marker,
200 float *reference_search_area, int reference_search_area_width,
201 int reference_search_area_height, float *mask,
202 double dst_pixel_x[5], double dst_pixel_y[5])
204 /* To convert to the x/y split array format for libmv. */
205 double src_pixel_x[5], src_pixel_y[5];
207 /* Settings for the tracker */
208 libmv_TrackRegionOptions options = {0};
209 libmv_TrackRegionResult result;
213 int new_search_area_width, new_search_area_height;
214 int frame_width, frame_height;
218 frame_width = destination_ibuf->x;
219 frame_height = destination_ibuf->y;
221 /* for now track to the same search area dimension as marker has got for current frame
222 * will make all tracked markers in currently tracked segment have the same search area
223 * size, but it's quite close to what is actually needed
225 patch_new = track_get_search_floatbuf(destination_ibuf, track, marker,
226 &new_search_area_width, &new_search_area_height);
228 /* configure the tracker */
229 tracking_configure_tracker(track, mask, &options);
231 /* convert the marker corners and center into pixel coordinates in the search/destination images. */
232 tracking_get_marker_coords_for_tracking(frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
233 tracking_get_marker_coords_for_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
235 if (patch_new == NULL || reference_search_area == NULL)
238 /* run the tracker! */
239 tracked = libmv_trackRegion(&options,
240 reference_search_area,
241 reference_search_area_width,
242 reference_search_area_height,
244 new_search_area_width,
245 new_search_area_height,
246 src_pixel_x, src_pixel_y,
248 dst_pixel_x, dst_pixel_y);
250 MEM_freeN(patch_new);
255 static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
256 MovieTrackingMarker *marker,
258 int *reference_framenr)
260 const MovieTrackingMarker *first_marker = track->markers;
261 const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
262 MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
264 while (reference >= first_marker &&
265 reference <= last_marker &&
266 (reference->flag & MARKER_DISABLED) != 0)
274 if (reference < first_marker ||
275 reference > last_marker)
280 *reference_framenr = reference->framenr;
281 return (reference->flag & MARKER_DISABLED) == 0;
284 /* Refine marker's position using previously known keyframe.
285 * Direction of searching for a keyframe depends on backwards flag,
286 * which means if backwards is false, previous keyframe will be as
289 void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards)
291 MovieTrackingMarker *reference_marker = NULL;
292 ImBuf *reference_ibuf, *destination_ibuf;
293 float *search_area, *mask = NULL;
294 int frame_width, frame_height;
295 int search_area_height, search_area_width;
296 int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
297 int reference_framenr;
298 MovieClipUser user = {0};
299 double dst_pixel_x[5], dst_pixel_y[5];
302 /* Construct a temporary clip used, used to acquire image buffers. */
303 user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
305 BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
307 /* Get an image buffer for reference frame, also gets reference marker. */
308 if (!refine_marker_reference_frame_get(track,
316 reference_ibuf = tracking_context_get_reference_ibuf(clip, &user, clip_flag, track, reference_framenr,
317 backwards, &reference_marker);
318 if (reference_ibuf == NULL) {
322 /* Could not refine with self. */
323 if (reference_marker == marker) {
327 /* Destination image buffer has got frame number corresponding to refining marker. */
328 destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
329 if (destination_ibuf == NULL) {
330 IMB_freeImBuf(reference_ibuf);
334 /* Get search area from reference image. */
335 search_area = track_get_search_floatbuf(reference_ibuf, track, reference_marker,
336 &search_area_width, &search_area_height);
338 /* If needed, compute track's mask. */
339 if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
340 mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
342 /* Run the tracker from reference frame to current one. */
343 tracked = configure_and_run_tracker(destination_ibuf, track, reference_marker, marker,
344 search_area, search_area_width, search_area_height,
345 mask, dst_pixel_x, dst_pixel_y);
347 /* Refine current marker's position if track was successful. */
349 tracking_set_marker_coords_from_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
350 marker->flag |= MARKER_TRACKED;
353 /* Free memory used for refining */
354 MEM_freeN(search_area);
357 IMB_freeImBuf(reference_ibuf);
358 IMB_freeImBuf(destination_ibuf);