tracking_region_tracker.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  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.
  8. *
  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.
  13. *
  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.
  17. *
  18. * The Original Code is Copyright (C) 2011 Blender Foundation.
  19. * All rights reserved.
  20. *
  21. * Contributor(s): Blender Foundation,
  22. * Sergey Sharybin
  23. * Keir Mierle
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. */
  27. /** \file blender/blenkernel/intern/tracking_region_tracker.c
  28. * \ingroup bke
  29. *
  30. * This file contains implementation of blender-side region tracker
  31. * which is used for 2D feature tracking.
  32. */
  33. #include "MEM_guardedalloc.h"
  34. #include "DNA_movieclip_types.h"
  35. #include "BLI_utildefines.h"
  36. #include "BLI_threads.h"
  37. #include "BKE_tracking.h"
  38. #include "BKE_movieclip.h"
  39. #include "IMB_imbuf_types.h"
  40. #include "IMB_imbuf.h"
  41. #include "libmv-capi.h"
  42. #include "tracking_private.h"
  43. /* **** utility functions for tracking **** */
  44. /* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
  45. static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels,
  46. float weight_red, float weight_green, float weight_blue)
  47. {
  48. int i;
  49. for (i = 0; i < num_pixels; i++) {
  50. const float *pixel = rgba + 4 * i;
  51. gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
  52. }
  53. }
  54. static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels,
  55. float weight_red, float weight_green, float weight_blue)
  56. {
  57. int i;
  58. for (i = 0; i < num_pixels; i++) {
  59. const unsigned char *pixel = rgba + i * 4;
  60. gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
  61. }
  62. }
  63. /* Get grayscale float search buffer for given marker and frame. */
  64. static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
  65. int *width_r, int *height_r)
  66. {
  67. ImBuf *searchibuf;
  68. float *gray_pixels;
  69. int width, height;
  70. searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
  71. if (!searchibuf) {
  72. *width_r = 0;
  73. *height_r = 0;
  74. return NULL;
  75. }
  76. width = searchibuf->x;
  77. height = searchibuf->y;
  78. gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
  79. if (searchibuf->rect_float) {
  80. float_rgba_to_gray(searchibuf->rect_float, gray_pixels, width * height,
  81. 0.2126f, 0.7152f, 0.0722f);
  82. }
  83. else {
  84. uint8_rgba_to_float_gray((unsigned char *)searchibuf->rect, gray_pixels, width * height,
  85. 0.2126f, 0.7152f, 0.0722f);
  86. }
  87. IMB_freeImBuf(searchibuf);
  88. *width_r = width;
  89. *height_r = height;
  90. return gray_pixels;
  91. }
  92. /* Get image buffer for a given frame
  93. *
  94. * Frame is in clip space.
  95. */
  96. static ImBuf *tracking_context_get_frame_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, int framenr)
  97. {
  98. ImBuf *ibuf;
  99. MovieClipUser new_user = *user;
  100. new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
  101. ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
  102. return ibuf;
  103. }
  104. /* Get image buffer for previous marker's keyframe. */
  105. static ImBuf *tracking_context_get_keyframed_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
  106. MovieTrackingTrack *track, int curfra, bool backwards,
  107. MovieTrackingMarker **marker_keyed_r)
  108. {
  109. MovieTrackingMarker *marker_keyed;
  110. int keyed_framenr;
  111. marker_keyed = tracking_get_keyframed_marker(track, curfra, backwards);
  112. if (marker_keyed == NULL) {
  113. return NULL;
  114. }
  115. keyed_framenr = marker_keyed->framenr;
  116. *marker_keyed_r = marker_keyed;
  117. return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
  118. }
  119. /* Get image buffer which si used as referece for track. */
  120. static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
  121. MovieTrackingTrack *track, int curfra, bool backwards,
  122. MovieTrackingMarker **reference_marker)
  123. {
  124. ImBuf *ibuf = NULL;
  125. if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
  126. ibuf = tracking_context_get_keyframed_ibuf(clip, user, clip_flag, track, curfra, backwards, reference_marker);
  127. }
  128. else {
  129. ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
  130. /* use current marker as keyframed position */
  131. *reference_marker = BKE_tracking_marker_get(track, curfra);
  132. }
  133. return ibuf;
  134. }
  135. /* Fill in libmv tracker options structure with settings need to be used to perform track. */
  136. void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
  137. libmv_TrackRegionOptions *options)
  138. {
  139. options->motion_model = track->motion_model;
  140. options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
  141. options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) != 0);
  142. options->num_iterations = 50;
  143. options->minimum_correlation = track->minimum_correlation;
  144. options->sigma = 0.9;
  145. if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
  146. options->image1_mask = mask;
  147. else
  148. options->image1_mask = NULL;
  149. }
  150. /* Peform tracking from a reference_marker to destination_ibuf.
  151. * Uses marker as an initial position guess.
  152. *
  153. * Returns truth if tracker returned success, puts result
  154. * to dst_pixel_x and dst_pixel_y.
  155. */
  156. static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrack *track,
  157. MovieTrackingMarker *reference_marker, MovieTrackingMarker *marker,
  158. float *reference_search_area, int reference_search_area_width,
  159. int reference_search_area_height, float *mask,
  160. double dst_pixel_x[5], double dst_pixel_y[5])
  161. {
  162. /* To convert to the x/y split array format for libmv. */
  163. double src_pixel_x[5], src_pixel_y[5];
  164. /* Settings for the tracker */
  165. libmv_TrackRegionOptions options = {0};
  166. libmv_TrackRegionResult result;
  167. float *patch_new;
  168. int new_search_area_width, new_search_area_height;
  169. int frame_width, frame_height;
  170. bool tracked;
  171. frame_width = destination_ibuf->x;
  172. frame_height = destination_ibuf->y;
  173. /* for now track to the same search area dimension as marker has got for current frame
  174. * will make all tracked markers in currently tracked segment have the same search area
  175. * size, but it's quite close to what is actually needed
  176. */
  177. patch_new = track_get_search_floatbuf(destination_ibuf, track, marker,
  178. &new_search_area_width, &new_search_area_height);
  179. /* configure the tracker */
  180. tracking_configure_tracker(track, mask, &options);
  181. /* convert the marker corners and center into pixel coordinates in the search/destination images. */
  182. tracking_get_marker_coords_for_tracking(frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
  183. tracking_get_marker_coords_for_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
  184. if (patch_new == NULL || reference_search_area == NULL)
  185. return false;
  186. /* run the tracker! */
  187. tracked = libmv_trackRegion(&options,
  188. reference_search_area,
  189. reference_search_area_width,
  190. reference_search_area_height,
  191. patch_new,
  192. new_search_area_width,
  193. new_search_area_height,
  194. src_pixel_x, src_pixel_y,
  195. &result,
  196. dst_pixel_x, dst_pixel_y);
  197. MEM_freeN(patch_new);
  198. return tracked;
  199. }
  200. static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
  201. MovieTrackingMarker *marker,
  202. bool backwards,
  203. int *reference_framenr)
  204. {
  205. const MovieTrackingMarker *first_marker = track->markers;
  206. const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
  207. MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
  208. while (reference >= first_marker &&
  209. reference <= last_marker &&
  210. (reference->flag & MARKER_DISABLED) != 0)
  211. {
  212. if (backwards)
  213. reference++;
  214. else
  215. reference--;
  216. }
  217. if (reference < first_marker ||
  218. reference > last_marker)
  219. {
  220. return false;
  221. }
  222. *reference_framenr = reference->framenr;
  223. return (reference->flag & MARKER_DISABLED) == 0;
  224. }
  225. /* Refine marker's position using previously known keyframe.
  226. * Direction of searching for a keyframe depends on backwards flag,
  227. * which means if backwards is false, previous keyframe will be as
  228. * reference.
  229. */
  230. void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards)
  231. {
  232. MovieTrackingMarker *reference_marker = NULL;
  233. ImBuf *reference_ibuf, *destination_ibuf;
  234. float *search_area, *mask = NULL;
  235. int frame_width, frame_height;
  236. int search_area_height, search_area_width;
  237. int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
  238. int reference_framenr;
  239. MovieClipUser user = {0};
  240. double dst_pixel_x[5], dst_pixel_y[5];
  241. bool tracked;
  242. /* Construct a temporary clip used, used to acquire image buffers. */
  243. user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
  244. BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
  245. /* Get an image buffer for reference frame, also gets reference marker. */
  246. if (!refine_marker_reference_frame_get(track,
  247. marker,
  248. backwards,
  249. &reference_framenr))
  250. {
  251. return;
  252. }
  253. reference_ibuf = tracking_context_get_reference_ibuf(clip, &user, clip_flag, track, reference_framenr,
  254. backwards, &reference_marker);
  255. if (reference_ibuf == NULL) {
  256. return;
  257. }
  258. /* Could not refine with self. */
  259. if (reference_marker == marker) {
  260. return;
  261. }
  262. /* Destination image buffer has got frame number corresponding to refining marker. */
  263. destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
  264. if (destination_ibuf == NULL) {
  265. IMB_freeImBuf(reference_ibuf);
  266. return;
  267. }
  268. /* Get search area from reference image. */
  269. search_area = track_get_search_floatbuf(reference_ibuf, track, reference_marker,
  270. &search_area_width, &search_area_height);
  271. /* If needed, compute track's mask. */
  272. if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
  273. mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
  274. /* Run the tracker from reference frame to current one. */
  275. tracked = configure_and_run_tracker(destination_ibuf, track, reference_marker, marker,
  276. search_area, search_area_width, search_area_height,
  277. mask, dst_pixel_x, dst_pixel_y);
  278. /* Refine current marker's position if track was successful. */
  279. if (tracked) {
  280. tracking_set_marker_coords_from_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
  281. marker->flag |= MARKER_TRACKED;
  282. }
  283. /* Free memory used for refining */
  284. MEM_freeN(search_area);
  285. if (mask)
  286. MEM_freeN(mask);
  287. IMB_freeImBuf(reference_ibuf);
  288. IMB_freeImBuf(destination_ibuf);
  289. }