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