Merge remote-tracking branch 'origin/blender-v2.81-release'
[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
64     prev = i;
65   }
66
67   return (count % 2) ? true : false;
68 }
69
70 /* Check whether point is inside any stroke of grease pencil layer. */
71 static bool check_point_in_layer(bGPDlayer *layer, float x, float y)
72 {
73   bGPDframe *frame = layer->frames.first;
74
75   while (frame) {
76     bGPDstroke *stroke = frame->strokes.first;
77
78     while (stroke) {
79       if (check_point_in_stroke(stroke, x, y)) {
80         return true;
81       }
82
83       stroke = stroke->next;
84     }
85     frame = frame->next;
86   }
87
88   return false;
89 }
90
91 /* Get features detected by libmv and create tracks on the clip for them. */
92 static void detect_retrieve_libmv_features(MovieTracking *tracking,
93                                            ListBase *tracksbase,
94                                            struct libmv_Features *features,
95                                            int framenr,
96                                            int width,
97                                            int height,
98                                            bGPDlayer *layer,
99                                            bool place_outside_layer)
100 {
101   int a;
102
103   a = libmv_countFeatures(features);
104   while (a--) {
105     MovieTrackingTrack *track;
106     double x, y, size, score;
107     bool ok = true;
108     float xu, yu;
109
110     libmv_getFeature(features, a, &x, &y, &score, &size);
111
112     /* In Libmv integer coordinate points to pixel center, in blender
113      * it's not. Need to add 0.5px offset to center.
114      */
115     xu = (x + 0.5) / width;
116     yu = (y + 0.5) / height;
117
118     if (layer) {
119       ok = check_point_in_layer(layer, xu, yu) != place_outside_layer;
120     }
121
122     if (ok) {
123       track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height);
124       track->flag |= SELECT;
125       track->pat_flag |= SELECT;
126       track->search_flag |= SELECT;
127     }
128   }
129 }
130
131 static void run_configured_detector(MovieTracking *tracking,
132                                     ListBase *tracksbase,
133                                     ImBuf *ibuf,
134                                     int framenr,
135                                     bGPDlayer *layer,
136                                     bool place_outside_layer,
137                                     libmv_DetectOptions *options)
138 {
139   struct libmv_Features *features = NULL;
140
141   if (ibuf->rect_float) {
142     features = libmv_detectFeaturesFloat(ibuf->rect_float, ibuf->x, ibuf->y, 4, options);
143   }
144   else if (ibuf->rect) {
145     features = libmv_detectFeaturesByte((unsigned char *)ibuf->rect, ibuf->x, ibuf->y, 4, options);
146   }
147
148   if (features != NULL) {
149     detect_retrieve_libmv_features(
150         tracking, tracksbase, features, framenr, ibuf->x, ibuf->y, layer, 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,
158                               ListBase *tracksbase,
159                               ImBuf *ibuf,
160                               int framenr,
161                               int margin,
162                               int min_trackness,
163                               int min_distance,
164                               bGPDlayer *layer,
165                               bool place_outside_layer)
166 {
167   libmv_DetectOptions options = {0};
168
169   options.detector = LIBMV_DETECTOR_FAST;
170   options.margin = margin;
171   options.min_distance = min_distance;
172   options.fast_min_trackness = min_trackness;
173
174   run_configured_detector(
175       tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
176 }
177
178 /* Detect features using Harris detector */
179 void BKE_tracking_detect_harris(MovieTracking *tracking,
180                                 ListBase *tracksbase,
181                                 ImBuf *ibuf,
182                                 int framenr,
183                                 int margin,
184                                 float threshold,
185                                 int min_distance,
186                                 bGPDlayer *layer,
187                                 bool place_outside_layer)
188 {
189   libmv_DetectOptions options = {0};
190
191   options.detector = LIBMV_DETECTOR_HARRIS;
192   options.margin = margin;
193   options.min_distance = min_distance;
194   options.harris_threshold = threshold;
195
196   run_configured_detector(
197       tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
198 }