Merge branch 'blender2.7'
[blender.git] / source / blender / blenkernel / intern / tracking_detect.c
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
20 /** \file \ingroup bke
21  *
22  * This file contains blender-side implementation of feature detection.
23  */
24
25 #include "DNA_gpencil_types.h"
26 #include "DNA_movieclip_types.h"
27 #include "DNA_object_types.h"   /* SELECT */
28
29 #include "BLI_utildefines.h"
30
31 #include "BKE_tracking.h"
32
33 #include "IMB_imbuf_types.h"
34
35 #include "libmv-capi.h"
36
37 /* Check whether point is inside grease pencil stroke. */
38 static bool check_point_in_stroke(bGPDstroke *stroke, float x, float y)
39 {
40         int i, prev;
41         int count = 0;
42         bGPDspoint *points = stroke->points;
43
44         /* Count intersections of horizontal ray coming from the point.
45          * Point will be inside layer if and only if number of intersection
46          * is uneven.
47          *
48          * Well, if layer has got self-intersections, this logic wouldn't
49          * work, but such situation is crappy anyway.
50          */
51
52         prev = stroke->totpoints - 1;
53
54         for (i = 0; i < stroke->totpoints; i++) {
55                 if ((points[i].y < y && points[prev].y >= y) || (points[prev].y < y && points[i].y >= y)) {
56                         float fac = (y - points[i].y) / (points[prev].y - points[i].y);
57
58                         if (points[i].x + fac * (points[prev].x - points[i].x) < x)
59                                 count++;
60                 }
61
62                 prev = i;
63         }
64
65         return (count % 2) ? true : false;
66 }
67
68 /* Check whether point is inside any stroke of grease pencil layer. */
69 static bool check_point_in_layer(bGPDlayer *layer, float x, float y)
70 {
71         bGPDframe *frame = layer->frames.first;
72
73         while (frame) {
74                 bGPDstroke *stroke = frame->strokes.first;
75
76                 while (stroke) {
77                         if (check_point_in_stroke(stroke, x, y))
78                                 return true;
79
80                         stroke = stroke->next;
81                 }
82                 frame = frame->next;
83         }
84
85         return false;
86 }
87
88 /* Get features detected by libmv and create tracks on the clip for them. */
89 static void detect_retrieve_libmv_features(MovieTracking *tracking, ListBase *tracksbase,
90                                            struct libmv_Features *features, int framenr, int width, int height,
91                                            bGPDlayer *layer, bool place_outside_layer)
92 {
93         int a;
94
95         a = libmv_countFeatures(features);
96         while (a--) {
97                 MovieTrackingTrack *track;
98                 double x, y, size, score;
99                 bool ok = true;
100                 float xu, yu;
101
102                 libmv_getFeature(features, a, &x, &y, &score, &size);
103
104                 /* In Libmv integer coordinate points to pixel center, in blender
105                  * it's not. Need to add 0.5px offset to center.
106                  */
107                 xu = (x + 0.5) / width;
108                 yu = (y + 0.5) / height;
109
110                 if (layer)
111                         ok = check_point_in_layer(layer, xu, yu) != place_outside_layer;
112
113                 if (ok) {
114                         track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height);
115                         track->flag |= SELECT;
116                         track->pat_flag |= SELECT;
117                         track->search_flag |= SELECT;
118                 }
119         }
120 }
121
122 static void run_configured_detector(MovieTracking *tracking, ListBase *tracksbase,
123                                     ImBuf *ibuf, int framenr, bGPDlayer *layer, bool place_outside_layer,
124                                     libmv_DetectOptions *options)
125 {
126         struct libmv_Features *features = NULL;
127
128         if (ibuf->rect_float) {
129                 features = libmv_detectFeaturesFloat(ibuf->rect_float, ibuf->x, ibuf->y, 4, options);
130         }
131         else if (ibuf->rect) {
132                 features = libmv_detectFeaturesByte((unsigned char *) ibuf->rect, ibuf->x, ibuf->y, 4, options);
133         }
134
135         if (features != NULL) {
136                 detect_retrieve_libmv_features(tracking, tracksbase, features,
137                                                framenr, ibuf->x, ibuf->y, layer,
138                                                place_outside_layer);
139
140                 libmv_featuresDestroy(features);
141         }
142 }
143
144 /* Detect features using FAST detector */
145 void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
146                               int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer,
147                               bool place_outside_layer)
148 {
149         libmv_DetectOptions options = {0};
150
151         options.detector = LIBMV_DETECTOR_FAST;
152         options.margin = margin;
153         options.min_distance = min_distance;
154         options.fast_min_trackness = min_trackness;
155
156         run_configured_detector(tracking, tracksbase, ibuf, framenr, layer,
157                                 place_outside_layer, &options);
158 }
159
160 /* Detect features using Harris detector */
161 void BKE_tracking_detect_harris(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
162                                 int framenr, int margin, float threshold, int min_distance, bGPDlayer *layer,
163                                 bool place_outside_layer)
164 {
165         libmv_DetectOptions options = {0};
166
167         options.detector = LIBMV_DETECTOR_HARRIS;
168         options.margin = margin;
169         options.min_distance = min_distance;
170         options.harris_threshold = threshold;
171
172         run_configured_detector(tracking, tracksbase, ibuf, framenr, layer,
173                                 place_outside_layer, &options);
174 }