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