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) {
51 EuclideanBundle(tracks, 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) {
62 return EuclideanIntersect(markers, 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) {
90 ProjectiveBundle(tracks, reconstruction);
91 }
92
93 static bool Resect(const vector<Marker>& markers,
94 ProjectiveReconstruction* reconstruction,
95 bool final_pass) {
96 (void)final_pass; // Ignored.
97
98 return ProjectiveResect(markers, reconstruction);
99 }
100
101 static bool Intersect(const vector<Marker>& markers,
102 ProjectiveReconstruction* reconstruction) {
103 return ProjectiveIntersect(markers, 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,
186 reconstruction)) {
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 =
287 reconstruction.CameraForImage(markers[i].image);
288 const typename PipelineRoutines::Point* point =
289 reconstruction.PointForTrack(markers[i].track);
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,
331 const EuclideanReconstruction& reconstruction,
332 const CameraIntrinsics& intrinsics) {
334 image_tracks, reconstruction, intrinsics);
335}
336
338 const Tracks& image_tracks,
339 const ProjectiveReconstruction& reconstruction,
340 const CameraIntrinsics& intrinsics) {
342 image_tracks, reconstruction, intrinsics);
343}
344
346 EuclideanReconstruction* reconstruction,
347 ProgressUpdateCallback* update_callback) {
349 tracks, reconstruction, update_callback);
350}
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
DBVT_INLINE bool Intersect(const btDbvtAabbMm &a, const btDbvtAabbMm &b)
Definition btDbvt.h:621
virtual void ApplyIntrinsics(double normalized_x, double normalized_y, double *image_x, double *image_y) const =0
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
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
#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
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
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)
int track
Definition marker.h:43
ListBase tracks
Definition tracking.cc:70