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 #include "intern/track_region.h"
21 #include "intern/image.h"
22 #include "intern/utildefines.h"
23 #include "libmv/image/image.h"
24 #include "libmv/tracking/track_region.h"
25 
26 /* define this to generate PNG images with content of search areas
27    tracking between which failed */
28 #undef DUMP_FAILURE
29 
30 /* define this to generate PNG images with content of search areas
31    on every iteration of tracking */
32 #undef DUMP_ALWAYS
33 
34 using libmv::FloatImage;
35 using libmv::TrackRegionOptions;
36 using libmv::TrackRegionResult;
37 using libmv::TrackRegion;
38 
libmv_configureTrackRegionOptions(const libmv_TrackRegionOptions & options,TrackRegionOptions * track_region_options)39 void libmv_configureTrackRegionOptions(
40     const libmv_TrackRegionOptions& options,
41     TrackRegionOptions* track_region_options) {
42   switch (options.motion_model) {
43 #define LIBMV_CONVERT(the_model) \
44   case TrackRegionOptions::the_model: \
45     track_region_options->mode = TrackRegionOptions::the_model; \
46     break;
47     LIBMV_CONVERT(TRANSLATION)
48     LIBMV_CONVERT(TRANSLATION_ROTATION)
49     LIBMV_CONVERT(TRANSLATION_SCALE)
50     LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE)
51     LIBMV_CONVERT(AFFINE)
52     LIBMV_CONVERT(HOMOGRAPHY)
53 #undef LIBMV_CONVERT
54   }
55 
56   track_region_options->minimum_correlation = options.minimum_correlation;
57   track_region_options->max_iterations = options.num_iterations;
58   track_region_options->sigma = options.sigma;
59   track_region_options->num_extra_points = 1;
60   track_region_options->image1_mask = NULL;
61   track_region_options->use_brute_initialization = options.use_brute;
62   /* TODO(keir): This will make some cases better, but may be a regression until
63    * the motion model is in. Since this is on trunk, enable it for now.
64    *
65    * TODO(sergey): This gives much worse results on mango footage (see 04_2e)
66    * so disabling for now for until proper prediction model is landed.
67    *
68    * The thing is, currently blender sends input coordinates as the guess to
69    * region tracker and in case of fast motion such an early out ruins the track.
70    */
71   track_region_options->attempt_refine_before_brute = false;
72   track_region_options->use_normalized_intensities = options.use_normalization;
73 }
74 
libmv_regionTrackergetResult(const TrackRegionResult & track_region_result,libmv_TrackRegionResult * result)75 void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result,
76                                   libmv_TrackRegionResult* result) {
77   result->termination = (int) track_region_result.termination;
78   result->termination_reason = "";
79   result->correlation = track_region_result.correlation;
80 }
81 
libmv_trackRegion(const libmv_TrackRegionOptions * options,const float * image1,int image1_width,int image1_height,const float * image2,int image2_width,int image2_height,const double * x1,const double * y1,libmv_TrackRegionResult *,double * x2,double * y2)82 int libmv_trackRegion(const libmv_TrackRegionOptions* options,
83                       const float* image1,
84                       int image1_width,
85                       int image1_height,
86                       const float* image2,
87                       int image2_width,
88                       int image2_height,
89                       const double* x1,
90                       const double* y1,
91                       libmv_TrackRegionResult* /*result*/,
92                       double* x2,
93                       double* y2) {
94   double xx1[5], yy1[5];
95   double xx2[5], yy2[5];
96   bool tracking_result = false;
97 
98   // Convert to doubles for the libmv api. The four corners and the center.
99   for (int i = 0; i < 5; ++i) {
100     xx1[i] = x1[i];
101     yy1[i] = y1[i];
102     xx2[i] = x2[i];
103     yy2[i] = y2[i];
104   }
105 
106   TrackRegionOptions track_region_options;
107   FloatImage image1_mask;
108 
109   libmv_configureTrackRegionOptions(*options, &track_region_options);
110   if (options->image1_mask) {
111     libmv_floatBufferToFloatImage(options->image1_mask,
112                                   image1_width,
113                                   image1_height,
114                                   1,
115                                   &image1_mask);
116 
117     track_region_options.image1_mask = &image1_mask;
118   }
119 
120   // Convert from raw float buffers to libmv's FloatImage.
121   FloatImage old_patch, new_patch;
122   libmv_floatBufferToFloatImage(image1,
123                                 image1_width,
124                                 image1_height,
125                                 1,
126                                 &old_patch);
127   libmv_floatBufferToFloatImage(image2,
128                                 image2_width,
129                                 image2_height,
130                                 1,
131                                 &new_patch);
132 
133   TrackRegionResult track_region_result;
134   TrackRegion(old_patch, new_patch,
135               xx1, yy1,
136               track_region_options,
137               xx2, yy2,
138               &track_region_result);
139 
140   // Convert to floats for the blender api.
141   for (int i = 0; i < 5; ++i) {
142     x2[i] = xx2[i];
143     y2[i] = yy2[i];
144   }
145 
146   // TODO(keir): Update the termination string with failure details.
147   if (track_region_result.termination == TrackRegionResult::CONVERGENCE ||
148       track_region_result.termination == TrackRegionResult::NO_CONVERGENCE) {
149     tracking_result = true;
150   }
151 
152   // Debug dump of patches.
153 #if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS)
154   bool need_dump = !tracking_result;
155 
156 #  ifdef DUMP_ALWAYS
157   need_dump = true;
158 #  endif
159 
160   if (need_dump) {
161     libmv_saveImage(old_patch, "old_patch", x1[4], y1[4]);
162     libmv_saveImage(new_patch, "new_patch", x2[4], y2[4]);
163     if (options->image1_mask) {
164       libmv_saveImage(image1_mask, "mask", x2[4], y2[4]);
165     }
166   }
167 #endif
168 
169   return tracking_result;
170 }
171