Skip to content

Commit 62618de

Browse files
author
swayfreeda
committed
new task4 for class4 incremental structure from motion
1 parent 1a6e86e commit 62618de

17 files changed

+2460
-0
lines changed

examples/task4/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
project(class4)
2+
set(CMAKE_CXX_STANDARD 11)
3+
set(CMAKE_CXX_FLAGS "-fPIC")
4+
5+
include_directories("../..")
6+
7+
set(INCREMENTAL_SFM_SOURCES
8+
class4_test_incremental_sfm.cc defines.h functions.cc functions.h)
9+
add_executable(task4_incremental_sfm ${INCREMENTAL_SFM_SOURCES})
10+
target_link_libraries(task4_incremental_sfm sfm util core features)
11+

examples/task4/class4_test_incremental_sfm.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//// Created by caoqi on 2018/8/28.//#include "defines.h"#include "functions.h"#include "sfm/bundler_common.h"#include "sfm/bundler_features.h"#include "sfm/bundler_matching.h"#include "sfm/bundler_intrinsics.h"#include "sfm/bundler_init_pair.h"#include "sfm/bundler_tracks.h"#include "sfm/bundler_incremental.h"#include "core/scene.h"#include "util/timer.h"#include <util/file_system.h>#include <core/bundle_io.h>#include <core/camera.h>#include <fstream>#include <iostream>/** *\description 创建一个场景 * @param image_folder_path * @param scene_path * @return */core::Scene::Ptrmake_scene(const std::string & image_folder_path, const std::string & scene_path){ util::WallTimer timer; /*** 创建文件夹 ***/ const std::string views_path = util::fs::join_path(scene_path, "views/"); util::fs::mkdir(scene_path.c_str()); util::fs::mkdir(views_path.c_str()); /***扫描文件夹,获取所有的图像文件路径***/ util::fs::Directory dir; try {dir.scan(image_folder_path); } catch (std::exception&e){ std::cerr << "Error scanning input dir: " << e.what() << std::endl; std::exit(EXIT_FAILURE); } std::cout << "Found " << dir.size() << " directory entries." << std::endl; core::Scene::Ptr scene= core::Scene::create(""); /**** 开始加载图像 ****/ std::sort(dir.begin(), dir.end()); int num_imported = 0; for(std::size_t i=0; i< dir.size(); i++){ // 是一个文件夹 if(dir[i].is_dir){ std::cout<<"Skipping directory "<<dir[i].name<<std::endl; continue; } std::string fname = dir[i].name; std::string afname = dir[i].get_absolute_name(); // 从可交换信息文件中读取图像焦距 std::string exif; core::ImageBase::Ptr image = load_any_image(afname, & exif); if(image == nullptr){ continue; } core::View::Ptr view = core::View::create(); view->set_id(num_imported); view->set_name(remove_file_extension(fname)); // 限制图像尺寸 int orig_width = image->width(); image = limit_image_size(image, MAX_PIXELS); if (orig_width == image->width() && has_jpeg_extension(fname)) view->set_image_ref(afname, "original"); else view->set_image(image, "original"); add_exif_to_view(view, exif); scene->get_views().push_back(view); /***保存视角信息到本地****/ std::string mve_fname = make_image_name(num_imported); std::cout << "Importing image: " << fname << ", writing MVE view: " << mve_fname << "..." << std::endl; view->save_view_as(util::fs::join_path(views_path, mve_fname)); num_imported+=1; } std::cout << "Imported " << num_imported << " input images, " << "took " << timer.get_elapsed() << " ms." << std::endl; return scene;}/** * * @param scene * @param viewports * @param pairwise_matching */voidfeatures_and_matching (core::Scene::Ptr scene, sfm::bundler::ViewportList* viewports, sfm::bundler::PairwiseMatching* pairwise_matching){ /* Feature computation for the scene. */ sfm::bundler::Features::Options feature_opts; feature_opts.image_embedding = "original"; feature_opts.max_image_size = MAX_PIXELS; feature_opts.feature_options.feature_types = sfm::FeatureSet::FEATURE_SIFT; std::cout << "Computing image features..." << std::endl; { util::WallTimer timer; sfm::bundler::Features bundler_features(feature_opts); bundler_features.compute(scene, viewports); std::cout << "Computing features took " << timer.get_elapsed() << " ms." << std::endl; std::cout<<"Feature detection took " + util::string::get(timer.get_elapsed()) + "ms."<<std::endl; } /* Exhaustive matching between all pairs of views. */ sfm::bundler::Matching::Options matching_opts; //matching_opts.ransac_opts.max_iterations = 1000; //matching_opts.ransac_opts.threshold = 0.0015; matching_opts.ransac_opts.verbose_output = false; matching_opts.use_lowres_matching = false; matching_opts.match_num_previous_frames = false; matching_opts.matcher_type = sfm::bundler::Matching::MATCHER_EXHAUSTIVE; std::cout << "Performing feature matching..." << std::endl; { util::WallTimer timer; sfm::bundler::Matching bundler_matching(matching_opts); bundler_matching.init(viewports); bundler_matching.compute(pairwise_matching); std::cout << "Matching took " << timer.get_elapsed() << " ms." << std::endl; std::cout<< "Feature matching took " + util::string::get(timer.get_elapsed()) + "ms."<<std::endl; } if (pairwise_matching->empty()) { std::cerr << "Error: No matching image pairs. Exiting." << std::endl; std::exit(EXIT_FAILURE); }}int main(int argc, char *argv[]){ if(argc < 3){ std::cout<<"Usage: [input]image_dir [output]scen_dir"<<std::endl; return -1; } core::Scene::Ptr scene = make_scene(argv[1], argv[2]); std::cout<<"Scene has "<<scene->get_views().size()<<" views. "<<std::endl; sfm::bundler::ViewportList viewports; sfm::bundler::PairwiseMatching pairwise_matching; features_and_matching(scene, &viewports, &pairwise_matching ); /* Drop descriptors and embeddings to save memory. */ scene->cache_cleanup(); for (std::size_t i = 0; i < viewports.size(); ++i) viewports[i].features.clear_descriptors(); /* Check if there are some matching images. */ if (pairwise_matching.empty()) { std::cerr << "No matching image pairs. Exiting." << std::endl; std::exit(EXIT_FAILURE); } // 计算相机内参数,从Exif中读取 { sfm::bundler::Intrinsics::Options intrinsics_opts; std::cout << "Initializing camera intrinsics..." << std::endl; sfm::bundler::Intrinsics intrinsics(intrinsics_opts); intrinsics.compute(scene, &viewports); } /****** 开始增量的捆绑调整*****/ util::WallTimer timer; /* Compute connected feature components, i.e. feature tracks. */ sfm::bundler::TrackList tracks; { sfm::bundler::Tracks::Options tracks_options; tracks_options.verbose_output = true; sfm::bundler::Tracks bundler_tracks(tracks_options); std::cout << "Computing feature tracks..." << std::endl; bundler_tracks.compute(pairwise_matching, &viewports, &tracks); std::cout << "Created a total of " << tracks.size() << " tracks." << std::endl; } /* Remove color data and pairwise matching to save memory. */ for (std::size_t i = 0; i < viewports.size(); ++i) viewports[i].features.colors.clear(); pairwise_matching.clear(); // 计算初始的匹配对 sfm::bundler::InitialPair::Result init_pair_result; sfm::bundler::InitialPair::Options init_pair_opts; //init_pair_opts.homography_opts.max_iterations = 1000; //init_pair_opts.homography_opts.threshold = 0.005f; init_pair_opts.homography_opts.verbose_output = false; init_pair_opts.max_homography_inliers = 0.8f; init_pair_opts.verbose_output = true; // 开始计算初始的匹配对 sfm::bundler::InitialPair init_pair(init_pair_opts); init_pair.initialize(viewports, tracks); init_pair.compute_pair(&init_pair_result); if (init_pair_result.view_1_id < 0 || init_pair_result.view_2_id < 0 || init_pair_result.view_1_id >= static_cast<int>(viewports.size()) || init_pair_result.view_2_id >= static_cast<int>(viewports.size())) { std::cerr << "Error finding initial pair, exiting!" << std::endl; std::cerr << "Try manually specifying an initial pair." << std::endl; std::exit(EXIT_FAILURE); } std::cout << "Using views " << init_pair_result.view_1_id << " and " << init_pair_result.view_2_id << " as initial pair." << std::endl; /* Incrementally compute full bundle. */ sfm::bundler::Incremental::Options incremental_opts; incremental_opts.pose_p3p_opts.max_iterations = 1000; incremental_opts.pose_p3p_opts.threshold = 0.005f; incremental_opts.pose_p3p_opts.verbose_output = false; incremental_opts.track_error_threshold_factor = TRACK_ERROR_THRES_FACTOR; incremental_opts.new_track_error_threshold = NEW_TRACK_ERROR_THRES; incremental_opts.min_triangulation_angle = MATH_DEG2RAD(1.0); incremental_opts.ba_fixed_intrinsics = false; //incremental_opts.ba_shared_intrinsics = conf.shared_intrinsics; incremental_opts.verbose_output = true; incremental_opts.verbose_ba = true; /* Initialize viewports with initial pair. */ viewports[init_pair_result.view_1_id].pose = init_pair_result.view_1_pose; viewports[init_pair_result.view_2_id].pose = init_pair_result.view_2_pose; /* Initialize the incremental bundler and reconstruct first tracks. */ sfm::bundler::Incremental incremental(incremental_opts); incremental.initialize(&viewports, &tracks); // 对当前两个视角进行track重建,并且如果track存在外点,则将每个track的外点剥离成新的track incremental.triangulate_new_tracks(2); // 根据重投影误差进行筛选 incremental.invalidate_large_error_tracks(); /* Run bundle adjustment. */ std::cout << "Running full bundle adjustment..." << std::endl; incremental.bundle_adjustment_full(); /* Reconstruct remaining views. */ int num_cameras_reconstructed = 2; int full_ba_num_skipped = 0; while (true) { /* Find suitable next views for reconstruction. */ std::vector<int> next_views; incremental.find_next_views(&next_views); /* Reconstruct the next view. */ int next_view_id = -1; for (std::size_t i = 0; i < next_views.size(); ++i) { std::cout << std::endl; std::cout << "Adding next view ID " << next_views[i] << " (" << (num_cameras_reconstructed + 1) << " of " << viewports.size() << ")..." << std::endl; if (incremental.reconstruct_next_view(next_views[i])) { next_view_id = next_views[i]; break; } } if (next_view_id < 0) { if (full_ba_num_skipped == 0) { std::cout << "No valid next view." << std::endl; std::cout << "SfM reconstruction finished." << std::endl; break; } else { incremental.triangulate_new_tracks(MIN_VIEWS_PER_TRACK); std::cout << "Running full bundle adjustment..." << std::endl; incremental.bundle_adjustment_full(); incremental.invalidate_large_error_tracks(); full_ba_num_skipped = 0; continue; } } /* Run single-camera bundle adjustment. */ std::cout << "Running single camera bundle adjustment..." << std::endl; incremental.bundle_adjustment_single_cam(next_view_id); num_cameras_reconstructed += 1; /* Run full bundle adjustment only after a couple of views. */ int const full_ba_skip_views = std::min(100, num_cameras_reconstructed / 10); if (full_ba_num_skipped < full_ba_skip_views) { std::cout << "Skipping full bundle adjustment (skipping " << full_ba_skip_views << " views)." << std::endl; full_ba_num_skipped += 1; } else { incremental.triangulate_new_tracks(MIN_VIEWS_PER_TRACK); std::cout << "Running full bundle adjustment..." << std::endl; incremental.bundle_adjustment_full(); incremental.invalidate_large_error_tracks(); full_ba_num_skipped = 0; } } sfm::bundler::TrackList valid_tracks; for(int i=0; i<tracks.size(); i++){ if(tracks[i].is_valid()){ valid_tracks.push_back(tracks[i]); } } std::cout << "SfM reconstruction took " << timer.get_elapsed() << " ms." << std::endl; std::cout<< "SfM reconstruction took " + util::string::get(timer.get_elapsed()) + "ms."<<std::endl; /***** 保存输出结果***/ std::ofstream out_file("./points.ply"); assert(out_file.is_open()); out_file<<"ply"<<std::endl; out_file<<"format ascii 1.0"<<std::endl; out_file<<"element vertex "<<valid_tracks.size()<<std::endl; out_file<<"property float x"<<std::endl; out_file<<"property float y"<<std::endl; out_file<<"property float z"<<std::endl; out_file<<"property uchar red"<<std::endl; out_file<<"property uchar green"<<std::endl; out_file<<"property uchar blue"<<std::endl; out_file<<"end_header"<<std::endl; for(int i=0; i< valid_tracks.size(); i++){ out_file<<valid_tracks[i].pos[0]<<" "<< valid_tracks[i].pos[1]<<" "<<valid_tracks[i].pos[2]<<" " <<(int)valid_tracks[i].color[0]<<" "<<(int)valid_tracks[i].color[1]<<" "<<(int)valid_tracks[i].color[2]<<std::endl; } out_file.close(); /* Normalize scene if requested. */// if (conf.normalize_scene)// {// std::cout << "Normalizing scene..." << std::endl;// incremental.normalize_scene();// } /* Save bundle file to scene. */ std::cout << "Creating bundle data structure..." << std::endl; core::Bundle::Ptr bundle = incremental.create_bundle(); core::save_mve_bundle(bundle, std::string(argv[2]) + "/synth_0.out"); /* Apply bundle cameras to views. */ core::Bundle::Cameras const& bundle_cams = bundle->get_cameras(); core::Scene::ViewList const& views = scene->get_views(); if (bundle_cams.size() != views.size()) { std::cerr << "Error: Invalid number of cameras!" << std::endl; std::exit(EXIT_FAILURE); }#pragma omp parallel for schedule(dynamic,1) for (std::size_t i = 0; i < bundle_cams.size(); ++i) { core::View::Ptr view = views[i]; core::CameraInfo const& cam = bundle_cams[i]; if (view == nullptr) continue; if (view->get_camera().flen == 0.0f && cam.flen == 0.0f) continue; view->set_camera(cam); /* Undistort image. */ if (!undistorted_name.empty()) { core::ByteImage::Ptr original = view->get_byte_image(original_name); if (original == nullptr) continue; core::ByteImage::Ptr undist = core::image::image_undistort_k2k4<uint8_t> (original, cam.flen, cam.dist[0], cam.dist[1]); view->set_image(undist, undistorted_name); }#pragma omp critical std::cout << "Saving view " << view->get_directory() << std::endl; view->save_view(); view->cache_cleanup(); } // log_message(conf, "SfM reconstruction done.\n"); return 0;}

examples/task4/defines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//// Created by caoqi on 2018/8/28.//#ifndef IMAGEBASEDMODELLINGEDU_DEFINES_H#define IMAGEBASEDMODELLINGEDU_DEFINES_H#include <string>#define MAX_PIXELS 6000000// 重建一个三维点需要的最少的视角个数#define MIN_VIEWS_PER_TRACK 2// 用于对Track进行滤波#define TRACK_ERROR_THRES_FACTOR 10.0f// 用于重建新的Ttrakc#define NEW_TRACK_ERROR_THRES 0.01fstatic const std::string undistorted_name = "undistorted";static const std::string original_name = "original";static const std::string exif_name = "exif";static const std::string prebundle_file = "prebundle.sfm";#endif //IMAGEBASEDMODELLINGEDU_DEFINES_H

examples/task4/functions.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//// Created by caoqi on 2018/8/27.//#include "defines.h"#include "functions.h"#include "util/file_system.h"#include "core/image_io.h"#include <iostream>core::ByteImage::Ptrload_8bit_image (std::string const& fname, std::string* exif){ std::string lcfname(util::string::lowercase(fname)); std::string ext4 = util::string::right(lcfname, 4); std::string ext5 = util::string::right(lcfname, 5); try { if (ext4 == ".jpg" || ext5 == ".jpeg") return core::image::load_jpg_file(fname, exif); else if (ext4 == ".png" || ext4 == ".ppm" || ext4 == ".tif" || ext5 == ".tiff") return core::image::load_file(fname); } catch (...) { } return core::ByteImage::Ptr();}core::RawImage::Ptrload_16bit_image (std::string const& fname){ std::string lcfname(util::string::lowercase(fname)); std::string ext4 = util::string::right(lcfname, 4); std::string ext5 = util::string::right(lcfname, 5); try { if (ext4 == ".tif" || ext5 == ".tiff") return core::image::load_tiff_16_file(fname); else if (ext4 == ".ppm") return core::image::load_ppm_16_file(fname); } catch (...) { } return core::RawImage::Ptr();}core::FloatImage::Ptrload_float_image (std::string const& fname){ std::string lcfname(util::string::lowercase(fname)); std::string ext4 = util::string::right(lcfname, 4); try { if (ext4 == ".pfm") return core::image::load_pfm_file(fname); } catch (...) { } return core::FloatImage::Ptr();}core::ImageBase::Ptrload_any_image (std::string const& fname, std::string* exif){ core::ByteImage::Ptr img_8 = load_8bit_image(fname, exif); if (img_8 != nullptr) return img_8; core::RawImage::Ptr img_16 = load_16bit_image(fname); if (img_16 != nullptr) return img_16; core::FloatImage::Ptr img_float = load_float_image(fname); if (img_float != nullptr) return img_float; std::cout << "Skipping file " << util::fs::basename(fname) << ", cannot load image." << std::endl; return core::ImageBase::Ptr();}std::stringremove_file_extension (std::string const& filename){ std::size_t pos = filename.find_last_of('.'); if (pos != std::string::npos) return filename.substr(0, pos); return filename;}core::ImageBase::Ptrlimit_image_size (core::ImageBase::Ptr image, int max_pixels){ switch (image->get_type()) { case core::IMAGE_TYPE_FLOAT: return limit_image_size<float>(std::dynamic_pointer_cast <core::FloatImage>(image), max_pixels); case core::IMAGE_TYPE_UINT8: return limit_image_size<uint8_t>(std::dynamic_pointer_cast <core::ByteImage>(image), max_pixels); case core::IMAGE_TYPE_UINT16: return limit_image_size<uint16_t>(std::dynamic_pointer_cast <core::RawImage>(image), max_pixels); default: break; } return core::ImageBase::Ptr();}boolhas_jpeg_extension (std::string const& filename){ std::string lcfname(util::string::lowercase(filename)); return util::string::right(lcfname, 4) == ".jpg" || util::string::right(lcfname, 5) == ".jpeg";}/* ---------------------------------------------------------------- */std::stringmake_image_name (int id){ return "view_" + util::string::get_filled(id, 4) + ".mve";}voidadd_exif_to_view (core::View::Ptr view, std::string const& exif){ if (exif.empty()) return; core::ByteImage::Ptr exif_image = core::ByteImage::create(exif.size(), 1, 1); std::copy(exif.begin(), exif.end(), exif_image->begin()); view->set_blob(exif_image, "exif");}

0 commit comments

Comments
 (0)