diff --git a/.gitignore b/.gitignore index a2f562f..dbfbc78 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,34 @@ *.o *.a *.so +*.dll # emacs temp files *~ + +# Compiled binaries and temporary library files +bin/Bundle2PMVS +bin/Bundle2Ply +bin/Bundle2Vis +bin/KeyMatchFull +bin/RadialUndistort +bin/bundler +lib/ann_1.1_char/lib +lib/f2c/arith.h +lib/f2c/signal1.h +lib/f2c/sysdep1.h +src/Bundle2PMVS +src/Bundle2Ply +src/Bundle2Vis +src/KeyMatchFull +src/RadialUndistort +src/bundler + +# Binaries we depend on +bin/sift + +# misc +list_keys.txt +list_tmp.txt +options.txt +sift.txt diff --git a/README.md b/README.md index 26b57cf..dc3c379 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ based on the Photo Tourism work of Noah Snavely, Steven M. Seitz, For more information, see the Bundler homepage at http://www.cs.cornell.edu/~snavely/bundler/ +or see the FAQ at + http://www.cs.cornell.edu/~snavely/bundler/faq.html What is Bundler? ---------------- diff --git a/bin/extract_focal.pl b/bin/extract_focal.pl index 5a07015..55334e2 100755 --- a/bin/extract_focal.pl +++ b/bin/extract_focal.pl @@ -52,6 +52,8 @@ "Canon Canon EOS 400D DIGITAL" => 22.2, "Canon Canon EOS 40D" => 22.2, "Canon Canon EOS 5D" => 35.8, + "Canon Canon EOS 5D Mark II" => 36.0, + "Canon Canon EOS 5D Mark III" => 36.0, "Canon Canon EOS DIGITAL REBEL" => 22.66, "Canon Canon EOS DIGITAL REBEL XT" => 22.2, "Canon Canon EOS DIGITAL REBEL XTi" => 22.2, @@ -112,6 +114,7 @@ "Canon Canon PowerShot SD700 IS" => 5.76, # 1/2.5" "Canon Canon PowerShot SD750" => 5.75, # 1/2.5" "Canon Canon PowerShot SD800 IS" => 5.76, # 1/2.5" + "Canon Canon PowerShot SX500 IS" => 6.17, # 1/2.3" "Canon EOS 300D DIGITAL" => 22.66, "Canon EOS DIGITAL REBEL" => 22.66, "Canon PowerShot A510" => 5.76, # 1/2.5" ??? diff --git a/src/Bundle.cpp b/src/Bundle.cpp index 9b22a4b..e8178ca 100644 --- a/src/Bundle.cpp +++ b/src/Bundle.cpp @@ -657,10 +657,13 @@ double BundlerApp::RunSFM_SBA(int num_pts, int num_cameras, int start_camera, printf("[RunSFM] run_sfm took %0.3fs\n", (double) (end - start) / (double) CLOCKS_PER_SEC); - /* Check for outliers */ + /* Compute statistics and check for outliers */ start = clock(); + double global_reprojection_error = 0; + int global_num_observations = 0; + std::vector outliers; std::vector reproj_errors; @@ -784,7 +787,8 @@ double BundlerApp::RunSFM_SBA(int num_pts, int num_cameras, int start_camera, iround(0.5 * num_pts_proj), dists), thresh); - // printf("Outlier threshold is %0.3f\n", thresh); + global_reprojection_error += sum; + global_num_observations += num_pts_proj; pt_count = 0; for (int j = 0; j < num_keys; j++) { @@ -846,6 +850,11 @@ double BundlerApp::RunSFM_SBA(int num_pts, int num_cameras, int start_camera, delete [] dists; } + printf("[RunSFM] Global mean reprojection error: %0.3e " + "(%d observations)\n", + global_reprojection_error / global_num_observations, + global_num_observations); + /* Remove outlying points */ if (remove_outliers) { for (int i = 0; i < (int) outliers.size(); i++) { diff --git a/src/BundleCeres.cpp b/src/BundleCeres.cpp index 1d2e5b8..863edcd 100644 --- a/src/BundleCeres.cpp +++ b/src/BundleCeres.cpp @@ -511,6 +511,9 @@ double BundlerApp::RunSFM_Ceres(int num_pts, int num_cameras, start = clock(); + double global_reprojection_error = 0; + int global_num_observations = 0; + std::vector outliers; std::vector outlier_views; std::vector reproj_errors; @@ -649,6 +652,9 @@ double BundlerApp::RunSFM_Ceres(int num_pts, int num_cameras, iround(0.5 * num_pts_proj), dists), thresh); + global_reprojection_error += sum; + global_num_observations += num_pts_proj; + pt_count = 0; for (int j = 0; j < num_keys; j++) { int pt_idx = GetKey(added_order[i],j).m_extra; @@ -715,6 +721,11 @@ double BundlerApp::RunSFM_Ceres(int num_pts, int num_cameras, delete [] dists; } + printf("[RunSFM] Global mean reprojection error: %0.3e " + "(%d observations)\n", + global_reprojection_error / global_num_observations, + global_num_observations); + /* Remove outlying points */ if ((!final_bundle || round > 0) && remove_outliers) { int num_dead = 0; diff --git a/src/BundleIO.cpp b/src/BundleIO.cpp index 1c4651f..5dd47b2 100644 --- a/src/BundleIO.cpp +++ b/src/BundleIO.cpp @@ -1138,8 +1138,7 @@ void BaseApp::DumpPointsToPly(const char *output_directory, const char *filename, int num_points, int num_cameras, v3_t *points, v3_t *colors, - camera_params_t *cameras - /*bool reflect*/) + camera_params_t *cameras) { int num_good_pts = 0; @@ -1174,8 +1173,6 @@ void BaseApp::DumpPointsToPly(const char *output_directory, /* Output the vertex */ fprintf(f, "%0.6e %0.6e %0.6e %d %d %d\n", Vx(points[i]), Vy(points[i]), Vz(points[i]), - // Vx(points[idx]), Vy(points[idx]), Vz(points[idx]), - // (reflect ? -1 : 1) * Vz(points[i]), iround(Vx(colors[i])), iround(Vy(colors[i])), iround(Vz(colors[i]))); @@ -1191,17 +1188,12 @@ void BaseApp::DumpPointsToPly(const char *output_directory, if ((i % 2) == 0) fprintf(f, "%0.6e %0.6e %0.6e 0 255 0\n", c[0], c[1], c[2]); - // (reflect ? -1 : 1) * c[2]); else fprintf(f, "%0.6e %0.6e %0.6e 255 0 0\n", c[0], c[1], c[2]); - // (reflect ? -1 : 1) * c[2]); double p_cam[3] = { 0.0, 0.0, -0.05 }; double p[3]; - // if (!reflect) - // p_cam[2] *= -1.0; - matrix_product(3, 3, 3, 1, Rinv, p_cam, p); p[0] += c[0]; @@ -1209,7 +1201,7 @@ void BaseApp::DumpPointsToPly(const char *output_directory, p[2] += c[2]; fprintf(f, "%0.6e %0.6e %0.6e 255 255 0\n", - p[0], p[1], p[2]); // (reflect ? -1 : 1) * p[2]); + p[0], p[1], p[2]); } fclose(f); diff --git a/src/KeyMatchFull.cpp b/src/KeyMatchFull.cpp index b321f17..6ccd8c8 100644 --- a/src/KeyMatchFull.cpp +++ b/src/KeyMatchFull.cpp @@ -16,7 +16,6 @@ /* KeyMatchFull.cpp */ /* Read in keys, match, write results to a file */ -#include #include #include #include @@ -24,16 +23,49 @@ #include "keys2a.h" +int ReadFileList(char* list_in, std::vector& key_files) { + FILE* fp; + + if ((fp = fopen(list_in, "r")) == NULL) { + printf("Error opening file %s for reading.\n", list_in); + return 1; + } + + char buf[512], *start; + while (fgets(buf, 512, fp)) { + // Remove trailing new-line + if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; + + // Find first non-space character + start = buf; + while(isspace(*start)) start++; + + // Skip empty lines + if (strlen(start) == 0) continue; + + // Append file-name to key_files + key_files.push_back(std::string(buf)); + } + + // Check we found input files + if (key_files.size() == 0) { + printf("No input files found in %s.\n", list_in); + return 1; + } + + return 0; +} + int main(int argc, char **argv) { char *list_in; char *file_out; double ratio; - + if (argc != 3 && argc != 4) { - printf("Usage: %s [window_radius]\n", argv[0]); - return -1; + printf("Usage: %s [window_radius]\n", argv[0]); + return EXIT_FAILURE; } - + list_in = argv[1]; ratio = 0.6; file_out = argv[2]; @@ -45,47 +77,31 @@ int main(int argc, char **argv) { clock_t start = clock(); - unsigned char **keys; - int *num_keys; - /* Read the list of files */ std::vector key_files; - - FILE *f = fopen(list_in, "r"); - if (f == NULL) { - printf("Error opening file %s for reading\n", list_in); - return 1; - } + if (ReadFileList(list_in, key_files) != 0) return EXIT_FAILURE; - char buf[512]; - while (fgets(buf, 512, f)) { - /* Remove trailing newline */ - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = 0; - - key_files.push_back(std::string(buf)); + FILE *f; + if ((f = fopen(file_out, "w")) == NULL) { + printf("Could not open %s for writing.\n", file_out); + return EXIT_FAILURE; } - fclose(f); - - f = fopen(file_out, "w"); - assert(f != NULL); - int num_images = (int) key_files.size(); - keys = new unsigned char *[num_images]; - num_keys = new int[num_images]; + std::vector keys(num_images); + std::vector num_keys(num_images); /* Read all keys */ for (int i = 0; i < num_images; i++) { keys[i] = NULL; - num_keys[i] = ReadKeyFile(key_files[i].c_str(), keys+i); + num_keys[i] = ReadKeyFile(key_files[i].c_str(), &keys[i]); } - clock_t end = clock(); + clock_t end = clock(); printf("[KeyMatchFull] Reading keys took %0.3fs\n", (end - start) / ((double) CLOCKS_PER_SEC)); - + for (int i = 0; i < num_images; i++) { if (num_keys[i] == 0) continue; @@ -109,7 +125,7 @@ int main(int argc, char **argv) { /* Compute likely matches between two sets of keypoints */ std::vector matches = MatchKeys(num_keys[j], keys[j], tree, ratio); - + int num_matches = (int) matches.size(); if (num_matches >= 16) { @@ -126,22 +142,21 @@ int main(int argc, char **argv) { } } - end = clock(); + end = clock(); printf("[KeyMatchFull] Matching took %0.3fs\n", (end - start) / ((double) CLOCKS_PER_SEC)); fflush(stdout); delete tree; } - + /* Free keypoints */ for (int i = 0; i < num_images; i++) { if (keys[i] != NULL) delete [] keys[i]; } - delete [] keys; - delete [] num_keys; - + fclose(f); - return 0; + return EXIT_SUCCESS; } + diff --git a/src/Makefile b/src/Makefile index 1903c3f..7d8ccb3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,6 +5,7 @@ CC=gcc CXX=g++ OPTFLAGS=-O3 -Wall -Wno-unused-result +# OPTFLAGS=-g2 OTHERFLAGS=-std=gnu++0x OS=$(shell uname -o) @@ -39,17 +40,24 @@ BUNDLER_OBJS=BaseApp.o BundlerApp.o keys.o Register.o Epipolar.o \ BundleIO.o ProcessBundle.o BundleTwo.o Decompose.o \ RelativePose.o Distortion.o TwoFrameModel.o LoadJPEG.o -BUNDLER_LIBS=-limage -lsfmdrv -lsba.v1.5 -lmatrix -lz -lblas -llapack \ +BUNDLER_BASE_LIBS=-limage -lsfmdrv -lsba.v1.5 -lmatrix -lz -llapack -lblas \ -lcblas -lminpack -lm -l5point -ljpeg -lANN_char -lgfortran -CERES_LIBS= -lceres -lcholmod -lcolamd -lamd -lcamd -lcxsparse \ +CERES_LIBS=-lceres -lcholmod -lccolamd -lcolamd -lamd -lcamd -lcxsparse \ -lsuitesparseconfig -lgomp -lglog -lpthread # if we are using Ceres, add to options ifeq ($(USE_CERES),true) +# Edit these two variables as needed +CERES_INCLUDE_PATH= +CERES_LIB_PATH= BUNDLER_DEFINES+=-D__USE_CERES__ -BUNDLER_LIBS+=$(CERES_LIBS) +BUNDLER_LIBS=$(CERES_LIBS) $(BUNDLER_BASE_LIBS) BUNDLER_OBJS+=BundleCeres.o +INCLUDE_PATH+=$(CERES_INCLUDE_PATH) +LIB_PATH+=$(CERES_LIB_PATH) INCLUDE_PATH+=-I/usr/include/eigen3 +else +BUNDLER_LIBS=$(BUNDLER_BASE_LIBS) endif CPPFLAGS=$(OPTFLAGS) $(OTHERFLAGS) $(INCLUDE_PATH) diff --git a/utils/bundler.py b/utils/bundler.py index 568b2b5..6fb1bd0 100755 --- a/utils/bundler.py +++ b/utils/bundler.py @@ -81,6 +81,8 @@ "Canon Canon EOS 400D DIGITAL" : 22.2, "Canon Canon EOS 40D" : 22.2, "Canon Canon EOS 5D" : 35.8, + "Canon Canon EOS 5D Mark II" : 36.0, + "Canon Canon EOS 5D Mark III" : 36.0, "Canon Canon EOS DIGITAL REBEL" : 22.66, "Canon Canon EOS DIGITAL REBEL XT" : 22.2, "Canon Canon EOS DIGITAL REBEL XTi" : 22.2, @@ -141,6 +143,7 @@ "Canon Canon PowerShot SD700 IS" : 5.76, # 1/2.5" "Canon Canon PowerShot SD750" : 5.75, # 1/2.5" "Canon Canon PowerShot SD800 IS" : 5.76, # 1/2.5" + "Canon Canon PowerShot SX500 IS" : 6.17, # 1/2.3" "Canon EOS 300D DIGITAL" : 22.66, "Canon EOS DIGITAL REBEL" : 22.66, "Canon PowerShot A510" : 5.76, # 1/2.5" ???