4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2011 Blender Foundation.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation,
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/blenkernel/intern/tracking.c
38 #include "MEM_guardedalloc.h"
40 #include "DNA_movieclip_types.h"
41 #include "DNA_object_types.h" /* SELECT */
42 #include "DNA_scene_types.h"
44 #include "BLI_utildefines.h"
46 #include "BLI_listbase.h"
47 #include "BLI_ghash.h"
49 #include "BKE_global.h"
50 #include "BKE_tracking.h"
51 #include "BKE_movieclip.h"
52 #include "BKE_object.h"
53 #include "BKE_scene.h"
55 #include "IMB_imbuf_types.h"
56 #include "IMB_imbuf.h"
59 #include "libmv-capi.h"
62 /*********************** common functions *************************/
64 void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event)
70 if(track->pat_min[a]>track->pat_max[a])
71 SWAP(float, track->pat_min[a], track->pat_max[a]);
73 if(track->search_min[a]>track->search_max[a])
74 SWAP(float, track->search_min[a], track->search_max[a]);
77 if(event==CLAMP_PAT_DIM) {
79 /* pattern shouldn't be resized bigger than search */
80 track->pat_min[a]= MAX2(track->pat_min[a], track->search_min[a]);
81 track->pat_max[a]= MIN2(track->pat_max[a], track->search_max[a]);
84 else if(event==CLAMP_PAT_POS) {
86 sub_v2_v2v2(dim, track->pat_max, track->pat_min);
89 /* pattern shouldn't be moved outside of search */
90 if(track->pat_min[a] < track->search_min[a]) {
91 track->pat_min[a]= track->search_min[a];
92 track->pat_max[a]= track->pat_min[a]+dim[a];
94 if(track->pat_max[a] > track->search_max[a]) {
95 track->pat_max[a]= track->search_max[a];
96 track->pat_min[a]= track->pat_max[a]-dim[a];
100 else if(event==CLAMP_SEARCH_DIM) {
101 for(a= 0; a<2; a++) {
102 /* search shouldn't be resized smaller than pattern */
103 track->search_min[a]= MIN2(track->pat_min[a], track->search_min[a]);
104 track->search_max[a]= MAX2(track->pat_max[a], track->search_max[a]);
107 else if(event==CLAMP_SEARCH_POS) {
109 sub_v2_v2v2(dim, track->search_max, track->search_min);
111 for(a= 0; a<2; a++) {
112 /* search shouldn't be moved inside pattern */
113 if(track->search_min[a] > track->pat_min[a]) {
114 track->search_min[a]= track->pat_min[a];
115 track->search_max[a]= track->search_min[a]+dim[a];
117 if(track->search_max[a] < track->pat_max[a]) {
118 track->search_max[a]= track->pat_max[a];
119 track->search_min[a]= track->search_max[a]-dim[a];
124 /* marker's center should be in center of pattern */
125 if(event==CLAMP_PAT_DIM || event==CLAMP_PAT_POS) {
127 sub_v2_v2v2(dim, track->pat_max, track->pat_min);
129 for(a= 0; a<2; a++) {
130 track->pat_min[a]= -dim[a]/2.f;
131 track->pat_max[a]= dim[a]/2.f;
136 void BKE_tracking_track_flag(MovieTrackingTrack *track, int area, int flag, int clear)
138 if(area==TRACK_AREA_NONE)
142 if(area&TRACK_AREA_POINT) track->flag&= ~flag;
143 if(area&TRACK_AREA_PAT) track->pat_flag&= ~flag;
144 if(area&TRACK_AREA_SEARCH) track->search_flag&= ~flag;
146 if(area&TRACK_AREA_POINT) track->flag|= flag;
147 if(area&TRACK_AREA_PAT) track->pat_flag|= flag;
148 if(area&TRACK_AREA_SEARCH) track->search_flag|= flag;
152 MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, float x, float y,
153 int framenr, int width, int height)
155 MovieTrackingTrack *track;
156 MovieTrackingMarker marker;
157 float pat[2]= {5.5f, 5.5f}, search[2]= {80.5f, 80.5f}; /* TODO: move to default setting? */
159 pat[0] /= (float)width;
160 pat[1] /= (float)height;
162 search[0] /= (float)width;
163 search[1] /= (float)height;
165 track= MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track");
166 strcpy(track->name, "Track");
168 memset(&marker, 0, sizeof(marker));
171 marker.framenr= framenr;
173 copy_v2_v2(track->pat_max, pat);
174 negate_v2_v2(track->pat_min, pat);
176 copy_v2_v2(track->search_max, search);
177 negate_v2_v2(track->search_min, search);
179 BKE_tracking_insert_marker(track, &marker);
181 BLI_addtail(&tracking->tracks, track);
182 BKE_track_unique_name(tracking, track);
187 void BKE_tracking_insert_marker(MovieTrackingTrack *track, MovieTrackingMarker *marker)
189 MovieTrackingMarker *old_marker= BKE_tracking_get_marker(track, marker->framenr);
191 if(old_marker && old_marker->framenr==marker->framenr) {
192 *old_marker= *marker;
194 int a= track->markersnr;
197 if(track->markers[a].framenr<marker->framenr)
203 if(track->markers) track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
204 else track->markers= MEM_callocN(sizeof(MovieTrackingMarker), "MovieTracking markers");
206 memmove(track->markers+a+2, track->markers+a+1, (track->markersnr-a-2)*sizeof(MovieTrackingMarker));
207 track->markers[a+1]= *marker;
209 track->last_marker= a+1;
213 void BKE_tracking_delete_marker(MovieTrackingTrack *track, int framenr)
217 while(a<track->markersnr) {
218 if(track->markers[a].framenr==framenr) {
219 if(track->markersnr>1) {
220 memmove(track->markers+a, track->markers+a+1, (track->markersnr-a-1)*sizeof(MovieTrackingMarker));
222 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
224 MEM_freeN(track->markers);
225 track->markers= NULL;
236 MovieTrackingMarker *BKE_tracking_get_marker(MovieTrackingTrack *track, int framenr)
238 int a= track->markersnr-1;
240 if(!track->markersnr)
243 /* approximate pre-first framenr marker with first marker */
244 if(framenr<track->markers[0].framenr)
245 return &track->markers[0];
247 if(track->last_marker<track->markersnr)
248 a= track->last_marker;
250 if(track->markers[a].framenr<=framenr) {
251 while(a<track->markersnr && track->markers[a].framenr<=framenr) {
252 if(track->markers[a].framenr==framenr) {
253 track->last_marker= a;
254 return &track->markers[a];
259 /* if there's no marker for exact position, use nearest marker from left side */
260 return &track->markers[a-1];
262 while(a>=0 && track->markers[a].framenr>=framenr) {
263 if(track->markers[a].framenr==framenr) {
264 track->last_marker= a;
265 return &track->markers[a];
271 /* if there's no marker for exact position, use nearest marker from left side */
272 return &track->markers[a];
278 MovieTrackingMarker *BKE_tracking_ensure_marker(MovieTrackingTrack *track, int framenr)
280 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
282 if(marker && marker->framenr!=framenr) {
283 MovieTrackingMarker marker_new;
286 marker_new.framenr= framenr;
288 BKE_tracking_insert_marker(track, &marker_new);
289 marker= BKE_tracking_get_marker(track, framenr);
295 MovieTrackingMarker *BKE_tracking_exact_marker(MovieTrackingTrack *track, int framenr)
297 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
299 if(marker && marker->framenr!=framenr)
305 int BKE_tracking_has_marker(MovieTrackingTrack *track, int framenr)
307 return BKE_tracking_exact_marker(track, framenr) != 0;
310 void BKE_tracking_free_track(MovieTrackingTrack *track)
312 if(track->markers) MEM_freeN(track->markers);
315 MovieTrackingTrack *BKE_tracking_copy_track(MovieTrackingTrack *track)
317 MovieTrackingTrack *new_track= MEM_dupallocN(track);
319 new_track->next= new_track->prev= NULL;
321 if(new_track->markers)
322 new_track->markers= MEM_dupallocN(new_track->markers);
327 void BKE_tracking_clear_path(MovieTrackingTrack *track, int ref_frame, int action)
331 if(action==TRACK_CLEAR_REMAINED) {
333 while(a<track->markersnr) {
334 if(track->markers[a].framenr>ref_frame) {
336 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
343 } else if(action==TRACK_CLEAR_UPTO) {
344 a= track->markersnr-1;
346 if(track->markers[a].framenr<=ref_frame) {
347 memmove(track->markers, track->markers+a, (track->markersnr-a)*sizeof(MovieTrackingMarker));
349 track->markersnr= track->markersnr-a;
350 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
357 } else if(action==TRACK_CLEAR_ALL) {
358 MovieTrackingMarker *marker, marker_new;
360 marker= BKE_tracking_get_marker(track, ref_frame);
364 MEM_freeN(track->markers);
365 track->markers= NULL;
369 BKE_tracking_insert_marker(track, &marker_new);
373 int BKE_tracking_test_join_tracks(MovieTrackingTrack *dst_track, MovieTrackingTrack *src_track)
375 int i, a= 0, b= 0, tot= dst_track->markersnr+src_track->markersnr;
378 for(i= 0; i<tot; i++) {
379 if(a>=src_track->markersnr) {
383 else if(b>=dst_track->markersnr) {
387 else if(src_track->markers[a].framenr<dst_track->markers[b].framenr) {
390 } else if(src_track->markers[a].framenr>dst_track->markers[b].framenr) {
394 if((src_track->markers[a].flag&MARKER_DISABLED)==0 && (dst_track->markers[b].flag&MARKER_DISABLED)==0)
406 void BKE_tracking_join_tracks(MovieTrackingTrack *dst_track, MovieTrackingTrack *src_track)
408 int i, a= 0, b= 0, tot;
409 MovieTrackingMarker *markers;
411 tot= BKE_tracking_test_join_tracks(dst_track, src_track);
413 markers= MEM_callocN(tot*sizeof(MovieTrackingMarker), "tracking joined tracks");
415 for(i= 0; i<tot; i++) {
416 if(b>=dst_track->markersnr) {
417 markers[i]= src_track->markers[a++];
419 else if(a>=src_track->markersnr) {
420 markers[i]= dst_track->markers[b++];
422 else if(src_track->markers[a].framenr<dst_track->markers[b].framenr) {
423 markers[i]= src_track->markers[a++];
424 } else if(src_track->markers[a].framenr>dst_track->markers[b].framenr) {
425 markers[i]= dst_track->markers[b++];
427 if((src_track->markers[a].flag&MARKER_DISABLED)) markers[i]= dst_track->markers[b];
428 else markers[i]= src_track->markers[a++];
435 MEM_freeN(dst_track->markers);
437 dst_track->markers= markers;
438 dst_track->markersnr= tot;
441 void BKE_tracking_free(MovieTracking *tracking)
443 MovieTrackingTrack *track;
445 for(track= tracking->tracks.first; track; track= track->next) {
446 BKE_tracking_free_track(track);
449 BLI_freelistN(&tracking->tracks);
451 if(tracking->camera.reconstructed)
452 MEM_freeN(tracking->camera.reconstructed);
454 if(tracking->stabilization.ibuf)
455 IMB_freeImBuf(tracking->stabilization.ibuf);
457 if(tracking->stabilization.scaleibuf)
458 IMB_freeImBuf(tracking->stabilization.scaleibuf);
461 /*********************** tracking *************************/
463 typedef struct TrackContext {
464 MovieTrackingTrack *track;
467 struct libmv_RegionTracker *region_tracker;
471 typedef struct MovieTrackingContext {
475 TrackContext *track_context;
479 MovieTrackingSettings settings;
483 } MovieTrackingContext;
485 MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, int backwards)
487 MovieTrackingContext *context= MEM_callocN(sizeof(MovieTrackingContext), "trackingContext");
488 MovieTracking *tracking= &clip->tracking;
489 MovieTrackingSettings *settings= &tracking->settings;
490 MovieTrackingTrack *track;
491 TrackContext *track_context;
493 context->settings= *settings;
494 context->backwards= backwards;
495 context->hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "tracking trackHash");
496 context->sync_frame= user->framenr;
499 track= tracking->tracks.first;
501 if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
502 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
504 if((marker->flag&MARKER_DISABLED)==0)
505 context->num_tracks++;
511 if(context->num_tracks) {
514 BKE_movieclip_acquire_size(clip, user, &width, &height);
516 /* create tracking data */
517 context->track_context= MEM_callocN(sizeof(TrackContext)*context->num_tracks, "tracking track_context");
519 track_context= context->track_context;
520 track= tracking->tracks.first;
522 if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
523 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
525 if((marker->flag&MARKER_DISABLED)==0) {
526 MovieTrackingTrack *new_track= BKE_tracking_copy_track(track);
528 track_context->track= new_track;
532 float search_size_x= (track->search_max[0]-track->search_min[0])*width;
533 float search_size_y= (track->search_max[1]-track->search_min[1])*height;
534 float pattern_size_x= (track->pat_max[0]-track->pat_min[0])*width;
535 float pattern_size_y= (track->pat_max[1]-track->pat_min[1])*height;
537 int level= log(2.0f * MIN2(search_size_x, search_size_y) / MAX2(pattern_size_x, pattern_size_y))/M_LN2;
539 track_context->region_tracker= libmv_regionTrackerNew(100, level, 0.2);
543 BLI_ghash_insert(context->hash, new_track, track);
554 context->user= *user;
559 void BKE_tracking_context_free(MovieTrackingContext *context)
562 TrackContext *track_context;
564 for(a= 0, track_context= context->track_context; a<context->num_tracks; a++, track_context++) {
565 BKE_tracking_free_track(context->track_context[a].track);
568 libmv_regionTrackerDestroy(track_context->region_tracker);
571 MEM_freeN(track_context->track);
574 if(context->track_context)
575 MEM_freeN(context->track_context);
577 BLI_ghash_free(context->hash, NULL, NULL);
582 static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track)
586 if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0)
589 for(y= 0; y<ibuf->y; y++) {
590 for (x= 0; x<ibuf->x; x++) {
591 int pixel= ibuf->x*y + x;
593 if(ibuf->rect_float) {
594 float *rrgbf= ibuf->rect_float + pixel*4;
596 if(track->flag&TRACK_DISABLE_RED) rrgbf[0]= 0;
597 if(track->flag&TRACK_DISABLE_GREEN) rrgbf[1]= 0;
598 if(track->flag&TRACK_DISABLE_BLUE) rrgbf[2]= 0;
600 char *rrgb= (char*)ibuf->rect + pixel*4;
602 if(track->flag&TRACK_DISABLE_RED) rrgb[0]= 0;
603 if(track->flag&TRACK_DISABLE_GREEN) rrgb[1]= 0;
604 if(track->flag&TRACK_DISABLE_BLUE) rrgb[2]= 0;
610 static ImBuf *acquire_area_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
611 float min[2], float max[2], int margin, float pos[2], int origin[2])
615 int x1, y1, x2, y2, w, h;
617 x= marker->pos[0]*ibuf->x;
618 y= marker->pos[1]*ibuf->y;
619 x1= x-(int)(-min[0]*ibuf->x);
620 y1= y-(int)(-min[1]*ibuf->y);
621 x2= x+(int)(max[0]*ibuf->x);
622 y2= y+(int)(max[1]*ibuf->y);
624 /* dimensions should be odd */
628 /* happens due to rounding issues */
632 tmpibuf= IMB_allocImBuf(w+margin*2, h+margin*2, 32, IB_rect);
633 IMB_rectcpy(tmpibuf, ibuf, 0, 0, x1-margin, y1-margin, w+margin*2, h+margin*2);
636 pos[0]= x-x1+(marker->pos[0]*ibuf->x-x)+margin;
637 pos[1]= y-y1+(marker->pos[1]*ibuf->y-y)+margin;
641 origin[0]= x1-margin;
642 origin[1]= y1-margin;
645 disable_imbuf_channels(tmpibuf, track);
650 ImBuf *BKE_tracking_acquire_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
651 int margin, float pos[2], int origin[2])
653 return acquire_area_imbuf(ibuf, track, marker, track->pat_min, track->pat_max, margin, pos, origin);
656 ImBuf *BKE_tracking_acquire_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
657 int margin, float pos[2], int origin[2])
659 return acquire_area_imbuf(ibuf, track, marker, track->search_min, track->search_max, margin, pos, origin);
663 static float *acquire_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
664 int *width_r, int *height_r, float pos[2], int origin[2])
668 int x, y, width, height;
670 width= (track->search_max[0]-track->search_min[0])*ibuf->x;
671 height= (track->search_max[1]-track->search_min[1])*ibuf->y;
673 tmpibuf= BKE_tracking_acquire_search_imbuf(ibuf, track, marker, 0, pos, origin);
674 disable_imbuf_channels(tmpibuf, track);
679 fp= pixels= MEM_callocN(width*height*sizeof(float), "tracking floatBuf");
680 for(y= 0; y<(int)height; y++) {
681 for (x= 0; x<(int)width; x++) {
682 int pixel= tmpibuf->x*y + x;
684 if(tmpibuf->rect_float) {
685 float *rrgbf= ibuf->rect_float + pixel*4;
687 *fp= (0.2126*rrgbf[0] + 0.7152*rrgbf[1] + 0.0722*rrgbf[2])/255;
689 char *rrgb= (char*)tmpibuf->rect + pixel*4;
691 *fp= (0.2126*rrgb[0] + 0.7152*rrgb[1] + 0.0722*rrgb[2])/255;
698 IMB_freeImBuf(tmpibuf);
704 void BKE_tracking_sync(MovieTrackingContext *context)
706 TrackContext *track_context;
707 MovieTrackingTrack *track;
708 ListBase tracks= {NULL, NULL};
709 ListBase *old_tracks= &context->clip->tracking.tracks;
710 int a, sel_type, newframe;
713 BKE_movieclip_last_selection(context->clip, &sel_type, &sel);
715 /* duplicate currently tracking tracks to list of displaying tracks */
716 for(a= 0, track_context= context->track_context; a<context->num_tracks; a++, track_context++) {
718 MovieTrackingTrack *new_track, *old;
720 track= track_context->track;
722 /* find original of tracking track in list of previously displayed tracks */
723 old= BLI_ghash_lookup(context->hash, track);
725 MovieTrackingTrack *cur= old_tracks->first;
734 /* original track was found, re-use flags and remove this track */
736 if(sel_type==MCLIP_SEL_TRACK && sel==cur)
739 track->flag= cur->flag;
740 track->pat_flag= cur->pat_flag;
741 track->search_flag= cur->search_flag;
743 BKE_tracking_free_track(cur);
744 BLI_freelinkN(old_tracks, cur);
748 new_track= BKE_tracking_copy_track(track);
750 BLI_ghash_remove(context->hash, track, NULL, NULL); /* XXX: are we actually need this */
751 BLI_ghash_insert(context->hash, track, new_track);
753 if(replace_sel) /* update current selection in clip */
754 BKE_movieclip_set_selection(context->clip, MCLIP_SEL_TRACK, new_track);
756 BLI_addtail(&tracks, new_track);
759 /* move tracks, which could be added by user during tracking */
760 track= old_tracks->first;
762 MovieTrackingTrack *next= track->next;
764 track->next= track->prev= NULL;
765 BLI_addtail(&tracks, track);
770 context->clip->tracking.tracks= tracks;
772 if(context->backwards) newframe= context->user.framenr+1;
773 else newframe= context->user.framenr-1;
775 context->sync_frame= newframe;
778 void BKE_tracking_sync_user(MovieClipUser *user, MovieTrackingContext *context)
780 user->framenr= context->sync_frame;
783 int BKE_tracking_next(MovieTrackingContext *context)
785 ImBuf *ibuf, *ibuf_new;
786 int curfra= context->user.framenr;
789 /* nothing to track, avoid unneeded frames reading to save time and memory */
790 if(!context->num_tracks)
793 ibuf= BKE_movieclip_acquire_ibuf(context->clip, &context->user);
796 if(context->backwards) context->user.framenr--;
797 else context->user.framenr++;
799 ibuf_new= BKE_movieclip_acquire_ibuf(context->clip, &context->user);
805 #pragma omp parallel for private(a) shared(ibuf, ibuf_new, ok)
806 for(a= 0; a<context->num_tracks; a++) {
807 TrackContext *track_context= &context->track_context[a];
808 MovieTrackingTrack *track= track_context->track;
809 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, curfra);
811 if(marker && (marker->flag&MARKER_DISABLED)==0 && marker->framenr==curfra) {
813 int width, height, origin[2];
815 float *patch, *patch_new;
816 double x1, y1, x2, y2;
818 MovieTrackingMarker marker_new;
820 patch= acquire_search_floatbuf(ibuf, track, marker, &width, &height, pos, origin);
821 patch_new= acquire_search_floatbuf(ibuf_new, track, marker, &width, &height, pos, origin);
829 wndx= (int)((track->pat_max[0]-track->pat_min[0])*ibuf->x)/2;
830 wndy= (int)((track->pat_max[1]-track->pat_min[1])*ibuf->y)/2;
832 if(libmv_regionTrackerTrack(track_context->region_tracker, patch, patch_new,
833 width, height, MAX2(wndx, wndy),
835 memset(&marker_new, 0, sizeof(marker_new));
836 marker_new.pos[0]= (origin[0]+x2)/ibuf_new->x;
837 marker_new.pos[1]= (origin[1]+y2)/ibuf_new->y;
838 marker_new.flag|= MARKER_TRACKED;
840 if(context->backwards) marker_new.framenr= curfra-1;
841 else marker_new.framenr= curfra+1;
845 BKE_tracking_insert_marker(track, &marker_new);
851 if(context->backwards) marker_new.framenr--;
852 else marker_new.framenr++;
854 marker_new.flag|= MARKER_DISABLED;
858 BKE_tracking_insert_marker(track, &marker_new);
863 MEM_freeN(patch_new);
871 IMB_freeImBuf(ibuf_new);
877 static struct libmv_Tracks *create_libmv_tracks(MovieClip *clip)
881 MovieTrackingTrack *track;
882 struct libmv_Tracks *tracks= libmv_tracksNew();;
884 /* XXX: could fail if footage uses images with different sizes */
885 BKE_movieclip_acquire_size(clip, NULL, &width, &height);
887 track= clip->tracking.tracks.first;
891 for(a= 0; a<track->markersnr; a++) {
892 MovieTrackingMarker *marker= &track->markers[a];
894 if((marker->flag&MARKER_DISABLED)==0)
895 libmv_tracksInsert(tracks, marker->framenr, tracknr, marker->pos[0]*width, marker->pos[1]*height);
905 static int retrive_libmv_reconstruct(MovieClip *clip, struct libmv_Reconstruction *reconstruction)
908 int sfra= INT_MAX, efra= INT_MIN, a, origin_set= 0;
909 MovieTracking *tracking= &clip->tracking;
910 MovieTrackingTrack *track;
911 MovieTrackingCamera *camera;
912 MovieReconstructedCamera *reconstructed;
913 float origin[3]= {0.0f, 0.f, 0.0f};
916 track= tracking->tracks.first;
920 if(libmv_reporojectionPointForTrack(reconstruction, tracknr, pos)) {
921 track->bundle_pos[0]= pos[0];
922 track->bundle_pos[1]= pos[1];
923 track->bundle_pos[2]= pos[2];
925 track->flag|= TRACK_HAS_BUNDLE;
927 track->flag&= ~TRACK_HAS_BUNDLE;
930 printf("No bundle for track #%d '%s'\n", tracknr, track->name);
933 if(track->markersnr) {
934 if(track->markers[0].framenr<sfra) sfra= track->markers[0].framenr;
935 if(track->markers[track->markersnr-1].framenr>efra) efra= track->markers[track->markersnr-1].framenr;
942 camera= &tracking->camera;
944 if(camera->reconstructed)
945 MEM_freeN(camera->reconstructed);
948 camera->reconstructed= NULL;
949 reconstructed= MEM_callocN((efra-sfra+1)*sizeof(MovieReconstructedCamera), "temp reconstructed camera");
951 for(a= sfra; a<=efra; a++) {
954 if(libmv_reporojectionCameraForImage(reconstruction, a, matd)) {
960 mat[i][j]= matd[i][j];
963 copy_v3_v3(origin, mat[3]);
968 sub_v3_v3(mat[3], origin);
970 copy_m4_m4(reconstructed[camera->reconnr].mat, mat);
971 reconstructed[camera->reconnr].framenr= a;
975 printf("No camera for frame %d\n", a);
979 if(camera->reconnr) {
980 camera->reconstructed= MEM_callocN(camera->reconnr*sizeof(MovieReconstructedCamera), "reconstructed camera");
981 memcpy(camera->reconstructed, reconstructed, camera->reconnr*sizeof(MovieReconstructedCamera));
985 track= tracking->tracks.first;
987 if(track->flag&TRACK_HAS_BUNDLE)
988 sub_v3_v3(track->bundle_pos, origin);
994 MEM_freeN(reconstructed);
1001 float BKE_tracking_solve_reconstruction(MovieClip *clip)
1005 MovieTrackingCamera *camera= &clip->tracking.camera;
1006 MovieTracking *tracking= &clip->tracking;
1007 struct libmv_Tracks *tracks= create_libmv_tracks(clip);
1008 struct libmv_Reconstruction *reconstruction = libmv_solveReconstruction(tracks,
1009 tracking->settings.keyframe1, tracking->settings.keyframe2,
1010 camera->focal, camera->principal[0], camera->principal[1],
1011 camera->k1, camera->k2, camera->k3);
1012 float error= libmv_reprojectionError(reconstruction);
1014 if(!retrive_libmv_reconstruct(clip, reconstruction))
1017 libmv_destroyReconstruction(reconstruction);
1018 libmv_tracksDestroy(tracks);
1025 void BKE_track_unique_name(MovieTracking *tracking, MovieTrackingTrack *track)
1027 BLI_uniquename(&tracking->tracks, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
1030 MovieTrackingTrack *BKE_find_track_by_name(MovieTracking *tracking, const char *name)
1032 MovieTrackingTrack *track= tracking->tracks.first;
1035 if(!strcmp(track->name, name))
1044 MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking, int framenr)
1046 MovieTrackingCamera *camera= &tracking->camera;
1049 if(!camera->reconnr)
1052 if(camera->last_camera<camera->reconnr)
1053 a= camera->last_camera;
1055 if(camera->reconstructed[a].framenr>=framenr)
1058 while(a>=0 && a<camera->reconnr) {
1059 if(camera->reconstructed[a].framenr==framenr) {
1060 camera->last_camera= a;
1061 return &camera->reconstructed[a];
1072 void BKE_get_tracking_mat(Scene *scene, float mat[4][4])
1075 scene->camera= scene_find_camera(scene);
1078 where_is_object_mat(scene, scene->camera, mat);
1083 void BKE_tracking_projection_matrix(MovieTracking *tracking, int framenr, int winx, int winy, float mat[4][4])
1085 MovieReconstructedCamera *camera;
1086 float lens= tracking->camera.focal*32.0f/(float)winx;
1087 float viewfac, pixsize, left, right, bottom, top, clipsta, clipend;
1094 viewfac= (lens*winx)/32.0f;
1096 viewfac= (lens*winy)/32.0f;
1098 pixsize= clipsta/viewfac;
1100 left= -0.5f*(float)winx*pixsize;
1101 bottom= -0.5f*(float)winy*pixsize;
1102 right= 0.5f*(float)winx*pixsize;
1103 top= 0.5f*(float)winy*pixsize;
1105 perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
1107 camera= BKE_tracking_get_reconstructed_camera(tracking, framenr);
1111 invert_m4_m4(imat, camera->mat);
1112 mul_m4_m4m4(mat, imat, winmat);
1113 } else copy_m4_m4(mat, winmat);
1116 void BKE_tracking_apply_intrinsics(MovieTracking *tracking, float co[2], float width, float height, float nco[2])
1118 MovieTrackingCamera *camera= &tracking->camera;
1123 /* normalize coords */
1124 x= (co[0]-camera->principal[0]) / camera->focal;
1125 y= (co[1]-camera->principal[1]) / camera->focal;
1127 libmv_applyCameraIntrinsics(camera->focal, camera->principal[0], camera->principal[1],
1128 camera->k1, camera->k2, camera->k3, x, y, &x, &y);
1130 /* result is in image coords already */
1136 void BKE_tracking_invert_intrinsics(MovieTracking *tracking, float co[2], float width, float height, float nco[2])
1138 MovieTrackingCamera *camera= &tracking->camera;
1141 double x= co[0], y= co[1];
1143 libmv_InvertIntrinsics(camera->focal, camera->principal[0], camera->principal[1],
1144 camera->k1, camera->k2, camera->k3, x, y, &x, &y);
1146 nco[0]= x * camera->focal + camera->principal[0];
1147 nco[1]= y * camera->focal + camera->principal[1];
1152 /* flips upside-down */
1153 static unsigned char *acquire_ucharbuf(ImBuf *ibuf)
1156 unsigned char *pixels, *fp;
1158 fp= pixels= MEM_callocN(ibuf->x*ibuf->y*sizeof(unsigned char), "tracking ucharBuf");
1159 for(y= 0; y<ibuf->y; y++) {
1160 for (x= 0; x<ibuf->x; x++) {
1161 int pixel= ibuf->x*(ibuf->y-y-1) + x;
1163 if(ibuf->rect_float) {
1164 float *rrgbf= ibuf->rect_float + pixel*4;
1166 //*fp= 0.2126f*rrgbf[0] + 0.7152f*rrgbf[1] + 0.0722f*rrgbf[2];
1167 *fp= (11*rrgbf[0]+16*rrgbf[1]+5*rrgbf[2])/32;
1169 char *rrgb= (char*)ibuf->rect + pixel*4;
1171 //*fp= 0.2126f*rrgb[0] + 0.7152f*rrgb[1] + 0.0722f*rrgb[2];
1172 *fp= (11*rrgb[0]+16*rrgb[1]+5*rrgb[2])/32;
1183 void BKE_tracking_detect(MovieTracking *tracking, ImBuf *ibuf, int framenr)
1186 struct libmv_Corners *corners;
1187 unsigned char *pixels= acquire_ucharbuf(ibuf);
1190 corners= libmv_detectCorners(pixels, ibuf->x, ibuf->y, ibuf->x);
1193 a= libmv_countCorners(corners);
1195 MovieTrackingTrack *track;
1197 float x, y, size, score;
1199 libmv_getCorner(corners, a, &x, &y, &score, &size);
1201 track= BKE_tracking_add_track(tracking, x/ibuf->x, 1.0f-(y/ibuf->y), framenr, ibuf->x, ibuf->y);
1202 track->flag|= SELECT;
1203 track->pat_flag|= SELECT;
1204 track->search_flag|= SELECT;
1207 libmv_destroyCorners(corners);
1211 MovieTrackingTrack *BKE_tracking_indexed_bundle(MovieTracking *tracking, int bundlenr)
1213 MovieTrackingTrack *track= tracking->tracks.first;
1217 if(track->flag&TRACK_HAS_BUNDLE) {
1230 static int stabilization_median_point(MovieTracking *tracking, int framenr, float median[2])
1233 float min[2], max[2];
1234 MovieTrackingTrack *track;
1236 INIT_MINMAX2(min, max);
1238 track= tracking->tracks.first;
1240 if(track->flag&TRACK_USE_2D_STAB) {
1241 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
1243 DO_MINMAX2(marker->pos, min, max);
1251 median[0]= (max[0]+min[0])/2.f;
1252 median[1]= (max[1]+min[1])/2.f;
1257 static float stabilization_auto_scale_factor(MovieTracking *tracking)
1259 float firstmedian[2];
1260 MovieTrackingStabilization *stab= &tracking->stabilization;
1265 if(stabilization_median_point(tracking, 1, firstmedian)) {
1266 int sfra= INT_MAX, efra= INT_MIN, cfra;
1267 float delta[2]= {0.f, 0.f}, scalex, scaley, near[2]={1.f, 1.f};
1268 MovieTrackingTrack *track;
1270 track= tracking->tracks.first;
1272 if(track->flag&TRACK_USE_2D_STAB) {
1273 if(track->markersnr) {
1274 sfra= MIN2(sfra, track->markers[0].framenr);
1275 efra= MAX2(efra, track->markers[track->markersnr-1].framenr);
1282 for(cfra=sfra; cfra<=efra; cfra++) {
1283 float median[2], d[2];
1285 stabilization_median_point(tracking, cfra, median);
1287 sub_v2_v2v2(d, firstmedian, median);
1291 delta[0]= MAX2(delta[0], d[0]);
1292 delta[1]= MAX2(delta[1], d[1]);
1294 near[0]= MIN3(near[0], median[0], 1.f-median[0]);
1295 near[1]= MIN3(near[1], median[1], 1.f-median[1]);
1298 near[0]= MAX2(near[0], 0.05);
1299 near[1]= MAX2(near[1], 0.05);
1301 scalex= 1.f+delta[0]/near[0];
1302 scaley= 1.f+delta[1]/near[1];
1304 stab->scale= MAX2(scalex, scaley);
1314 static void calculate_stabmat(MovieTrackingStabilization *stab, float width, float height,
1315 float firstmedian[2], float curmedian[2], float mat[4][4])
1319 mat[0][0]= stab->scale;
1320 mat[1][1]= stab->scale;
1321 mat[2][2]= stab->scale;
1322 mat[3][0]= (firstmedian[0]-curmedian[0])*width*stab->scale;
1323 mat[3][1]= (firstmedian[1]-curmedian[1])*height*stab->scale;
1325 mat[3][0]-= (firstmedian[0]*stab->scale-firstmedian[0])*width;
1326 mat[3][1]-= (firstmedian[1]*stab->scale-firstmedian[1])*height;
1329 static int stabilize_need_recalc(MovieTracking *tracking, float width, float height,
1330 float firstmedian[2], float curmedian[2], float mat[4][4])
1332 float stabmat[4][4];
1333 MovieTrackingStabilization *stab= &tracking->stabilization;
1338 if(stab->flag&TRACKING_AUTOSCALE)
1339 stabilization_auto_scale_factor(tracking);
1341 calculate_stabmat(stab, width, height, firstmedian, curmedian, stabmat);
1343 return memcmp(mat, stabmat, sizeof(float)*16);
1346 static ImBuf* stabilize_acquire_ibuf(ImBuf *cacheibuf, ImBuf *srcibuf, int fill)
1350 if(cacheibuf && (cacheibuf->x != srcibuf->x || cacheibuf->y != srcibuf->y)) {
1351 IMB_freeImBuf(cacheibuf);
1357 if(srcibuf->rect_float)
1358 flags|= IB_rectfloat;
1362 float col[4]= {0.f, 0.f, 0.f, 0.f};
1363 IMB_rectfill(cacheibuf, col);
1367 cacheibuf= IMB_allocImBuf(srcibuf->x, srcibuf->y, srcibuf->depth, flags);
1368 cacheibuf->profile= srcibuf->profile;
1374 void BKE_tracking_stabilization_matrix(MovieTracking *tracking, int framenr, int width, int height, float mat[4][4])
1376 float firstmedian[2], curmedian[2], stabmat[4][4];
1377 MovieTrackingStabilization *stab= &tracking->stabilization;
1379 copy_m4_m4(stabmat, mat);
1381 if((stab->flag&TRACKING_2D_STABILIZATION)==0) {
1387 if(stabilization_median_point(tracking, 1, firstmedian)) {
1388 stabilization_median_point(tracking, framenr, curmedian);
1390 if((stab->flag&TRACKING_AUTOSCALE)==0)
1393 if(!stab->ok && stab->ibufok && stab->ibuf)
1394 stab->ibufok= stabilize_need_recalc(tracking, width, height, firstmedian, curmedian, mat) == 0;
1396 if(!stab->ibuf || !stab->ibufok) {
1397 if(stab->flag&TRACKING_AUTOSCALE)
1398 stabilization_auto_scale_factor(tracking);
1400 calculate_stabmat(stab, width, height, firstmedian, curmedian, stabmat);
1404 calculate_stabmat(stab, width, height, firstmedian, curmedian, stabmat);
1411 copy_m4_m4(mat, stabmat);
1414 ImBuf *BKE_tracking_stabilize_shot(MovieTracking *tracking, int framenr, ImBuf *ibuf, float mat[4][4])
1416 float firstmedian[2], curmedian[2], stabmat[4][4];
1417 MovieTrackingStabilization *stab= &tracking->stabilization;
1420 copy_m4_m4(stabmat, mat);
1422 if((stab->flag&TRACKING_2D_STABILIZATION)==0) {
1429 if(stabilization_median_point(tracking, 1, firstmedian)) {
1431 float width= ibuf->x, height= ibuf->y;
1433 stabilization_median_point(tracking, framenr, curmedian);
1435 if((stab->flag&TRACKING_AUTOSCALE)==0)
1438 if(!stab->ok && stab->ibufok && stab->ibuf)
1439 stab->ibufok= stabilize_need_recalc(tracking, width, height, firstmedian, curmedian, mat) == 0;
1441 if(!stab->ibuf || !stab->ibufok) {
1442 tmpibuf= stabilize_acquire_ibuf(stab->ibuf, ibuf, 1);
1443 stab->ibuf= tmpibuf;
1445 if(stab->flag&TRACKING_AUTOSCALE) {
1448 stabilization_auto_scale_factor(tracking);
1450 scaleibuf= stabilize_acquire_ibuf(stab->scaleibuf, ibuf, 0);
1451 stab->scaleibuf= scaleibuf;
1453 IMB_rectcpy(scaleibuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
1454 IMB_scalefastImBuf(scaleibuf, ibuf->x*stab->scale, ibuf->y*stab->scale);
1459 calculate_stabmat(stab, width, height, firstmedian, curmedian, stabmat);
1461 IMB_rectcpy(tmpibuf, ibuf, stabmat[3][0], stabmat[3][1], 0, 0, ibuf->x, ibuf->y);
1463 tmpibuf->userflags|= IB_MIPMAP_INVALID;
1465 if(tmpibuf->rect_float)
1466 tmpibuf->userflags|= IB_RECT_INVALID;
1468 calculate_stabmat(stab, width, height, firstmedian, curmedian, stabmat);
1469 tmpibuf= stab->ibuf;
1472 stab->ibuf= tmpibuf;
1473 IMB_refImBuf(stab->ibuf);
1476 copy_m4_m4(mat, stabmat);
1487 copy_m4_m4(mat, stabmat);