Blender V4.3
intern/libmv/libmv/simple_pipeline/pipeline.cc
Go to the documentation of this file.
1// Copyright (c) 2011 libmv authors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to
5// deal in the Software without restriction, including without limitation the
6// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7// sell copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19// IN THE SOFTWARE.
20
22
23#include <cstdio>
24
32
33#ifdef _MSC_VER
34# define snprintf _snprintf
35#endif
36
37namespace libmv {
38namespace {
39
40// These are "strategy" classes which make it possible to use the same code for
41// both projective and euclidean reconstruction.
42// FIXME(MatthiasF): OOP would achieve the same goal while avoiding
43// template bloat and making interface changes much easier.
44struct EuclideanPipelineRoutines {
45 typedef EuclideanReconstruction Reconstruction;
46 typedef EuclideanCamera Camera;
47 typedef EuclideanPoint Point;
48
49 static void Bundle(const Tracks& tracks,
50 EuclideanReconstruction* reconstruction) {
52 }
53
54 static bool Resect(const vector<Marker>& markers,
55 EuclideanReconstruction* reconstruction,
56 bool final_pass) {
57 return EuclideanResect(markers, reconstruction, final_pass);
58 }
59
60 static bool Intersect(const vector<Marker>& markers,
61 EuclideanReconstruction* reconstruction) {
63 }
64
65 static Marker ProjectMarker(const EuclideanPoint& point,
66 const EuclideanCamera& camera,
67 const CameraIntrinsics& intrinsics) {
68 Vec3 projected = camera.R * point.X + camera.t;
69 projected /= projected(2);
70
71 Marker reprojected_marker;
72 intrinsics.ApplyIntrinsics(projected(0),
73 projected(1),
74 &reprojected_marker.x,
75 &reprojected_marker.y);
76
77 reprojected_marker.image = camera.image;
78 reprojected_marker.track = point.track;
79 return reprojected_marker;
80 }
81};
82
83struct ProjectivePipelineRoutines {
84 typedef ProjectiveReconstruction Reconstruction;
85 typedef ProjectiveCamera Camera;
86 typedef ProjectivePoint Point;
87
88 static void Bundle(const Tracks& tracks,
89 ProjectiveReconstruction* reconstruction) {
91 }
92
93 static bool Resect(const vector<Marker>& markers,
94 ProjectiveReconstruction* reconstruction,
95 bool final_pass) {
96 (void)final_pass; // Ignored.
97
99 }
100
101 static bool Intersect(const vector<Marker>& markers,
102 ProjectiveReconstruction* reconstruction) {
104 }
105
106 static Marker ProjectMarker(const ProjectivePoint& point,
107 const ProjectiveCamera& camera,
108 const CameraIntrinsics& intrinsics) {
109 Vec3 projected = camera.P * point.X;
110 projected /= projected(2);
111
112 Marker reprojected_marker;
113 intrinsics.ApplyIntrinsics(projected(0),
114 projected(1),
115 &reprojected_marker.x,
116 &reprojected_marker.y);
117
118 reprojected_marker.image = camera.image;
119 reprojected_marker.track = point.track;
120 return reprojected_marker;
121 }
122};
123
124} // namespace
125
127 ProgressUpdateCallback* update_callback,
128 double progress,
129 const char* step = NULL) {
130 if (update_callback) {
131 char message[256];
132
133 if (step) {
134 snprintf(message,
135 sizeof(message),
136 "Completing solution %d%% | %s",
137 (int)(progress * 100),
138 step);
139 } else {
140 snprintf(message,
141 sizeof(message),
142 "Completing solution %d%%",
143 (int)(progress * 100));
144 }
145
146 update_callback->invoke(progress, message);
147 }
148}
149
150template <typename PipelineRoutines>
152 const Tracks& tracks,
153 typename PipelineRoutines::Reconstruction* reconstruction,
154 ProgressUpdateCallback* update_callback = NULL) {
155 int max_track = tracks.MaxTrack();
156 int max_image = tracks.MaxImage();
157 int num_resects = -1;
158 int num_intersects = -1;
159 int tot_resects = 0;
160 LG << "Max track: " << max_track;
161 LG << "Max image: " << max_image;
162 LG << "Number of markers: " << tracks.NumMarkers();
163 while (num_resects != 0 || num_intersects != 0) {
164 // Do all possible intersections.
165 num_intersects = 0;
166 for (int track = 0; track <= max_track; ++track) {
167 if (reconstruction->PointForTrack(track)) {
168 LG << "Skipping point: " << track;
169 continue;
170 }
171 vector<Marker> all_markers = tracks.MarkersForTrack(track);
172 LG << "Got " << all_markers.size() << " markers for track " << track;
173
174 vector<Marker> reconstructed_markers;
175 for (int i = 0; i < all_markers.size(); ++i) {
176 if (reconstruction->CameraForImage(all_markers[i].image)) {
177 reconstructed_markers.push_back(all_markers[i]);
178 }
179 }
180 LG << "Got " << reconstructed_markers.size()
181 << " reconstructed markers for track " << track;
182 if (reconstructed_markers.size() >= 2) {
183 CompleteReconstructionLogProgress(update_callback,
184 double(tot_resects) / (max_image));
185 if (PipelineRoutines::Intersect(reconstructed_markers,
187 num_intersects++;
188 LG << "Ran Intersect() for track " << track;
189 } else {
190 LG << "Failed Intersect() for track " << track;
191 }
192 }
193 }
194 if (num_intersects) {
196 update_callback, double(tot_resects) / (max_image), "Bundling...");
197 PipelineRoutines::Bundle(tracks, reconstruction);
198 LG << "Ran Bundle() after intersections.";
199 }
200 LG << "Did " << num_intersects << " intersects.";
201
202 // Do all possible resections.
203 num_resects = 0;
204 for (int image = 0; image <= max_image; ++image) {
205 if (reconstruction->CameraForImage(image)) {
206 LG << "Skipping frame: " << image;
207 continue;
208 }
209 vector<Marker> all_markers = tracks.MarkersInImage(image);
210 LG << "Got " << all_markers.size() << " markers for image " << image;
211
212 vector<Marker> reconstructed_markers;
213 for (int i = 0; i < all_markers.size(); ++i) {
214 if (reconstruction->PointForTrack(all_markers[i].track)) {
215 reconstructed_markers.push_back(all_markers[i]);
216 }
217 }
218 LG << "Got " << reconstructed_markers.size()
219 << " reconstructed markers for image " << image;
220 if (reconstructed_markers.size() >= 5) {
221 CompleteReconstructionLogProgress(update_callback,
222 double(tot_resects) / (max_image));
223 if (PipelineRoutines::Resect(
224 reconstructed_markers, reconstruction, false)) {
225 num_resects++;
226 tot_resects++;
227 LG << "Ran Resect() for image " << image;
228 } else {
229 LG << "Failed Resect() for image " << image;
230 }
231 }
232 }
233 if (num_resects) {
235 update_callback, double(tot_resects) / (max_image), "Bundling...");
236 PipelineRoutines::Bundle(tracks, reconstruction);
237 }
238 LG << "Did " << num_resects << " resects.";
239 }
240
241 // One last pass...
242 num_resects = 0;
243 for (int image = 0; image <= max_image; ++image) {
244 if (reconstruction->CameraForImage(image)) {
245 LG << "Skipping frame: " << image;
246 continue;
247 }
248 vector<Marker> all_markers = tracks.MarkersInImage(image);
249
250 vector<Marker> reconstructed_markers;
251 for (int i = 0; i < all_markers.size(); ++i) {
252 if (reconstruction->PointForTrack(all_markers[i].track)) {
253 reconstructed_markers.push_back(all_markers[i]);
254 }
255 }
256 if (reconstructed_markers.size() >= 5) {
257 CompleteReconstructionLogProgress(update_callback,
258 double(tot_resects) / (max_image));
259 if (PipelineRoutines::Resect(
260 reconstructed_markers, reconstruction, true)) {
261 num_resects++;
262 LG << "Ran final Resect() for image " << image;
263 } else {
264 LG << "Failed final Resect() for image " << image;
265 }
266 }
267 }
268 if (num_resects) {
270 update_callback, double(tot_resects) / (max_image), "Bundling...");
271 PipelineRoutines::Bundle(tracks, reconstruction);
272 }
273}
274
275template <typename PipelineRoutines>
277 const Tracks& image_tracks,
278 const typename PipelineRoutines::Reconstruction& reconstruction,
279 const CameraIntrinsics& intrinsics) {
280 int num_skipped = 0;
281 int num_reprojected = 0;
282 double total_error = 0.0;
283 vector<Marker> markers = image_tracks.AllMarkers();
284 for (int i = 0; i < markers.size(); ++i) {
285 double weight = markers[i].weight;
286 const typename PipelineRoutines::Camera* camera =
288 const typename PipelineRoutines::Point* point =
290 if (!camera || !point || weight == 0.0) {
291 num_skipped++;
292 continue;
293 }
294 num_reprojected++;
295
296 Marker reprojected_marker =
297 PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
298 double ex = (reprojected_marker.x - markers[i].x) * weight;
299 double ey = (reprojected_marker.y - markers[i].y) * weight;
300
301 const int N = 100;
302 char line[N];
303 snprintf(line,
304 N,
305 "image %-3d track %-3d "
306 "x %7.1f y %7.1f "
307 "rx %7.1f ry %7.1f "
308 "ex %7.1f ey %7.1f"
309 " e %7.1f",
310 markers[i].image,
311 markers[i].track,
312 markers[i].x,
313 markers[i].y,
314 reprojected_marker.x,
315 reprojected_marker.y,
316 ex,
317 ey,
318 sqrt(ex * ex + ey * ey));
319 VLOG(1) << line;
320
321 total_error += sqrt(ex * ex + ey * ey);
322 }
323 LG << "Skipped " << num_skipped << " markers.";
324 LG << "Reprojected " << num_reprojected << " markers.";
325 LG << "Total error: " << total_error << " px";
326 LG << "Average error: " << (total_error / num_reprojected) << " px";
327 return total_error / num_reprojected;
328}
329
330double EuclideanReprojectionError(const Tracks& image_tracks,
332 const CameraIntrinsics& intrinsics) {
334 image_tracks, reconstruction, intrinsics);
335}
336
338 const Tracks& image_tracks,
340 const CameraIntrinsics& intrinsics) {
342 image_tracks, reconstruction, intrinsics);
343}
344
351
357
358void InvertIntrinsicsForTracks(const Tracks& raw_tracks,
359 const CameraIntrinsics& camera_intrinsics,
360 Tracks* calibrated_tracks) {
361 vector<Marker> markers = raw_tracks.AllMarkers();
362 for (int i = 0; i < markers.size(); ++i) {
363 camera_intrinsics.InvertIntrinsics(
364 markers[i].x, markers[i].y, &(markers[i].x), &(markers[i].y));
365 }
366 *calibrated_tracks = Tracks(markers);
367}
368
369} // namespace libmv
sqrt(x)+1/max(0
DBVT_INLINE bool Intersect(const btDbvtAabbMm &a, const btDbvtAabbMm &b)
Definition btDbvt.h:621
virtual void InvertIntrinsics(double image_x, double image_y, double *normalized_x, double *normalized_y) const =0
virtual void invoke(double progress, const char *message)=0
ProjectivePoint * PointForTrack(int track)
Returns a pointer to the point corresponding to track.
ProjectiveCamera * CameraForImage(int image)
Returns a pointer to the camera corresponding to image.
vector< Marker > AllMarkers() const
Returns all the markers.
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
#define NULL
const vector< Marker > & markers
const ProjectiveReconstruction & reconstruction
Definition intersect.cc:198
#define LG
#define VLOG(severity)
Definition log.h:34
#define N
double ProjectiveReprojectionError(const Tracks &image_tracks, const ProjectiveReconstruction &reconstruction, const CameraIntrinsics &intrinsics)
void ProjectiveBundle(const Tracks &, ProjectiveReconstruction *)
Definition bundle.cc:852
bool ProjectiveResect(const vector< Marker > &markers, ProjectiveReconstruction *reconstruction)
Definition resect.cc:225
bool EuclideanResect(const vector< Marker > &markers, EuclideanReconstruction *reconstruction, bool final_pass)
Definition resect.cc:94
static void CompleteReconstructionLogProgress(ProgressUpdateCallback *update_callback, double progress, const char *step=NULL)
void EuclideanBundle(const Tracks &tracks, EuclideanReconstruction *reconstruction)
Definition bundle.cc:650
void EuclideanCompleteReconstruction(const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback)
bool EuclideanIntersect(const vector< Marker > &markers, EuclideanReconstruction *reconstruction)
Definition intersect.cc:69
Eigen::Vector3d Vec3
Definition numeric.h:106
double InternalReprojectionError(const Tracks &image_tracks, const typename PipelineRoutines::Reconstruction &reconstruction, const CameraIntrinsics &intrinsics)
double EuclideanReprojectionError(const Tracks &image_tracks, const EuclideanReconstruction &reconstruction, const CameraIntrinsics &intrinsics)
void InvertIntrinsicsForTracks(const Tracks &raw_tracks, const CameraIntrinsics &camera_intrinsics, Tracks *calibrated_tracks)
bool ProjectiveIntersect(const vector< Marker > &markers, ProjectiveReconstruction *reconstruction)
Definition intersect.cc:203
void InternalCompleteReconstruction(const Tracks &tracks, typename PipelineRoutines::Reconstruction *reconstruction, ProgressUpdateCallback *update_callback=NULL)
void ProjectiveCompleteReconstruction(const Tracks &tracks, ProjectiveReconstruction *reconstruction)