From f09f407db124c68953c83aaf223f544715a65a7b Mon Sep 17 00:00:00 2001 From: Rishabh Singh <reyanshsolis@gmail.com> Date: Sat, 21 May 2022 14:57:06 +0530 Subject: [PATCH] Add default dataset loading in reconstruction system. (#4954) --- cpp/open3d/data/Dataset.cpp | 127 +++++++++++- cpp/open3d/data/Dataset.h | 94 ++++++++- cpp/open3d/t/io/sensor/RGBDVideoReader.cpp | 10 +- cpp/pybind/data/data.cpp | 190 ++++++++++++++---- cpp/tests/data/Dataset.cpp | 6 - docs/tutorial/data/index.rst | 78 +++++++ .../reconstruction_system/integrate_scene.rst | 2 +- .../reconstruction_system/make_fragments.rst | 18 +- .../reconstruction_system/system_overview.rst | 72 +++++-- .../t_reconstruction_system/index.rst | 70 +++++++ .../t_reconstruction_system/integration.rst | 2 +- examples/cpp/OfflineSLAM.cpp | 3 +- examples/cpp/OnlineSLAMRGBD.cpp | 48 ++++- examples/cpp/OnlineSLAMRealSense.cpp | 2 +- examples/python/open3d_example.py | 35 ++-- .../reconstruction_system/colored_icp.py | 87 -------- .../config/indoor_lidar_rgbd/apartment.json | 14 -- .../config/indoor_lidar_rgbd/bedroom.json | 14 -- .../config/indoor_lidar_rgbd/boardroom.json | 14 -- .../config/indoor_lidar_rgbd/lobby.json | 14 -- .../config/indoor_lidar_rgbd/loft.json | 14 -- .../config/redwood_objects/car.json | 14 -- .../config/redwood_objects/chair.json | 14 -- .../config/redwood_objects/motorcycle.json | 14 -- .../config/redwood_objects/plant.json | 14 -- .../config/redwood_objects/sofa.json | 14 -- .../config/redwood_objects/truck.json | 14 -- .../redwood_simulated/livingroom1-clean.json | 23 --- .../livingroom1-simulated.json | 15 -- .../redwood_simulated/livingroom2-clean.json | 14 -- .../livingroom2-simulated.json | 15 -- .../redwood_simulated/office1-clean.json | 14 -- .../redwood_simulated/office1-simulated.json | 15 -- .../redwood_simulated/office2-clean.json | 14 -- .../redwood_simulated/office2-simulated.json | 15 -- .../config/stanford/burghers.json | 14 -- .../config/stanford/cactusgarden.json | 14 -- .../config/stanford/copyroom.json | 14 -- .../config/stanford/lounge.json | 14 -- .../config/stanford/stonewall.json | 14 -- .../config/stanford/totempole.json | 14 -- .../reconstruction_system/data_loader.py | 96 +++++++++ .../initialize_config.py | 53 ++++- .../reconstruction_system/integrate_scene.py | 3 - .../reconstruction_system/make_fragments.py | 14 +- .../reconstruction_system/run_system.py | 20 +- .../reconstruction_system/scripts/__init__.py | 0 .../scripts/download_dataset.py | 90 --------- .../scripts/download_indoor_lidar_rgbd.sh | 18 -- .../scripts/download_redwood_objects.sh | 21 -- .../scripts/download_redwood_simulated.sh | 48 ----- .../scripts/download_stanford.sh | 19 -- .../scripts/download_tutorial.sh | 7 - .../scripts/gdrive_download.sh | 22 -- .../scripts/requirements.txt | 2 - .../scripts/synchronize_frames.py | 115 ----------- .../python/t_reconstruction_system/common.py | 91 +++++++-- .../t_reconstruction_system/dense_slam.py | 17 +- .../t_reconstruction_system/dense_slam_gui.py | 21 +- .../t_reconstruction_system/integrate.py | 4 +- .../integrate_custom.py | 19 +- .../t_reconstruction_system/ray_casting.py | 20 +- 62 files changed, 941 insertions(+), 966 deletions(-) delete mode 100644 examples/python/reconstruction_system/colored_icp.py delete mode 100644 examples/python/reconstruction_system/config/indoor_lidar_rgbd/apartment.json delete mode 100644 examples/python/reconstruction_system/config/indoor_lidar_rgbd/bedroom.json delete mode 100644 examples/python/reconstruction_system/config/indoor_lidar_rgbd/boardroom.json delete mode 100644 examples/python/reconstruction_system/config/indoor_lidar_rgbd/lobby.json delete mode 100644 examples/python/reconstruction_system/config/indoor_lidar_rgbd/loft.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/car.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/chair.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/motorcycle.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/plant.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/sofa.json delete mode 100644 examples/python/reconstruction_system/config/redwood_objects/truck.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/livingroom1-clean.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/livingroom1-simulated.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/livingroom2-clean.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/livingroom2-simulated.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/office1-clean.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/office1-simulated.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/office2-clean.json delete mode 100644 examples/python/reconstruction_system/config/redwood_simulated/office2-simulated.json delete mode 100644 examples/python/reconstruction_system/config/stanford/burghers.json delete mode 100644 examples/python/reconstruction_system/config/stanford/cactusgarden.json delete mode 100644 examples/python/reconstruction_system/config/stanford/copyroom.json delete mode 100644 examples/python/reconstruction_system/config/stanford/lounge.json delete mode 100644 examples/python/reconstruction_system/config/stanford/stonewall.json delete mode 100644 examples/python/reconstruction_system/config/stanford/totempole.json create mode 100644 examples/python/reconstruction_system/data_loader.py delete mode 100644 examples/python/reconstruction_system/scripts/__init__.py delete mode 100644 examples/python/reconstruction_system/scripts/download_dataset.py delete mode 100755 examples/python/reconstruction_system/scripts/download_indoor_lidar_rgbd.sh delete mode 100755 examples/python/reconstruction_system/scripts/download_redwood_objects.sh delete mode 100755 examples/python/reconstruction_system/scripts/download_redwood_simulated.sh delete mode 100755 examples/python/reconstruction_system/scripts/download_stanford.sh delete mode 100755 examples/python/reconstruction_system/scripts/download_tutorial.sh delete mode 100755 examples/python/reconstruction_system/scripts/gdrive_download.sh delete mode 100644 examples/python/reconstruction_system/scripts/requirements.txt delete mode 100644 examples/python/reconstruction_system/scripts/synchronize_frames.py diff --git a/cpp/open3d/data/Dataset.cpp b/cpp/open3d/data/Dataset.cpp index 34acfa90599..5b18b4426d8 100644 --- a/cpp/open3d/data/Dataset.cpp +++ b/cpp/open3d/data/Dataset.cpp @@ -61,22 +61,22 @@ Dataset::Dataset(const std::string& prefix, const std::string& data_root) SingleDownloadDataset::SingleDownloadDataset( const std::string& prefix, - const std::vector<std::string>& urls, + const std::vector<std::string>& url_mirrors, const std::string& md5, const bool no_extract, const std::string& data_root) : Dataset(prefix, data_root) { const std::string filename = - utility::filesystem::GetFileNameWithoutDirectory(urls[0]); + utility::filesystem::GetFileNameWithoutDirectory(url_mirrors[0]); - const bool is_extract_present = + const bool is_extract_folder_present = utility::filesystem::DirectoryExists(Dataset::GetExtractDir()); - if (!is_extract_present) { + if (!is_extract_folder_present) { // `download_dir` is relative path from `${data_root}`. const std::string download_dir = "download/" + GetPrefix(); - const std::string download_file_path = - utility::DownloadFromURL(urls, md5, download_dir, data_root_); + const std::string download_file_path = utility::DownloadFromURL( + url_mirrors, md5, download_dir, data_root_); // Extract / Copy data. if (!no_extract) { @@ -90,6 +90,52 @@ SingleDownloadDataset::SingleDownloadDataset( } } +MultiDownloadDataset::MultiDownloadDataset( + const std::string& prefix, + const std::vector<std::vector<std::string>>& url_mirrors_list, + const std::vector<std::string>& md5_list, + const bool no_extract, + const std::string& data_root) + : Dataset(prefix, data_root) { + std::vector<std::string> filenames; + for (auto& file_mirrors : url_mirrors_list) { + filenames.push_back(file_mirrors[0]); + } + const bool is_extract_folder_present = + utility::filesystem::DirectoryExists(Dataset::GetExtractDir()); + + if (!is_extract_folder_present) { + size_t number_of_files = url_mirrors_list.size(); + if (md5_list.size() != number_of_files) { + utility::LogError( + "md5_list and url_mirrors_list must be of same length."); + } + + // `download_dir` is relative path from `${data_root}`. + const std::string download_dir = "download/" + GetPrefix(); + std::vector<std::string> download_file_paths; + for (size_t i = 0; i < number_of_files; ++i) { + download_file_paths.push_back( + utility::DownloadFromURL(url_mirrors_list[i], md5_list[i], + download_dir, data_root_)); + } + + // Extract / Copy data. + if (!no_extract) { + for (auto& download_file_path : download_file_paths) { + utility::Extract(download_file_path, Dataset::GetExtractDir()); + } + } else { + utility::filesystem::MakeDirectoryHierarchy( + Dataset::GetExtractDir()); + for (auto& download_file_path : download_file_paths) { + utility::filesystem::Copy(download_file_path, + Dataset::GetExtractDir()); + } + } + } +} + DemoICPPointClouds::DemoICPPointClouds(const std::string& data_root) : SingleDownloadDataset( "DemoICPPointClouds", @@ -690,5 +736,74 @@ std::string OfficePointClouds::GetPaths(size_t index) const { return paths_[index]; } +LoungeRGBDImages::LoungeRGBDImages(const std::string& data_root) + : SingleDownloadDataset( + "LoungeRGBDImages", + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/LoungeRGBDImages.zip"}, + "cdd307caef898519a8829ce1b6ab9f75", + /*no_extract =*/false, + data_root) { + color_paths_.reserve(3000); + depth_paths_.reserve(3000); + const std::string extract_dir = Dataset::GetExtractDir(); + const size_t n_zero = 6; + for (int i = 1; i < 3000; ++i) { + std::string idx = std::to_string(i); + idx = std::string(n_zero - std::min(n_zero, idx.length()), '0') + idx; + color_paths_.push_back(extract_dir + "/color/" + idx + ".png"); + depth_paths_.push_back(extract_dir + "/depth/" + idx + ".png"); + } + + trajectory_log_path_ = extract_dir + "/lounge_trajectory.log"; + reconstruction_path_ = extract_dir + "/lounge.ply"; +} + +BedroomRGBDImages::BedroomRGBDImages(const std::string& data_root) + : MultiDownloadDataset( + "BedroomRGBDImages", + {{"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/bedroom01.zip"}, + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/bedroom02.zip"}, + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/bedroom03.zip"}, + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/bedroom04.zip"}, + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/bedroom05.zip"}}, + {"2d1018ceeb72680f5d16b2f419da9bb1", + "5e6ffbccc0907dc5acc374aa76a79081", + "ebf13b89ec364b1788dd492c27b9b800", + "94c0e6c862a54588582b06520946fb15", + "54b927edb6fd61838025bc66ed767408"}, + /*no_extract =*/false, + data_root) { + color_paths_.reserve(21931); + depth_paths_.reserve(21931); + const std::string extract_dir = Dataset::GetExtractDir(); + const size_t n_zero = 6; + for (int i = 1; i < 21931; ++i) { + std::string idx = std::to_string(i); + idx = std::string(n_zero - std::min(n_zero, idx.length()), '0') + idx; + color_paths_.push_back(extract_dir + "/image/" + idx + ".jpg"); + depth_paths_.push_back(extract_dir + "/depth/" + idx + ".png"); + } + + trajectory_log_path_ = extract_dir + "/bedroom.log"; + reconstruction_path_ = extract_dir + "/bedroom.ply"; +} + +JackJackL515Bag::JackJackL515Bag(const std::string& data_root) + : SingleDownloadDataset( + "JackJackL515Bag", + {"https://github.com/isl-org/open3d_downloads/releases/download/" + "20220301-data/JackJackL515Bag.bag"}, + "9f670dc92569b986b739c4179a659176", + /*no_extract =*/true, + data_root) { + path_ = Dataset::GetExtractDir() + "/JackJackL515Bag.bag"; +} + } // namespace data } // namespace open3d diff --git a/cpp/open3d/data/Dataset.h b/cpp/open3d/data/Dataset.h index 7031c2cc442..f66e417aa19 100644 --- a/cpp/open3d/data/Dataset.h +++ b/cpp/open3d/data/Dataset.h @@ -114,7 +114,7 @@ class Dataset { class SingleDownloadDataset : public Dataset { public: SingleDownloadDataset(const std::string& prefix, - const std::vector<std::string>& urls, + const std::vector<std::string>& url_mirrors, const std::string& md5, const bool no_extract = false, const std::string& data_root = ""); @@ -122,6 +122,21 @@ class SingleDownloadDataset : public Dataset { virtual ~SingleDownloadDataset() {} }; +/// \class MultiDownloadDataset +/// \brief This class allows user to create simple dataset which includes +/// multiple file downloading and extracting / copying. +class MultiDownloadDataset : public Dataset { +public: + MultiDownloadDataset( + const std::string& prefix, + const std::vector<std::vector<std::string>>& url_mirrors_list, + const std::vector<std::string>& md5_list, + const bool no_extract = false, + const std::string& data_root = ""); + + virtual ~MultiDownloadDataset() {} +}; + /// \class DemoICPPointClouds /// \brief Data class for `DemoICPPointClouds` contains 3 point clouds of binary /// PCD format. This data is used in Open3D for ICP demo. @@ -860,5 +875,82 @@ class OfficePointClouds : public SingleDownloadDataset { std::vector<std::string> paths_; }; +/// \class LoungeRGBDImages +/// \brief Data class for `LoungeRGBDImages` contains a sample set of 3000 color +/// and depth images from Stanford Lounge RGBD dataset. Additionally it also +/// contains camera trajectory log, and mesh reconstruction. +class LoungeRGBDImages : public SingleDownloadDataset { +public: + LoungeRGBDImages(const std::string& data_root = ""); + + /// \brief Returns List of paths to color image samples of size 3000. + std::vector<std::string> GetColorPaths() const { return color_paths_; }; + /// \brief Returns List of paths to depth image samples of size 3000. + std::vector<std::string> GetDepthPaths() const { return depth_paths_; }; + + /// \brief Returns path to camera trajectory log file + /// `lounge_trajectory.log`. + std::string GetTrajectoryLogPath() const { return trajectory_log_path_; }; + /// \brief Returns path to mesh reconstruction `lounge.ply`. + std::string GetReconstructionPath() const { return reconstruction_path_; }; + +private: + /// List of paths to color image samples of size 3000. + std::vector<std::string> color_paths_; + /// List of paths to depth image samples of size 3000. + std::vector<std::string> depth_paths_; + + /// Path to camera trajectory log file `lounge_trajectory.log`. + std::string trajectory_log_path_; + /// Path to mesh reconstruction. + std::string reconstruction_path_; +}; + +/// \class BedroomRGBDImages +/// \brief Data class for `BedroomRGBDImages` contains a sample set of 21931 +/// color and depth images from Redwood RGBD dataset. Additionally it also +/// contains camera trajectory log, and mesh reconstruction. +class BedroomRGBDImages : public MultiDownloadDataset { +public: + BedroomRGBDImages(const std::string& data_root = ""); + + /// \brief Returns List of paths to color image samples of size 21931. + std::vector<std::string> GetColorPaths() const { return color_paths_; }; + /// \brief Returns List of paths to depth image samples of size 21931. + std::vector<std::string> GetDepthPaths() const { return depth_paths_; }; + + /// \brief Returns path to camera trajectory log file + /// `lounge_trajectory.log`. + std::string GetTrajectoryLogPath() const { return trajectory_log_path_; }; + /// \brief Returns path to mesh reconstruction `bedroom.ply`. + std::string GetReconstructionPath() const { return reconstruction_path_; }; + +private: + /// List of paths to color image samples of size 3000. + std::vector<std::string> color_paths_; + /// List of paths to depth image samples of size 3000. + std::vector<std::string> depth_paths_; + + /// Path to camera trajectory log file `bedroom.log`. + std::string trajectory_log_path_; + /// Path to mesh reconstruction. + std::string reconstruction_path_; +}; + +/// \class JackJackL515Bag +/// \brief Data class for `JackJackL515Bag` contains the RealSense L515 +/// `JackJackL515Bag.bag` file. +class JackJackL515Bag : public SingleDownloadDataset { +public: + JackJackL515Bag(const std::string& data_root = ""); + + /// \brief Returns path to the `JackJackL515Bag.bag` file. + std::string GetPath() const { return path_; }; + +private: + /// Path to `JackJackL515Bag.bag` file. + std::string path_; +}; + } // namespace data } // namespace open3d diff --git a/cpp/open3d/t/io/sensor/RGBDVideoReader.cpp b/cpp/open3d/t/io/sensor/RGBDVideoReader.cpp index fc84ce34225..016a354648b 100644 --- a/cpp/open3d/t/io/sensor/RGBDVideoReader.cpp +++ b/cpp/open3d/t/io/sensor/RGBDVideoReader.cpp @@ -102,12 +102,14 @@ std::unique_ptr<RGBDVideoReader> RGBDVideoReader::Create( auto reader = std::make_unique<RSBagReader>(); reader->Open(filename); return reader; - } else -#endif - { - utility::LogError("Unsupported file format for {}", filename); + } else { + utility::LogError("Unsupported file format for {}.", filename); } +#endif + utility::LogError( + "Build with -DBUILD_LIBREALSENSE=ON to use RealSense bag file."); } + } // namespace io } // namespace t } // namespace open3d diff --git a/cpp/pybind/data/data.cpp b/cpp/pybind/data/data.cpp index b0fa95586d2..5c8f274650d 100644 --- a/cpp/pybind/data/data.cpp +++ b/cpp/pybind/data/data.cpp @@ -39,10 +39,16 @@ class PyDataset : public DatasetBase { using DatasetBase::DatasetBase; }; -template <class SimpleDatasetBase = SingleDownloadDataset> -class PySimpleDataset : public PyDataset<SimpleDatasetBase> { +template <class SingleDownloadDatasetBase = SingleDownloadDataset> +class PySingleDownloadDataset : public PyDataset<SingleDownloadDatasetBase> { public: - using PyDataset<SimpleDatasetBase>::PyDataset; + using PyDataset<SingleDownloadDatasetBase>::PyDataset; +}; + +template <class MultiDownloadDatasetBase = MultiDownloadDataset> +class PyMultiDownloadDataset : public PyDataset<MultiDownloadDatasetBase> { +public: + using PyDataset<MultiDownloadDatasetBase>::PyDataset; }; void pybind_data_classes(py::module& m) { @@ -71,22 +77,39 @@ void pybind_data_classes(py::module& m) { docstring::ClassMethodDocInject(m, "Dataset", "extract_dir"); // open3d.data.SingleDownloadDataset - py::class_<SingleDownloadDataset, PySimpleDataset<SingleDownloadDataset>, + py::class_<SingleDownloadDataset, + PySingleDownloadDataset<SingleDownloadDataset>, std::shared_ptr<SingleDownloadDataset>, Dataset> single_download_dataset(m, "SingleDownloadDataset", "Single file download dataset class."); single_download_dataset.def( py::init<const std::string&, const std::vector<std::string>&, const std::string&, const bool, const std::string&>(), - "prefix"_a, "urls"_a, "md5"_a, "no_extract"_a = false, + "prefix"_a, "url_mirrors"_a, "md5"_a, "no_extract"_a = false, "data_root"_a = "", "This class allows user to create simple dataset which includes " "single file downloading and extracting / copying."); + + // open3d.data.MultiDownloadDataset + py::class_<MultiDownloadDataset, + PyMultiDownloadDataset<MultiDownloadDataset>, + std::shared_ptr<MultiDownloadDataset>, Dataset> + multi_download_dataset(m, "MultiDownloadDataset", + "Multiple files download dataset class."); + multi_download_dataset.def( + py::init<const std::string&, + const std::vector<std::vector<std::string>>&, + const std::vector<std::string>&, const bool, + const std::string&>(), + "prefix"_a, "url_mirrors_list"_a, "md5_list"_a, + "no_extract"_a = false, "data_root"_a = "", + "This class allows user to create simple dataset which includes " + "multiple files downloading and extracting / copying."); } void pybind_demo_icp_pointclouds(py::module& m) { // open3d.data.DemoICPPointClouds - py::class_<DemoICPPointClouds, PySimpleDataset<DemoICPPointClouds>, + py::class_<DemoICPPointClouds, PySingleDownloadDataset<DemoICPPointClouds>, std::shared_ptr<DemoICPPointClouds>, SingleDownloadDataset> demo_icp_pointclouds(m, "DemoICPPointClouds", "Data class for `DemoICPPointClouds` contains " @@ -113,7 +136,7 @@ void pybind_demo_icp_pointclouds(py::module& m) { void pybind_demo_colored_icp_pointclouds(py::module& m) { // open3d.data.DemoColoredICPPointClouds py::class_<DemoColoredICPPointClouds, - PySimpleDataset<DemoColoredICPPointClouds>, + PySingleDownloadDataset<DemoColoredICPPointClouds>, std::shared_ptr<DemoColoredICPPointClouds>, SingleDownloadDataset> demo_colored_icp_pointclouds( @@ -136,7 +159,7 @@ void pybind_demo_colored_icp_pointclouds(py::module& m) { void pybind_demo_crop_pointcloud(py::module& m) { // open3d.data.DemoCropPointCloud - py::class_<DemoCropPointCloud, PySimpleDataset<DemoCropPointCloud>, + py::class_<DemoCropPointCloud, PySingleDownloadDataset<DemoCropPointCloud>, std::shared_ptr<DemoCropPointCloud>, SingleDownloadDataset> demo_crop_pointcloud( m, "DemoCropPointCloud", @@ -161,7 +184,7 @@ void pybind_demo_crop_pointcloud(py::module& m) { void pybind_demo_feature_matching_point_clouds(py::module& m) { // open3d.data.DemoFeatureMatchingPointClouds py::class_<DemoFeatureMatchingPointClouds, - PySimpleDataset<DemoFeatureMatchingPointClouds>, + PySingleDownloadDataset<DemoFeatureMatchingPointClouds>, std::shared_ptr<DemoFeatureMatchingPointClouds>, SingleDownloadDataset> demo_feature_matching( @@ -200,7 +223,7 @@ void pybind_demo_feature_matching_point_clouds(py::module& m) { void pybind_demo_pose_graph_optimization(py::module& m) { // open3d.data.DemoPoseGraphOptimization py::class_<DemoPoseGraphOptimization, - PySimpleDataset<DemoPoseGraphOptimization>, + PySingleDownloadDataset<DemoPoseGraphOptimization>, std::shared_ptr<DemoPoseGraphOptimization>, SingleDownloadDataset> demo_pose_graph_optimization( @@ -228,7 +251,7 @@ void pybind_demo_pose_graph_optimization(py::module& m) { void pybind_demo_custom_visualization(py::module& m) { // open3d.data.DemoCustomVisualization py::class_<DemoCustomVisualization, - PySimpleDataset<DemoCustomVisualization>, + PySingleDownloadDataset<DemoCustomVisualization>, std::shared_ptr<DemoCustomVisualization>, SingleDownloadDataset> demo_custom_visualization( m, "DemoCustomVisualization", @@ -260,7 +283,7 @@ void pybind_demo_custom_visualization(py::module& m) { void pybind_pcd_point_cloud(py::module& m) { // open3d.data.PCDPointCloud - py::class_<PCDPointCloud, PySimpleDataset<PCDPointCloud>, + py::class_<PCDPointCloud, PySingleDownloadDataset<PCDPointCloud>, std::shared_ptr<PCDPointCloud>, SingleDownloadDataset> pcd_pointcloud(m, "PCDPointCloud", "Data class for `PCDPointCloud` contains the " @@ -274,7 +297,7 @@ void pybind_pcd_point_cloud(py::module& m) { void pybind_ply_point_cloud(py::module& m) { // open3d.data.PLYPointCloud - py::class_<PLYPointCloud, PySimpleDataset<PLYPointCloud>, + py::class_<PLYPointCloud, PySingleDownloadDataset<PLYPointCloud>, std::shared_ptr<PLYPointCloud>, SingleDownloadDataset> ply_pointcloud(m, "PLYPointCloud", "Data class for `PLYPointCloud` contains the " @@ -288,7 +311,7 @@ void pybind_ply_point_cloud(py::module& m) { void pybind_pts_point_cloud(py::module& m) { // open3d.data.PTSPointCloud - py::class_<PTSPointCloud, PySimpleDataset<PTSPointCloud>, + py::class_<PTSPointCloud, PySingleDownloadDataset<PTSPointCloud>, std::shared_ptr<PTSPointCloud>, SingleDownloadDataset> pts_point_cloud(m, "PTSPointCloud", "Data class for `PTSPointCloud` contains a sample " @@ -301,7 +324,7 @@ void pybind_pts_point_cloud(py::module& m) { void pybind_sample_nyu_rgbd_image(py::module& m) { // open3d.data.SampleNYURGBDImage - py::class_<SampleNYURGBDImage, PySimpleDataset<SampleNYURGBDImage>, + py::class_<SampleNYURGBDImage, PySingleDownloadDataset<SampleNYURGBDImage>, std::shared_ptr<SampleNYURGBDImage>, SingleDownloadDataset> rgbd_image_nyu(m, "SampleNYURGBDImage", "Data class for `SampleNYURGBDImage` contains a " @@ -320,7 +343,7 @@ void pybind_sample_nyu_rgbd_image(py::module& m) { void pybind_sample_sun_rgbd_image(py::module& m) { // open3d.data.SampleSUNRGBDImage - py::class_<SampleSUNRGBDImage, PySimpleDataset<SampleSUNRGBDImage>, + py::class_<SampleSUNRGBDImage, PySingleDownloadDataset<SampleSUNRGBDImage>, std::shared_ptr<SampleSUNRGBDImage>, SingleDownloadDataset> rgbd_image_sun(m, "SampleSUNRGBDImage", "Data class for `SampleSUNRGBDImage` contains a " @@ -339,7 +362,7 @@ void pybind_sample_sun_rgbd_image(py::module& m) { void pybind_sample_tum_rgbd_image(py::module& m) { // open3d.data.SampleTUMRGBDImage - py::class_<SampleTUMRGBDImage, PySimpleDataset<SampleTUMRGBDImage>, + py::class_<SampleTUMRGBDImage, PySingleDownloadDataset<SampleTUMRGBDImage>, std::shared_ptr<SampleTUMRGBDImage>, SingleDownloadDataset> rgbd_image_tum(m, "SampleTUMRGBDImage", "Data class for `SampleTUMRGBDImage` contains a " @@ -359,7 +382,7 @@ void pybind_sample_tum_rgbd_image(py::module& m) { void pybind_sample_redwood_rgbd_images(py::module& m) { // open3d.data.SampleRedwoodRGBDImages py::class_<SampleRedwoodRGBDImages, - PySimpleDataset<SampleRedwoodRGBDImages>, + PySingleDownloadDataset<SampleRedwoodRGBDImages>, std::shared_ptr<SampleRedwoodRGBDImages>, SingleDownloadDataset> rgbd_dataset_redwood( m, "SampleRedwoodRGBDImages", @@ -418,7 +441,7 @@ void pybind_sample_redwood_rgbd_images(py::module& m) { void pybind_sample_fountain_rgbd_images(py::module& m) { // open3d.data.SampleFountainRGBDImages py::class_<SampleFountainRGBDImages, - PySimpleDataset<SampleFountainRGBDImages>, + PySingleDownloadDataset<SampleFountainRGBDImages>, std::shared_ptr<SampleFountainRGBDImages>, SingleDownloadDataset> fountain_rgbd_dataset( m, "SampleFountainRGBDImages", @@ -459,7 +482,7 @@ void pybind_sample_fountain_rgbd_images(py::module& m) { void pybind_sample_l515_bag(py::module& m) { // open3d.data.SampleL515Bag - py::class_<SampleL515Bag, PySimpleDataset<SampleL515Bag>, + py::class_<SampleL515Bag, PySingleDownloadDataset<SampleL515Bag>, std::shared_ptr<SampleL515Bag>, SingleDownloadDataset> sample_l515_bag(m, "SampleL515Bag", "Data class for `SampleL515Bag` contains the " @@ -472,7 +495,7 @@ void pybind_sample_l515_bag(py::module& m) { void pybind_eagle(py::module& m) { // open3d.data.EaglePointCloud - py::class_<EaglePointCloud, PySimpleDataset<EaglePointCloud>, + py::class_<EaglePointCloud, PySingleDownloadDataset<EaglePointCloud>, std::shared_ptr<EaglePointCloud>, SingleDownloadDataset> eagle(m, "EaglePointCloud", "Data class for `EaglePointCloud` contains the " @@ -485,7 +508,7 @@ void pybind_eagle(py::module& m) { void pybind_armadillo(py::module& m) { // open3d.data.ArmadilloMesh - py::class_<ArmadilloMesh, PySimpleDataset<ArmadilloMesh>, + py::class_<ArmadilloMesh, PySingleDownloadDataset<ArmadilloMesh>, std::shared_ptr<ArmadilloMesh>, SingleDownloadDataset> armadillo(m, "ArmadilloMesh", "Data class for `ArmadilloMesh` contains the " @@ -499,7 +522,7 @@ void pybind_armadillo(py::module& m) { void pybind_bunny(py::module& m) { // open3d.data.BunnyMesh - py::class_<BunnyMesh, PySimpleDataset<BunnyMesh>, + py::class_<BunnyMesh, PySingleDownloadDataset<BunnyMesh>, std::shared_ptr<BunnyMesh>, SingleDownloadDataset> bunny(m, "BunnyMesh", "Data class for `BunnyMesh` contains the `BunnyMesh.ply` " @@ -513,8 +536,8 @@ void pybind_bunny(py::module& m) { void pybind_knot(py::module& m) { // open3d.data.KnotMesh - py::class_<KnotMesh, PySimpleDataset<KnotMesh>, std::shared_ptr<KnotMesh>, - SingleDownloadDataset> + py::class_<KnotMesh, PySingleDownloadDataset<KnotMesh>, + std::shared_ptr<KnotMesh>, SingleDownloadDataset> knot(m, "KnotMesh", "Data class for `KnotMesh` contains the `KnotMesh.ply`."); knot.def(py::init<const std::string&>(), "data_root"_a = "") @@ -525,7 +548,7 @@ void pybind_knot(py::module& m) { void pybind_monkey(py::module& m) { // open3d.data.MonkeyModel - py::class_<MonkeyModel, PySimpleDataset<MonkeyModel>, + py::class_<MonkeyModel, PySingleDownloadDataset<MonkeyModel>, std::shared_ptr<MonkeyModel>, SingleDownloadDataset> monkey(m, "MonkeyModel", "Data class for `MonkeyModel` contains a monkey model file, " @@ -547,7 +570,7 @@ void pybind_monkey(py::module& m) { void pybind_sword(py::module& m) { // open3d.data.SwordModel - py::class_<SwordModel, PySimpleDataset<SwordModel>, + py::class_<SwordModel, PySingleDownloadDataset<SwordModel>, std::shared_ptr<SwordModel>, SingleDownloadDataset> sword(m, "SwordModel", "Data class for `SwordModel` contains a monkey model file, " @@ -569,7 +592,7 @@ void pybind_sword(py::module& m) { void pybind_crate(py::module& m) { // open3d.data.CrateModel - py::class_<CrateModel, PySimpleDataset<CrateModel>, + py::class_<CrateModel, PySingleDownloadDataset<CrateModel>, std::shared_ptr<CrateModel>, SingleDownloadDataset> crate(m, "CrateModel", "Data class for `CrateModel` contains a crate model file, " @@ -591,7 +614,7 @@ void pybind_crate(py::module& m) { void pybind_helmet(py::module& m) { // open3d.data.FlightHelmetModel - py::class_<FlightHelmetModel, PySimpleDataset<FlightHelmetModel>, + py::class_<FlightHelmetModel, PySingleDownloadDataset<FlightHelmetModel>, std::shared_ptr<FlightHelmetModel>, SingleDownloadDataset> helmet(m, "FlightHelmetModel", "Data class for `FlightHelmetModel` contains a flight " @@ -615,7 +638,7 @@ void pybind_helmet(py::module& m) { void pybind_metal_texture(py::module& m) { // open3d.data.MetalTexture - py::class_<MetalTexture, PySimpleDataset<MetalTexture>, + py::class_<MetalTexture, PySingleDownloadDataset<MetalTexture>, std::shared_ptr<MetalTexture>, SingleDownloadDataset> metal_texture(m, "MetalTexture", "Data class for `MetalTexture` contains albedo, " @@ -646,7 +669,8 @@ void pybind_metal_texture(py::module& m) { void pybind_painted_plaster_texture(py::module& m) { // open3d.data.PaintedPlasterTexture - py::class_<PaintedPlasterTexture, PySimpleDataset<PaintedPlasterTexture>, + py::class_<PaintedPlasterTexture, + PySingleDownloadDataset<PaintedPlasterTexture>, std::shared_ptr<PaintedPlasterTexture>, SingleDownloadDataset> painted_plaster_texture( m, "PaintedPlasterTexture", @@ -679,7 +703,7 @@ void pybind_painted_plaster_texture(py::module& m) { void pybind_tiles_texture(py::module& m) { // open3d.data.TilesTexture - py::class_<TilesTexture, PySimpleDataset<TilesTexture>, + py::class_<TilesTexture, PySingleDownloadDataset<TilesTexture>, std::shared_ptr<TilesTexture>, SingleDownloadDataset> tiles_texture( m, "TilesTexture", @@ -706,7 +730,7 @@ void pybind_tiles_texture(py::module& m) { void pybind_terrazzo_texture(py::module& m) { // open3d.data.TerrazzoTexture - py::class_<TerrazzoTexture, PySimpleDataset<TerrazzoTexture>, + py::class_<TerrazzoTexture, PySingleDownloadDataset<TerrazzoTexture>, std::shared_ptr<TerrazzoTexture>, SingleDownloadDataset> terrazzo_texture( m, "TerrazzoTexture", @@ -735,7 +759,7 @@ void pybind_terrazzo_texture(py::module& m) { void pybind_wood_texture(py::module& m) { // open3d.data.WoodTexture - py::class_<WoodTexture, PySimpleDataset<WoodTexture>, + py::class_<WoodTexture, PySingleDownloadDataset<WoodTexture>, std::shared_ptr<WoodTexture>, SingleDownloadDataset> wood_texture( m, "WoodTexture", @@ -761,7 +785,7 @@ void pybind_wood_texture(py::module& m) { void pybind_wood_floor_texture(py::module& m) { // open3d.data.WoodFloorTexture - py::class_<WoodFloorTexture, PySimpleDataset<WoodFloorTexture>, + py::class_<WoodFloorTexture, PySingleDownloadDataset<WoodFloorTexture>, std::shared_ptr<WoodFloorTexture>, SingleDownloadDataset> wood_floor_texture(m, "WoodFloorTexture", " Data class for `WoodFloorTexture` contains " @@ -790,7 +814,7 @@ void pybind_wood_floor_texture(py::module& m) { void pybind_juneau(py::module& m) { // open3d.data.JuneauImage - py::class_<JuneauImage, PySimpleDataset<JuneauImage>, + py::class_<JuneauImage, PySingleDownloadDataset<JuneauImage>, std::shared_ptr<JuneauImage>, SingleDownloadDataset> juneau(m, "JuneauImage", "Data class for `JuneauImage` contains the " @@ -804,7 +828,8 @@ void pybind_juneau(py::module& m) { void pybind_living_room_point_clouds(py::module& m) { // open3d.data.LivingRoomPointClouds - py::class_<LivingRoomPointClouds, PySimpleDataset<LivingRoomPointClouds>, + py::class_<LivingRoomPointClouds, + PySingleDownloadDataset<LivingRoomPointClouds>, std::shared_ptr<LivingRoomPointClouds>, SingleDownloadDataset> living_room_point_clouds( m, "LivingRoomPointClouds", @@ -825,7 +850,7 @@ void pybind_living_room_point_clouds(py::module& m) { void pybind_office_point_clouds(py::module& m) { // open3d.data.OfficePointClouds - py::class_<OfficePointClouds, PySimpleDataset<OfficePointClouds>, + py::class_<OfficePointClouds, PySingleDownloadDataset<OfficePointClouds>, std::shared_ptr<OfficePointClouds>, SingleDownloadDataset> office_point_clouds( m, "OfficePointClouds", @@ -843,6 +868,92 @@ void pybind_office_point_clouds(py::module& m) { docstring::ClassMethodDocInject(m, "OfficePointClouds", "paths"); } +void pybind_lounge_rgbd_images(py::module& m) { + // open3d.data.LoungeRGBDImages + py::class_<LoungeRGBDImages, PySingleDownloadDataset<LoungeRGBDImages>, + std::shared_ptr<LoungeRGBDImages>, SingleDownloadDataset> + lounge_rgbd_images( + m, "LoungeRGBDImages", + "Data class for `LoungeRGBDImages` contains a sample set " + "of 3000 color and depth images from Stanford Lounge RGBD " + "dataset. Additionally it also contains camera trajectory " + "log, and mesh reconstruction."); + lounge_rgbd_images.def(py::init<const std::string&>(), "data_root"_a = "") + .def_property_readonly( + "color_paths", &LoungeRGBDImages::GetColorPaths, + "List of paths to color image samples of size 3000. Use " + "`color_paths[0]`, `color_paths[1]` ... " + "`color_paths[2999]` to access the paths.") + .def_property_readonly( + "depth_paths", &LoungeRGBDImages::GetDepthPaths, + "List of paths to depth image samples of size 3000. Use " + "`depth_paths[0]`, `depth_paths[1]` ... " + "`depth_paths[2999]` to access the paths.") + .def_property_readonly( + "trajectory_log_path", + &LoungeRGBDImages::GetTrajectoryLogPath, + "Path to camera trajectory log file `trajectory.log`.") + .def_property_readonly("reconstruction_path", + &LoungeRGBDImages::GetReconstructionPath, + "Path to mesh reconstruction."); + docstring::ClassMethodDocInject(m, "LoungeRGBDImages", "color_paths"); + docstring::ClassMethodDocInject(m, "LoungeRGBDImages", "depth_paths"); + docstring::ClassMethodDocInject(m, "LoungeRGBDImages", + "trajectory_log_path"); + docstring::ClassMethodDocInject(m, "LoungeRGBDImages", + "reconstruction_path"); +} + +void pybind_bedroom_rgbd_images(py::module& m) { + // open3d.data.BedroomRGBDImages + py::class_<BedroomRGBDImages, PyMultiDownloadDataset<BedroomRGBDImages>, + std::shared_ptr<BedroomRGBDImages>, MultiDownloadDataset> + lounge_rgbd_images( + m, "BedroomRGBDImages", + "Data class for `BedroomRGBDImages` contains a sample set " + "of 21931 color and depth images from Redwood Bedroom RGBD " + "dataset. Additionally it also contains camera trajectory " + "log, and mesh reconstruction."); + lounge_rgbd_images.def(py::init<const std::string&>(), "data_root"_a = "") + .def_property_readonly("color_paths", + &BedroomRGBDImages::GetColorPaths, + "List of paths to color image samples of " + "size 21931. Use `color_paths[0]`, " + "`color_paths[1]` ... `color_paths[21930]` " + "to access the paths.") + .def_property_readonly( + "depth_paths", &BedroomRGBDImages::GetDepthPaths, + "List of paths to depth image samples of size 21931. Use " + "`depth_paths[0]`, `depth_paths[1]` ... " + "`depth_paths[21930]` to access the paths.") + .def_property_readonly( + "trajectory_log_path", + &BedroomRGBDImages::GetTrajectoryLogPath, + "Path to camera trajectory log file `trajectory.log`.") + .def_property_readonly("reconstruction_path", + &BedroomRGBDImages::GetReconstructionPath, + "Path to mesh reconstruction."); + docstring::ClassMethodDocInject(m, "BedroomRGBDImages", "color_paths"); + docstring::ClassMethodDocInject(m, "BedroomRGBDImages", "depth_paths"); + docstring::ClassMethodDocInject(m, "BedroomRGBDImages", + "trajectory_log_path"); + docstring::ClassMethodDocInject(m, "BedroomRGBDImages", + "reconstruction_path"); +} + +void pybind_jackjack_l515_bag(py::module& m) { + // open3d.data.JackJackL515Bag + py::class_<JackJackL515Bag, PySingleDownloadDataset<JackJackL515Bag>, + std::shared_ptr<JackJackL515Bag>, SingleDownloadDataset> + jackjack_l515_bag(m, "JackJackL515Bag", + "Data class for `SampleL515Bag` contains the " + "`JackJackL515Bag.bag` file."); + jackjack_l515_bag.def(py::init<const std::string&>(), "data_root"_a = "") + .def_property_readonly("path", &JackJackL515Bag::GetPath, + "Path to the `JackJackL515Bag.bag` file."); + docstring::ClassMethodDocInject(m, "JackJackL515Bag", "path"); +} + void pybind_data(py::module& m) { py::module m_submodule = m.def_submodule("data", "Data handling module."); pybind_data_classes(m_submodule); @@ -887,6 +998,9 @@ void pybind_data(py::module& m) { // Point Cloud fragments data. pybind_living_room_point_clouds(m_submodule); pybind_office_point_clouds(m_submodule); + pybind_lounge_rgbd_images(m_submodule); + pybind_bedroom_rgbd_images(m_submodule); + pybind_jackjack_l515_bag(m_submodule); } } // namespace data diff --git a/cpp/tests/data/Dataset.cpp b/cpp/tests/data/Dataset.cpp index 483b21be2dd..0c7ee44048e 100644 --- a/cpp/tests/data/Dataset.cpp +++ b/cpp/tests/data/Dataset.cpp @@ -997,12 +997,6 @@ TEST(Dataset, DISABLED_RedwoodOfficePointClouds) { EXPECT_TRUE(utility::filesystem::FileExists(dataset.GetPaths(i))); } - EXPECT_EQ(dataset.GetPaths(), paths); - for (size_t i = 0; i < paths.size(); ++i) { - EXPECT_EQ(dataset.GetPaths(i), paths[i]); - EXPECT_TRUE(utility::filesystem::FileExists(dataset.GetPaths(i))); - } - EXPECT_EQ(dataset.GetPrefix(), prefix); EXPECT_EQ(dataset.GetDataRoot(), data_root); EXPECT_EQ(dataset.GetDownloadDir(), download_dir); diff --git a/docs/tutorial/data/index.rst b/docs/tutorial/data/index.rst index f4aba5f20ad..aa9dd025d53 100644 --- a/docs/tutorial/data/index.rst +++ b/docs/tutorial/data/index.rst @@ -586,6 +586,84 @@ RGBD dataset. auto rgbd_image = geometry::RGBDImage::CreateFromTUMFormat( *color_raw, *depth_raw, /*convert_rgb_to_intensity =*/ false); +LoungeRGBDImages +------------------ + +Lounge RGBD dataset from Stanford containing ``color`` and ``depth`` +sequence of 3000 images, along with ``camera trajectory`` and ``reconstruction``. + +.. code-block:: python + + dataset = o3d.data.LoungeRGBDImages() + + rgbd_images = [] + for i in range(len(dataset.depth_paths)): + color_raw = o3d.io.read_image(dataset.color_paths[i]) + depth_raw = o3d.io.read_image(dataset.depth_paths[i]) + rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( + color_raw, depth_raw) + rgbd_images.append(rgbd_image) + + mesh = o3d.io.read_triangle_mesh(dataset.reconstruction_path) + +.. code-block:: cpp + + data::LoungeRGBDImages dataset; + + std::vector<std::shared_ptr<geometry::RGBDImage>> rgbd_images; + for(size_t i = 0; i < dataset.GetDepthPaths().size(); ++i) { + auto color_raw = io::CreateImageFromFile(dataset.GetColorPaths()[i]); + auto depth_raw = io::CreateImageFromFile(dataset.GetDepthPaths()[i]); + + auto rgbd_image = geometry::RGBDImage::CreateFromColorAndDepth( + *color_raw, *depth_raw, + /*depth_scale =*/1000.0, + /*depth_trunc =*/3.0, + /*convert_rgb_to_intensity =*/false); + rgbd_images.push_back(rgbd_image); + } + + auto mesh = io::CreateTriangleMeshFromFile(dataset.GetReconstructionPath()); + +BedroomRGBDImages +------------------ + +Bedroom RGBD dataset from Redwood containing ``color`` and ``depth`` +sequence of 21931 images, along with ``camera trajectory`` and ``reconstruction``. + +.. code-block:: python + + dataset = o3d.data.BedroomRGBDImages() + + rgbd_images = [] + for i in range(len(dataset.depth_paths)): + color_raw = o3d.io.read_image(dataset.color_paths[i]) + depth_raw = o3d.io.read_image(dataset.depth_paths[i]) + rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( + color_raw, depth_raw) + rgbd_images.append(rgbd_image) + + mesh = o3d.io.read_triangle_mesh(dataset.reconstruction_path) + +.. code-block:: cpp + + data::BedroomRGBDImages dataset; + + std::vector<std::shared_ptr<geometry::RGBDImage>> rgbd_images; + for(size_t i = 0; i < dataset.GetDepthPaths().size(); ++i) { + auto color_raw = io::CreateImageFromFile(dataset.GetColorPaths()[i]); + auto depth_raw = io::CreateImageFromFile(dataset.GetDepthPaths()[i]); + + auto rgbd_image = geometry::RGBDImage::CreateFromColorAndDepth( + *color_raw, *depth_raw, + /*depth_scale =*/1000.0, + /*depth_trunc =*/3.0, + /*convert_rgb_to_intensity =*/false); + rgbd_images.push_back(rgbd_image); + } + + auto mesh = io::CreateTriangleMeshFromFile(dataset.GetReconstructionPath()); + Demo ~~~~ diff --git a/docs/tutorial/reconstruction_system/integrate_scene.rst b/docs/tutorial/reconstruction_system/integrate_scene.rst index 328d7f47055..4a56b188ab3 100644 --- a/docs/tutorial/reconstruction_system/integrate_scene.rst +++ b/docs/tutorial/reconstruction_system/integrate_scene.rst @@ -22,7 +22,7 @@ Integrate RGBD frames .. literalinclude:: ../../../examples/python/reconstruction_system/integrate_scene.py :language: python :lineno-start: 38 - :lines: 27,39-75 + :lines: 27,40-72 :linenos: This function first reads the alignment results from both diff --git a/docs/tutorial/reconstruction_system/make_fragments.rst b/docs/tutorial/reconstruction_system/make_fragments.rst index 6df2578abda..2485bfad2b3 100644 --- a/docs/tutorial/reconstruction_system/make_fragments.rst +++ b/docs/tutorial/reconstruction_system/make_fragments.rst @@ -25,8 +25,8 @@ Register RGBD image pairs .. literalinclude:: ../../../examples/python/reconstruction_system/make_fragments.py :language: python - :lineno-start: 58 - :lines: 27,59-88 + :lineno-start: 46 + :lines: 27,47-76 :linenos: The function reads a pair of RGBD images and registers the ``source_rgbd_image`` @@ -45,8 +45,8 @@ Multiway registration .. literalinclude:: ../../../examples/python/reconstruction_system/make_fragments.py :language: python - :lineno-start: 88 - :lines: 27,89-136 + :lineno-start: 76 + :lines: 27,77-123 :linenos: This script uses the technique demonstrated in @@ -62,7 +62,7 @@ function ``optimize_posegraph_for_fragment``. .. literalinclude:: ../../../examples/python/reconstruction_system/optimize_posegraph.py :language: python :lineno-start: 51 - :lines: 27,52-64 + :lines: 27,52-63 :linenos: This function calls ``global_optimization`` to estimate poses of the RGBD images. @@ -74,8 +74,8 @@ Make a fragment .. literalinclude:: ../../../examples/python/reconstruction_system/make_fragments.py :language: python - :lineno-start: 136 - :lines: 27,137-158 + :lineno-start: 124 + :lines: 27,125-146 :linenos: Once the poses are estimates, :ref:`/tutorial/pipelines/rgbd_integration.ipynb` @@ -86,8 +86,8 @@ Batch processing .. literalinclude:: ../../../examples/python/reconstruction_system/make_fragments.py :language: python - :lineno-start: 193 - :lines: 27,194-217 + :lineno-start: 181 + :lines: 27,182-205 :linenos: The main function calls each individual function explained above. diff --git a/docs/tutorial/reconstruction_system/system_overview.rst b/docs/tutorial/reconstruction_system/system_overview.rst index 3aa76cd16f9..2cae7ed387e 100644 --- a/docs/tutorial/reconstruction_system/system_overview.rst +++ b/docs/tutorial/reconstruction_system/system_overview.rst @@ -32,38 +32,66 @@ the scene. This part uses :ref:`/tutorial/pipelines/rgbd_integration.ipynb`. Example dataset `````````````````````````````````````` -We use `the SceneNN dataset <http://people.sutd.edu.sg/~saikit/projects/sceneNN/>`_ -to demonstrate the system in this tutorial. Alternatively, there are lots of -excellent RGBD datasets such as `Redwood data <http://redwood-data.org/>`_, -`TUM RGBD data <https://vision.in.tum.de/data/datasets/rgbd-dataset>`_, -`ICL-NUIM data <https://www.doc.ic.ac.uk/~ahanda/VaFRIC/iclnuim.html>`_, and -`SUN3D data <http://sun3d.cs.princeton.edu/>`_. - -The tutorial uses sequence ``016`` from the SceneNN dataset. This is a -`quick link <https://drive.google.com/open?id=11U8jEDYKvB5lXsK3L1rQcGTjp0YmRrzT>`_ -to download the RGBD sequence used in this tutorial. Alternatively, you can -download the original dataset from -`SceneNN oni file archive <https://drive.google.com/drive/folders/0B-aa7y5Ox4eZUmhJdmlYc3BQSG8>`_, -and then extract the ``oni`` file into color and depth image sequence using -`OniParser from the Redwood reconstruction system <http://redwood-data.org/indoor/tutorial.html>`_ -or other conversion tools. Some helper scripts can be found from -``reconstruction_system/scripts``. +We provide default datasets such as Lounge RGB-D dataset from Stanford, Bedroom RGB-D dataset from Redwood, +Jack Jack RealSense L515 bag file dataset to demonstrate the system in this tutorial. +Other than this, one may user any RGB-D data. +There are lots of excellent RGBD datasets such as: +`Redwood data <http://redwood-data.org/>`_, `TUM RGBD data <https://vision.in.tum.de/data/datasets/rgbd-dataset>`_, +`ICL-NUIM data <https://www.doc.ic.ac.uk/~ahanda/VaFRIC/iclnuim.html>`_, +`the SceneNN dataset <http://people.sutd.edu.sg/~saikit/projects/sceneNN/>`_ and `SUN3D data <http://sun3d.cs.princeton.edu/>`_. .. _reconstruction_system_how_to_run_the_pipeline: Quick start `````````````````````````````````````` - -Put all color images in the ``image`` folder, and all depth images in the -``depth`` folder. Run the following commands from the root folder. +Getting the example code .. code-block:: sh + # Activate your conda enviroment, where you have installed open3d pip package. + # Clone the Open3D github repository and go to the example. cd examples/python/reconstruction_system/ - python run_system.py [config_file] [--make] [--register] [--refine] [--integrate] -``config_file`` has parameters and file paths. For example, -``reconstruction_system/config/tutorial.json`` has the following script. + # Show CLI help for `run_system.py` + python dense_slam_gui.py --help + +Running the example with default dataset. + +.. code-block:: sh + + # The following command, will download and use the default dataset, + # which is ``lounge`` dataset from stanford. + # --make will make fragments from RGBD sequence. + # --register will register all fragments to detect loop closure. + # --refine flag will refine rough registrations. + # --integrate flag will integrate the whole RGBD sequence to make final mesh. + # [Optional] Use --slac and --slac_integrate flags to perform SLAC optimisation. + python run_system.py --make --register --refine --integrate + +Changing the default dataset. +One may change the default dataset to other avaialble datasets. +Currently the following datasets are available: + +1. Lounge (keyword: ``lounge``) (Default) + +2. Bedroom (keyword: ``bedroom``) + +3. Jack Jack (keyword: ``jack_jack``) + + +.. code-block:: sh + + # Using jack_jack as the default dataset. + python run_system.py --default_dataset 'bedroom' --make --register --refine --integrate + +Running the example with custom dataset using config file. +Manually download or store the data in a folder and store all the color images +in the ``image`` sub-folder, and all the depth images in the ``depth`` sub-folder. +Create a ``config.json`` file and set the ``path_dataset`` to the data directory. +Override the parameters for which you want to change the default values. + +Example config file for offline reconstruction system has been provided in +``examples/python/reconstruction_system/config/tutorial.json``, which looks like the following: .. literalinclude:: ../../../examples/python/reconstruction_system/config/tutorial.json :language: json diff --git a/docs/tutorial/t_reconstruction_system/index.rst b/docs/tutorial/t_reconstruction_system/index.rst index bd41306741b..31322f613c0 100644 --- a/docs/tutorial/t_reconstruction_system/index.rst +++ b/docs/tutorial/t_reconstruction_system/index.rst @@ -19,6 +19,76 @@ If you use any part of the tensor-based reconstruction system or the hash map ba .. note:: As of now the tutorial is only for **online** dense SLAM, and **offline** integration **with** provided poses. The tutorials for tensor-based **offline** reconstruction system, Simultaneous localization and calibration (SLAC), and shape from shading (SfS) tutorials as mentioned in [Dong2021]_ are still under construction. At current, please refer to :ref:`reconstruction_system` for the legacy versions. +Quick start +`````````````````````````````````````` +Getting the example code + +.. code-block:: sh + + # Activate your conda enviroment, where you have installed open3d pip package. + # Clone the Open3D github repository and go to the example. + cd examples/python/t_reconstruction_system/ + + # Show CLI help for ``dense_slam_gui.py`` + python dense_slam_gui.py --help + +Running the example with default dataset. + +.. code-block:: sh + + # The following command, will download and use the default dataset, + # which is ``lounge`` dataset from stanford. + python dense_slam_gui.py + +It is recommended to use CUDA if avaialble. + +.. code-block:: sh + + # The following command, will download and use the default dataset, + # which is ``lounge`` dataset from stanford. + python dense_slam_gui.py --device 'cuda:0' + +Changing the default dataset. +One may change the default dataset to other avaialble datasets. +Currently the following datasets are available: + +1. Lounge (keyword: ``lounge``) (Default) + +2. Bedroom (keyword: ``bedroom``) + +3. Jack Jack (keyword: ``jack_jack``) + +.. code-block:: sh + + # Using jack_jack as the default dataset. + python dense_slam_gui.py --default_dataset 'bedroom' + + +Running the example with custom dataset using config file. +Manually download or store the data in a folder and store all the color images +in the ``image`` sub-folder, and all the depth images in the ``depth`` sub-folder. +Create a ``config.yml`` file and set the ``path_dataset`` to the data directory. +Override the parameters for which you want to change the default values. + +Example config file for online reconstruction system has been provided in +``examples/python/t_reconstruction_system/default_config.yml``, which looks like the following: + +.. literalinclude:: ../../../examples/python/t_reconstruction_system/default_config.yml + :language: yml + :lineno-start: 1 + :lines: 1- + :linenos: + +Capture your own dataset +`````````````````````````````````````` + +This tutorial provides an example that can record synchronized and aligned RGBD +images using the Intel RealSense camera. For more details, please see +:ref:`capture_your_own_dataset`. + +Getting started with online reconstruction system +`````````````````````````````````````` + .. toctree:: voxel_block_grid diff --git a/docs/tutorial/t_reconstruction_system/integration.rst b/docs/tutorial/t_reconstruction_system/integration.rst index 971d164f5d9..e62d9bf3cfc 100644 --- a/docs/tutorial/t_reconstruction_system/integration.rst +++ b/docs/tutorial/t_reconstruction_system/integration.rst @@ -62,7 +62,7 @@ The voxel block grids can be saved to and loaded from `.npz` files that are acce :lineno-start: 47 :lines: 27,48,98 -The `.npz` file of the aforementioned voxel block grid contains the following entries: +The ``.npz`` file of the aforementioned voxel block grid contains the following entries: - ``attr_name_tsdf``: stores the value buffer index: 0 - ``attr_name_weight``: stores the value buffer index: 1 diff --git a/examples/cpp/OfflineSLAM.cpp b/examples/cpp/OfflineSLAM.cpp index a0c8ddb47c4..a2b668be44b 100644 --- a/examples/cpp/OfflineSLAM.cpp +++ b/examples/cpp/OfflineSLAM.cpp @@ -32,7 +32,7 @@ void PrintHelp() { PrintOpen3DVersion(); // clang-format off utility::LogInfo("Usage:"); - utility::LogInfo(" > DenseSLAM [options]"); + utility::LogInfo(" > OfflineSLAM [options]"); utility::LogInfo(" Given an RGBD image sequence, perform frame-to-model tracking and mapping, and reconstruct the surface."); utility::LogInfo(""); utility::LogInfo("Basic options:"); @@ -47,6 +47,7 @@ void PrintHelp() { utility::LogInfo(" --device [CPU:0]"); utility::LogInfo(" --pointcloud [file path to save the extracted pointcloud]"); utility::LogInfo(" --mesh [file path to save the extracted mesh]"); + utility::LogInfo("To run similar example with a default dataset, try the `OnlineSLAMRGBD` example"); // clang-format on utility::LogInfo(""); } diff --git a/examples/cpp/OnlineSLAMRGBD.cpp b/examples/cpp/OnlineSLAMRGBD.cpp index b37b4913117..e5c213c91c7 100644 --- a/examples/cpp/OnlineSLAMRGBD.cpp +++ b/examples/cpp/OnlineSLAMRGBD.cpp @@ -84,12 +84,21 @@ void PrintHelp() { // clang-format off utility::LogInfo("Usage:"); - utility::LogInfo(" > RGBDDenseSLAM [dataset_path] [options]"); + utility::LogInfo(" > OnlineSLAMRGBD [options]"); utility::LogInfo("Basic options:"); utility::LogInfo(" [-V]"); + utility::LogInfo(" [--dataset_path /path/to/dataset]"); + utility::LogInfo(" - To use your own dataset, pass the path"); + utility::LogInfo(" to the dataset root folder containing"); + utility::LogInfo(" `image` and `depth` folder. If not"); + utility::LogInfo(" provided, default dataset will be used."); utility::LogInfo(" [--intrinsic_path camera_intrinsic.json]"); utility::LogInfo(" [--align]"); utility::LogInfo(" [--device CUDA:0]"); + utility::LogInfo(" [--default_dataset lounge]"); + utility::LogInfo(" - To change default dataset (used when"); + utility::LogInfo(" dataset_path is not set)."); + utility::LogInfo(" Available options: `lounge` and `bedroom`."); // clang-format on utility::LogInfo(""); } @@ -100,18 +109,41 @@ int main(int argc, char* argv[]) { utility::SetVerbosityLevel(utility::VerbosityLevel::Debug); - if (argc < 2 || + if (argc < 1 || utility::ProgramOptionExistsAny(argc, argv, {"-h", "--help"})) { PrintHelp(); return 1; } - std::string dataset_path = argv[1]; - if (!utility::filesystem::DirectoryExists(dataset_path)) { - utility::LogWarning( - "Expected an existing directory, but {} does not exist.", - dataset_path); - return -1; + bool use_default_dataset = true; + + std::string dataset_path = + utility::GetProgramOptionAsString(argc, argv, "--dataset_path", ""); + if (!dataset_path.empty()) { + if (!utility::filesystem::DirectoryExists(dataset_path)) { + utility::LogError( + "Expected an existing directory, but {} does not exist.", + dataset_path); + } + + use_default_dataset = false; + } + + if (use_default_dataset) { + const std::string default_dataset = utility::GetProgramOptionAsString( + argc, argv, "--default_dataset", "lounge"); + if (default_dataset == "lounge") { + data::LoungeRGBDImages dataset; + dataset_path = dataset.GetExtractDir(); + } else if (default_dataset == "bedroom") { + data::BedroomRGBDImages dataset; + dataset_path = dataset.GetExtractDir(); + } else { + utility::LogError( + "The default_dataset {}, is not available. Please select " + "from `lounge` (default) and `bedroom` dataset.", + default_dataset); + } } if (utility::ProgramOptionExists(argc, argv, "-V")) { diff --git a/examples/cpp/OnlineSLAMRealSense.cpp b/examples/cpp/OnlineSLAMRealSense.cpp index ea594ab4627..92e67ac61c1 100644 --- a/examples/cpp/OnlineSLAMRealSense.cpp +++ b/examples/cpp/OnlineSLAMRealSense.cpp @@ -37,7 +37,7 @@ void PrintHelp() { // clang-format off utility::LogInfo("Usage:"); - utility::LogInfo(" > RealSenseDenseSLAMGUI [options]"); + utility::LogInfo(" > OnlineSLAMRealSense [options]"); utility::LogInfo("Basic options:"); utility::LogInfo(" [-V]"); utility::LogInfo(" [--use_bag_file /path/to/realsense_video_file.bag] If not provided, it will look for realsense sensor."); diff --git a/examples/python/open3d_example.py b/examples/python/open3d_example.py index 4447fdba2dd..2058ffa496a 100644 --- a/examples/python/open3d_example.py +++ b/examples/python/open3d_example.py @@ -207,6 +207,18 @@ def add_if_exists(path_dataset, folder_names): f"None of the folders {folder_names} found in {path_dataset}") +def read_rgbd_image(color_file, depth_file, convert_rgb_to_intensity, config): + color = o3d.io.read_image(color_file) + depth = o3d.io.read_image(depth_file) + rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( + color, + depth, + depth_scale=config["depth_scale"], + depth_trunc=config["max_depth"], + convert_rgb_to_intensity=convert_rgb_to_intensity) + return rgbd_image + + def get_rgbd_folders(path_dataset): path_color = add_if_exists(path_dataset, ["image/", "rgb/", "color/"]) path_depth = join(path_dataset, "depth/") @@ -277,29 +289,6 @@ def read_poses_from_log(traj_log): return trans_arr -def extract_rgbd_frames(rgbd_video_file): - """ - Extract color and aligned depth frames and intrinsic calibration from an - RGBD video file (currently only RealSense bag files supported). Folder - structure is: - <directory of rgbd_video_file/<rgbd_video_file name without extension>/ - {depth/00000.jpg,color/00000.png,intrinsic.json} - """ - frames_folder = join(dirname(rgbd_video_file), - basename(splitext(rgbd_video_file)[0])) - path_intrinsic = join(frames_folder, "intrinsic.json") - if isfile(path_intrinsic): - warn(f"Skipping frame extraction for {rgbd_video_file} since files are" - " present.") - else: - rgbd_video = o3d.t.io.RGBDVideoReader.create(rgbd_video_file) - rgbd_video.save_frames(frames_folder) - with open(path_intrinsic) as intr_file: - intr = json.load(intr_file) - depth_scale = intr["depth_scale"] - return frames_folder, path_intrinsic, depth_scale - - flip_transform = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]] diff --git a/examples/python/reconstruction_system/colored_icp.py b/examples/python/reconstruction_system/colored_icp.py deleted file mode 100644 index 8e2c5cf2523..00000000000 --- a/examples/python/reconstruction_system/colored_icp.py +++ /dev/null @@ -1,87 +0,0 @@ -# ---------------------------------------------------------------------------- -# - Open3D: www.open3d.org - -# ---------------------------------------------------------------------------- -# The MIT License (MIT) -# -# Copyright (c) 2018-2021 www.open3d.org -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# ---------------------------------------------------------------------------- - -# examples/python/reconstruction_system/colored_icp.py - -import numpy as np -import open3d as o3d -import os, sys - -pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -sys.path.append(pyexample_path) - -from utility.visualization import draw_registration_result_original_color -import argparse - - -def multiscale_icp(source, - target, - voxel_size, - max_iter, - init_transformation=np.identity(4)): - current_transformation = init_transformation - for i, scale in enumerate(range(len(max_iter))): # multi-scale approach - iter = max_iter[scale] - distance_threshold = 0.07 - print("voxel_size {}".format(voxel_size[scale])) - source_down = source.voxel_down_sample(voxel_size[scale]) - target_down = target.voxel_down_sample(voxel_size[scale]) - source_down.estimate_normals( - o3d.geometry.KDTreeSearchParamHybrid(radius=voxel_size[scale] * 2.0, - max_nn=30)) - target_down.estimate_normals( - o3d.geometry.KDTreeSearchParamHybrid(radius=voxel_size[scale] * 2.0, - max_nn=30)) - result_icp = o3d.pipelines.registration.registration_colored_icp( - source_down, target_down, distance_threshold, - current_transformation, - o3d.pipelines.registration.TransformationEstimationForColoredICP(), - o3d.pipelines.registration.ICPConvergenceCriteria( - relative_fitness=1e-6, relative_rmse=1e-6, max_iteration=iter)) - - current_transformation = result_icp.transformation - draw_registration_result_original_color(source, target, - current_transformation) - print(current_transformation) - - return result_icp.transformation - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('src') - parser.add_argument('dst') - parser.add_argument('--voxel_size', default=0.05, type=float) - args = parser.parse_args() - - o3d.utility.set_verbosity_level(o3d.utility.Debug) - source = o3d.io.read_point_cloud(args.src) - target = o3d.io.read_point_cloud(args.dst) - voxel_size = args.voxel_size - - trans = multiscale_icp(source, target, - [voxel_size, voxel_size / 2.0, voxel_size / 4.0], - [50, 30, 14], np.identity(4)) diff --git a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/apartment.json b/examples/python/reconstruction_system/config/indoor_lidar_rgbd/apartment.json deleted file mode 100644 index 0c2aa90052f..00000000000 --- a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/apartment.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Indoor Lidar-RGBD Dataset: http://redwood-data.org/indoor_lidar_rgbd/download.html", - "path_dataset": "dataset/indoor_lidar_rgbd/apartment/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/bedroom.json b/examples/python/reconstruction_system/config/indoor_lidar_rgbd/bedroom.json deleted file mode 100644 index 18b22284fa8..00000000000 --- a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/bedroom.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Indoor Lidar-RGBD Dataset: http://redwood-data.org/indoor_lidar_rgbd/download.html", - "path_dataset": "dataset/indoor_lidar_rgbd/bedroom/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/boardroom.json b/examples/python/reconstruction_system/config/indoor_lidar_rgbd/boardroom.json deleted file mode 100644 index 0da6c60a9a7..00000000000 --- a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/boardroom.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Indoor Lidar-RGBD Dataset: http://redwood-data.org/indoor_lidar_rgbd/download.html", - "path_dataset": "dataset/indoor_lidar_rgbd/boardroom/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/lobby.json b/examples/python/reconstruction_system/config/indoor_lidar_rgbd/lobby.json deleted file mode 100644 index e5a42b73aaf..00000000000 --- a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/lobby.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Indoor Lidar-RGBD Dataset: http://redwood-data.org/indoor_lidar_rgbd/download.html", - "path_dataset": "dataset/indoor_lidar_rgbd/lobby/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/loft.json b/examples/python/reconstruction_system/config/indoor_lidar_rgbd/loft.json deleted file mode 100644 index 24fdacb11b7..00000000000 --- a/examples/python/reconstruction_system/config/indoor_lidar_rgbd/loft.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Indoor Lidar-RGBD Dataset: http://redwood-data.org/indoor_lidar_rgbd/download.html", - "path_dataset": "dataset/indoor_lidar_rgbd/loft/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/car.json b/examples/python/reconstruction_system/config/redwood_objects/car.json deleted file mode 100644 index cfa062f6dfc..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/car.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/car/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/chair.json b/examples/python/reconstruction_system/config/redwood_objects/chair.json deleted file mode 100644 index fe39966fa8f..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/chair.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/chair/", - "path_intrinsic": "", - "max_depth": 2.0, - "voxel_size": 0.02, - "max_depth_diff": 0.03, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 2.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/motorcycle.json b/examples/python/reconstruction_system/config/redwood_objects/motorcycle.json deleted file mode 100644 index b50971d71a0..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/motorcycle.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/motorcycle/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/plant.json b/examples/python/reconstruction_system/config/redwood_objects/plant.json deleted file mode 100644 index 4d76835196a..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/plant.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/plant/", - "path_intrinsic": "", - "max_depth": 2.0, - "voxel_size": 0.02, - "max_depth_diff": 0.03, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 2.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/sofa.json b/examples/python/reconstruction_system/config/redwood_objects/sofa.json deleted file mode 100644 index a0c69468ce3..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/sofa.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/sofa/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_objects/truck.json b/examples/python/reconstruction_system/config/redwood_objects/truck.json deleted file mode 100644 index c98eeca1f2d..00000000000 --- a/examples/python/reconstruction_system/config/redwood_objects/truck.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Single object scans http://redwood-data.org/3dscan/index.html", - "path_dataset": "dataset/redwood_objects/truck/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-clean.json b/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-clean.json deleted file mode 100644 index a1a8fce4550..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-clean.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/livingroom1-clean/", - "path_intrinsic": "", - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true, - "max_iterations": 5, - "sdf_trunc": 0.04, - "block_count": 40000, - "distance_threshold": 0.07, - "fitness_threshold": 0.3, - "regularizer_weight": 1, - "method": "slac", - "device": "CPU:0", - "save_output_as": "pointcloud" -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-simulated.json b/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-simulated.json deleted file mode 100644 index 561f01a9d85..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/livingroom1-simulated.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/livingroom1-simulated/", - "path_intrinsic": "", - "n_frames_per_fragment": 50, - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 20.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-clean.json b/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-clean.json deleted file mode 100644 index 261aa335d27..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-clean.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/livingroom2-clean/", - "path_intrinsic": "", - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-simulated.json b/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-simulated.json deleted file mode 100644 index 3674f64682b..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/livingroom2-simulated.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/livingroom2-simulated/", - "path_intrinsic": "", - "n_frames_per_fragment": 50, - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 20.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/office1-clean.json b/examples/python/reconstruction_system/config/redwood_simulated/office1-clean.json deleted file mode 100644 index 27b028528de..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/office1-clean.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/office1-clean/", - "path_intrinsic": "", - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/office1-simulated.json b/examples/python/reconstruction_system/config/redwood_simulated/office1-simulated.json deleted file mode 100644 index cfd6bc27421..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/office1-simulated.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/office1-simulated/", - "path_intrinsic": "", - "n_frames_per_fragment": 50, - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 20.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/office2-clean.json b/examples/python/reconstruction_system/config/redwood_simulated/office2-clean.json deleted file mode 100644 index 356dfc5e8d0..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/office2-clean.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/office2-clean/", - "path_intrinsic": "", - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/redwood_simulated/office2-simulated.json b/examples/python/reconstruction_system/config/redwood_simulated/office2-simulated.json deleted file mode 100644 index e03231280c2..00000000000 --- a/examples/python/reconstruction_system/config/redwood_simulated/office2-simulated.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Redwood Dataset: http://redwood-data.org/indoor/dataset.html", - "path_dataset": "dataset/redwood_simulated/office2-simulated/", - "path_intrinsic": "", - "n_frames_per_fragment": 50, - "max_depth": 5.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 20.0, - "tsdf_cubic_size": 4.0, - "icp_method": "point_to_point", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/burghers.json b/examples/python/reconstruction_system/config/stanford/burghers.json deleted file mode 100644 index fcc1409e89d..00000000000 --- a/examples/python/reconstruction_system/config/stanford/burghers.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/burghers/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/cactusgarden.json b/examples/python/reconstruction_system/config/stanford/cactusgarden.json deleted file mode 100644 index b6190da4a13..00000000000 --- a/examples/python/reconstruction_system/config/stanford/cactusgarden.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/cactusgarden/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/copyroom.json b/examples/python/reconstruction_system/config/stanford/copyroom.json deleted file mode 100644 index 2146a8ae7a3..00000000000 --- a/examples/python/reconstruction_system/config/stanford/copyroom.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/copyroom/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/lounge.json b/examples/python/reconstruction_system/config/stanford/lounge.json deleted file mode 100644 index 3c419ad4567..00000000000 --- a/examples/python/reconstruction_system/config/stanford/lounge.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/lounge/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/stonewall.json b/examples/python/reconstruction_system/config/stanford/stonewall.json deleted file mode 100644 index b0267d174e2..00000000000 --- a/examples/python/reconstruction_system/config/stanford/stonewall.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/stonewall/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/config/stanford/totempole.json b/examples/python/reconstruction_system/config/stanford/totempole.json deleted file mode 100644 index 9e1f482d5c3..00000000000 --- a/examples/python/reconstruction_system/config/stanford/totempole.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Open3D reconstruction tutorial http://open3d.org/docs/release/tutorial/reconstruction_system/system_overview.html", - "path_dataset": "dataset/stanford/totempole/", - "path_intrinsic": "", - "max_depth": 3.0, - "voxel_size": 0.05, - "max_depth_diff": 0.07, - "preference_loop_closure_odometry": 0.1, - "preference_loop_closure_registration": 5.0, - "tsdf_cubic_size": 3.0, - "icp_method": "color", - "global_registration": "ransac", - "python_multi_threading": true -} diff --git a/examples/python/reconstruction_system/data_loader.py b/examples/python/reconstruction_system/data_loader.py new file mode 100644 index 00000000000..2333d88aa09 --- /dev/null +++ b/examples/python/reconstruction_system/data_loader.py @@ -0,0 +1,96 @@ +# ---------------------------------------------------------------------------- +# - Open3D: www.open3d.org - +# ---------------------------------------------------------------------------- +# The MIT License (MIT) +# +# Copyright (c) 2018-2021 www.open3d.org +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# ---------------------------------------------------------------------------- + +import open3d as o3d + + +def lounge_data_loader(): + print('Loading Stanford Lounge RGB-D Dataset') + + # Get the dataset. + lounge_rgbd = o3d.data.LoungeRGBDImages() + + # Set dataset specific parameters. + config = {} + config['path_dataset'] = lounge_rgbd.extract_dir + config['path_intrinsic'] = "" + config['max_depth'] = 3.0 + config['voxel_size'] = 0.05 + config['max_depth_diff'] = 0.07 + config['preference_loop_closure_odometry'] = 0.1 + config['preference_loop_closure_registration'] = 5.0 + config['tsdf_cubic_size'] = 3.0 + config['icp_method'] = "color" + config['global_registration'] = "ransac" + config['python_multi_threading'] = True + + return config + + +def bedroom_data_loader(): + print('Loading Redwood Bedroom RGB-D Dataset') + + # Get the dataset. + bedroom_rgbd = o3d.data.BedroomRGBDImages() + + # Set dataset specific parameters. + config = {} + config['path_dataset'] = bedroom_rgbd.extract_dir + config['path_intrinsic'] = "" + config['max_depth'] = 3.0 + config['voxel_size'] = 0.05 + config['max_depth_diff'] = 0.07 + config['preference_loop_closure_odometry'] = 0.1 + config['preference_loop_closure_registration'] = 5.0 + config['tsdf_cubic_size'] = 3.0 + config['icp_method'] = "color" + config['global_registration'] = "ransac" + config['python_multi_threading'] = True + + return config + + +def jackjack_data_loader(): + print('Loading RealSense L515 Jack-Jack RGB-D Bag Dataset') + + # Get the dataset. + jackjack_bag = o3d.data.JackJackL515Bag() + + # Set dataset specific parameters. + config = {} + config['path_dataset'] = jackjack_bag.path + config['path_intrinsic'] = "" + config['max_depth'] = 0.85 + config['voxel_size'] = 0.025 + config['max_depth_diff'] = 0.03 + config['preference_loop_closure_odometry'] = 0.1 + config['preference_loop_closure_registration'] = 5.0 + config['tsdf_cubic_size'] = 0.75 + config['icp_method'] = "color" + config['global_registration'] = "ransac" + config['python_multi_threading'] = True + + return config diff --git a/examples/python/reconstruction_system/initialize_config.py b/examples/python/reconstruction_system/initialize_config.py index 750e78a8b4b..56a30569ee2 100644 --- a/examples/python/reconstruction_system/initialize_config.py +++ b/examples/python/reconstruction_system/initialize_config.py @@ -26,13 +26,37 @@ # examples/python/reconstruction_system/initialize_config.py +import open3d as o3d + import os import sys +import json +from os.path import isfile, join, splitext, dirname, basename +from warnings import warn +from data_loader import lounge_data_loader, bedroom_data_loader, jackjack_data_loader -pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -sys.path.append(pyexample_path) -from open3d_example import extract_rgbd_frames +def extract_rgbd_frames(rgbd_video_file): + """ + Extract color and aligned depth frames and intrinsic calibration from an + RGBD video file (currently only RealSense bag files supported). Folder + structure is: + <directory of rgbd_video_file/<rgbd_video_file name without extension>/ + {depth/00000.jpg,color/00000.png,intrinsic.json} + """ + frames_folder = join(dirname(rgbd_video_file), + basename(splitext(rgbd_video_file)[0])) + path_intrinsic = join(frames_folder, "intrinsic.json") + if isfile(path_intrinsic): + warn(f"Skipping frame extraction for {rgbd_video_file} since files are" + " present.") + else: + rgbd_video = o3d.t.io.RGBDVideoReader.create(rgbd_video_file) + rgbd_video.save_frames(frames_folder) + with open(path_intrinsic) as intr_file: + intr = json.load(intr_file) + depth_scale = intr["depth_scale"] + return frames_folder, path_intrinsic, depth_scale def set_default_value(config, key, value): @@ -102,3 +126,26 @@ def initialize_config(config): print("Extracting frames from RGBD video file") config["path_dataset"], config["path_intrinsic"], config[ "depth_scale"] = extract_rgbd_frames(config["path_dataset"]) + + +def dataset_loader(dataset_name): + print('Config file was not passed. Using deafult dataset.') + # Load the dataset and config. + config = {} + if dataset_name == 'lounge': + config = lounge_data_loader() + elif dataset_name == 'bedroom': + config = bedroom_data_loader() + elif dataset_name == 'jack_jack': + config = jackjack_data_loader() + else: + print( + "The requested dataset is not available. Available dataset options include lounge and jack_jack." + ) + sys.exit(1) + + # Set the default values for non-specified parameters. + initialize_config(config) + + print('Loaded data from {}'.format(config['path_dataset'])) + return config diff --git a/examples/python/reconstruction_system/integrate_scene.py b/examples/python/reconstruction_system/integrate_scene.py index dc919134320..10923e99a61 100644 --- a/examples/python/reconstruction_system/integrate_scene.py +++ b/examples/python/reconstruction_system/integrate_scene.py @@ -36,9 +36,6 @@ from open3d_example import * -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from make_fragments import read_rgbd_image - def scalable_integrate_rgb_frames(path_dataset, intrinsic, config): poses = [] diff --git a/examples/python/reconstruction_system/make_fragments.py b/examples/python/reconstruction_system/make_fragments.py index 50d767b6141..72c99f6e37a 100644 --- a/examples/python/reconstruction_system/make_fragments.py +++ b/examples/python/reconstruction_system/make_fragments.py @@ -34,7 +34,7 @@ pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pyexample_path) -from open3d_example import join, make_clean_folder, get_rgbd_file_lists, initialize_opencv +from open3d_example import * sys.path.append(os.path.dirname(os.path.abspath(__file__))) from optimize_posegraph import optimize_posegraph_for_fragment @@ -45,18 +45,6 @@ from opencv_pose_estimation import pose_estimation -def read_rgbd_image(color_file, depth_file, convert_rgb_to_intensity, config): - color = o3d.io.read_image(color_file) - depth = o3d.io.read_image(depth_file) - rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( - color, - depth, - depth_scale=config["depth_scale"], - depth_trunc=config["max_depth"], - convert_rgb_to_intensity=convert_rgb_to_intensity) - return rgbd_image - - def register_one_rgbd_pair(s, t, color_files, depth_files, intrinsic, with_opencv, config): source_rgbd_image = read_rgbd_image(color_files[s], depth_files[s], True, diff --git a/examples/python/reconstruction_system/run_system.py b/examples/python/reconstruction_system/run_system.py index e4baf0f21e8..5efb3a6758a 100644 --- a/examples/python/reconstruction_system/run_system.py +++ b/examples/python/reconstruction_system/run_system.py @@ -41,11 +41,19 @@ from open3d_example import check_folder_structure sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from initialize_config import initialize_config +from initialize_config import initialize_config, dataset_loader if __name__ == "__main__": parser = argparse.ArgumentParser(description="Reconstruction system") - parser.add_argument("config", help="path to the config file") + parser.add_argument("--config", + help="path to the config file", + default=None) + parser.add_argument("--default_dataset", + help="(optional) default dataset to be used, only if " + "config file is not provided. " + "Options: [lounge, bedroom, jack_jack]", + type=str, + default="lounge") parser.add_argument("--make", help="Step 1) make fragments from RGBD sequence.", action="store_true") @@ -90,12 +98,16 @@ parser.print_help(sys.stderr) sys.exit(1) - # check folder structure + # load dataset and check folder structure if args.config is not None: with open(args.config) as json_file: config = json.load(json_file) initialize_config(config) - check_folder_structure(config["path_dataset"]) + check_folder_structure(config['path_dataset']) + else: + # load deafult dataset. + config = dataset_loader(args.default_dataset) + assert config is not None if args.debug_mode: diff --git a/examples/python/reconstruction_system/scripts/__init__.py b/examples/python/reconstruction_system/scripts/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/python/reconstruction_system/scripts/download_dataset.py b/examples/python/reconstruction_system/scripts/download_dataset.py deleted file mode 100644 index 62e85784e9c..00000000000 --- a/examples/python/reconstruction_system/scripts/download_dataset.py +++ /dev/null @@ -1,90 +0,0 @@ -# ---------------------------------------------------------------------------- -# - Open3D: www.open3d.org - -# ---------------------------------------------------------------------------- -# The MIT License (MIT) -# -# Copyright (c) 2018-2021 www.open3d.org -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# ---------------------------------------------------------------------------- -""" -Cross-platform Python script to download and extract datasets. All common -archive formats are supported. -python download_dataset.py dataset_name ... [--cache download-folder] -[--extract-to local-folder] -""" -import urllib.request -import shutil -import os -import argparse - -dataset_dict = { - "L515_test": - "https://storage.googleapis.com/isl-datasets/open3d-dev/realsense/L515_test.bag", - "L515_paper_lantern": - "https://storage.googleapis.com/isl-datasets/open3d-dev/realsense/L515_paper_lantern.bag", - "L515_JackJack": - "https://storage.googleapis.com/isl-datasets/open3d-dev/realsense/L515_JackJack.bag" -} - - -def download(dataset_name, download_folder, extract_folder): - """ - Download dataset 'dataset_name' to 'download_folder'. If it is an archive, - extract it to 'extract_folder', else move it there. - """ - cache_path = os.path.join(download_folder, - os.path.basename(dataset_dict[dataset_name])) - extract_path = os.path.join(extract_folder, dataset_name) - os.makedirs(os.path.realpath(extract_path), exist_ok=True) - with urllib.request.urlopen(dataset_dict[dataset_name]) as response: - with open(cache_path, 'wb') as cp_obj: - shutil.copyfileobj(response, cp_obj) - try: - shutil.unpack_archive(cache_path, extract_path) - except (ValueError, shutil.ReadError): # Not an archive - shutil.move(cache_path, extract_path) - print(f"Downloaded dataset {dataset_name} to {extract_path}") - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser( - description='Download and extract datasets.') - parser.add_argument('dataset_name', - nargs='*', - help='Names of datasets to download.') - parser.add_argument('-c', - '--cache', - default='.', - help='Download folder for caching archives.') - parser.add_argument('-e', - '--extract-to', - default='../datasets/', - help='Extract downloaded datasets here.') - parser.add_argument('-l', - '--list-datasets', - action='store_true', - help='List datasets') - - args = parser.parse_args() - if args.list_datasets: - print('Available datasets:\n\t' + '\n\t'.join(dataset_dict.keys())) - for ds in args.dataset_name: - download(ds, args.cache, args.extract_to) diff --git a/examples/python/reconstruction_system/scripts/download_indoor_lidar_rgbd.sh b/examples/python/reconstruction_system/scripts/download_indoor_lidar_rgbd.sh deleted file mode 100755 index 5d37eee8410..00000000000 --- a/examples/python/reconstruction_system/scripts/download_indoor_lidar_rgbd.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -set -e - -process_scene() -{ - DATA_NAME=$1 - GDRIVE_ID=$2 - ./gdrive_download.sh $GDRIVE_ID - unzip --qq $DATA_NAME.zip -d ../dataset/indoor_lidar_rgbd - rm $DATA_NAME.zip -} - -mkdir ../dataset/indoor_lidar_rgbd -process_scene "rgbd_apartment" "1TqoIE1Q1M30q8FBQ_dMcZj9JR6G0ztI5" -process_scene "rgbd_bedroom" "1SN318pHOQn7ioSABJLY6SQ1O7gVMDvB2" -process_scene "rgbd_boardroom" "1gRDVGgPR--cKKHkrlaXVzc1Zj9VhC3Dr" -process_scene "rgbd_lobby" "1MhjCJuznp3pG6zxHrIbmcjPjXhvlBStu" -process_scene "rgbd_loft" "1OOmymidV5nhmGSdk1Y7yI_9fXxLHNPjX" diff --git a/examples/python/reconstruction_system/scripts/download_redwood_objects.sh b/examples/python/reconstruction_system/scripts/download_redwood_objects.sh deleted file mode 100755 index 08b2ebf687a..00000000000 --- a/examples/python/reconstruction_system/scripts/download_redwood_objects.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -e - -process_redwood_object() -{ - DATA_NUM=$1 - DATA_NAME=$2 - GDRIVE_ID=$3 - ./gdrive_download.sh $GDRIVE_ID - unzip --qq $DATA_NUM.zip -d ../dataset/redwood_objects/$DATA_NAME - python synchronize_frames.py ${PWD}/../dataset/redwood_objects/$DATA_NAME - rm $DATA_NUM.zip -} - -mkdir ../dataset/redwood_objects -process_redwood_object "00021" "chair" "1iMxjIZMFcoL3s9FzzqM0K-tM2ehO74D0" -process_redwood_object "00577" "sofa" "1_WZK0AZTt7N3QBh9JnDypM1sPKnE0oIY" -process_redwood_object "01833" "car" "1HCRVzlZ0huAsTyQsjOvI2OsZ_oU3zpt9" -process_redwood_object "05984" "motorcycle" "1jZLTNrOIP2sFgzF9sHb027iI2JhOOqpu" -process_redwood_object "06127" "plant" "1nWilJfkAA7D3a8JEc_Tx9pLD4a25u8xG" -process_redwood_object "06822" "truck" "1TqkWcdzQZG50ZV9nXdZYZmR_aLH-WYkr" diff --git a/examples/python/reconstruction_system/scripts/download_redwood_simulated.sh b/examples/python/reconstruction_system/scripts/download_redwood_simulated.sh deleted file mode 100755 index c7b40f1e9bc..00000000000 --- a/examples/python/reconstruction_system/scripts/download_redwood_simulated.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -set -e - -download_redwood_scene() -{ - DATA_NAME=$1 - - # Source: http://redwood-data.org/indoor/data/$DATA_NAME-color.zip - wget https://github.com/isl-org/open3d_downloads/releases/download/redwood-simulated/$DATA_NAME-color.zip - - # Source: http://redwood-data.org/indoor/data/$DATA_NAME-depth-clean.zip - wget https://github.com/isl-org/open3d_downloads/releases/download/redwood-simulated/$DATA_NAME-depth-clean.zip - - # Source: http://redwood-data.org/indoor/data/$DATA_NAME-depth-simulated.zip - wget https://github.com/isl-org/open3d_downloads/releases/download/redwood-simulated/$DATA_NAME-depth-simulated.zip - -} - -unzip_redwood_scene() -{ - DATA_NAME=$1 - DATA_TYPE=$2 - mkdir $DATA_NAME-$DATA_TYPE - mkdir $DATA_NAME-$DATA_TYPE/image - mkdir $DATA_NAME-$DATA_TYPE/depth - unzip --qq $DATA_NAME-color.zip -d $DATA_NAME-$DATA_TYPE/image - unzip --qq $DATA_NAME-depth-$DATA_TYPE.zip -d $DATA_NAME-$DATA_TYPE/depth -} - -cd .. && mkdir dataset/redwood_simulated && cd dataset/redwood_simulated - -download_redwood_scene "livingroom1" -unzip_redwood_scene "livingroom1" "clean" -# unzip_redwood_scene "livingroom1" "simulated" - -download_redwood_scene "livingroom2" -unzip_redwood_scene "livingroom2" "clean" -# unzip_redwood_scene "livingroom2" "simulated" - -download_redwood_scene "office1" -unzip_redwood_scene "office1" "clean" -# unzip_redwood_scene "office1" "simulated" - -download_redwood_scene "office2" -unzip_redwood_scene "office2" "clean" -# unzip_redwood_scene "office2" "simulated" - -rm *.zip diff --git a/examples/python/reconstruction_system/scripts/download_stanford.sh b/examples/python/reconstruction_system/scripts/download_stanford.sh deleted file mode 100755 index d0d8bf33338..00000000000 --- a/examples/python/reconstruction_system/scripts/download_stanford.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -e - -process_stanford_scene() -{ - DATA_NAME=$1 - GDRIVE_ID=$2 - ./gdrive_download.sh $GDRIVE_ID - unzip --qq $DATA_NAME"_png.zip" -d ../dataset/stanford/$DATA_NAME - rm $DATA_NAME"_png.zip" -} - -mkdir ../dataset/stanford -process_stanford_scene "burghers" "0B6qjzcYetERgUU0wMkhnZVNCa28" -process_stanford_scene "lounge" "0B6qjzcYetERgSUZFT2FWdWsxQzQ" -process_stanford_scene "copyroom" "0B6qjzcYetERgWTBDYWdkVHN3aHc" -process_stanford_scene "cactusgarden" "0B6qjzcYetERgYUxUSFFIYjZIb3c" -process_stanford_scene "stonewall" "0B6qjzcYetERgOXBCM181bTdsUGc" -process_stanford_scene "totempole" "0B6qjzcYetERgNjVEWm5sSWFlWk0" diff --git a/examples/python/reconstruction_system/scripts/download_tutorial.sh b/examples/python/reconstruction_system/scripts/download_tutorial.sh deleted file mode 100755 index 376b73bd89e..00000000000 --- a/examples/python/reconstruction_system/scripts/download_tutorial.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -e - -./gdrive_download.sh 1dkA6Tjh-aEie1J8qGlY1NlyJVP0_FpBX -unzip -qq tutorial.zip -mv tutorial ../dataset/ -rm *.zip diff --git a/examples/python/reconstruction_system/scripts/gdrive_download.sh b/examples/python/reconstruction_system/scripts/gdrive_download.sh deleted file mode 100755 index 8463655bd23..00000000000 --- a/examples/python/reconstruction_system/scripts/gdrive_download.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -e - -# gdrive_download -# -# script to download Google Drive files from command line -# not guaranteed to work indefinitely -# taken from Stack Overflow answer: -# http://stackoverflow.com/a/38937732/7002068 - -gURL=$1 -# match more than 26 word characters -ggID=$(echo "$gURL" | egrep -o '(\w|-){26,}') - -ggURL='https://drive.google.com/uc?export=download' - -curl -sc /tmp/gcokie "${ggURL}&id=${ggID}" >/dev/null -getcode="$(awk '/_warning_/ {print $NF}' /tmp/gcokie)" - -cmd='curl --insecure -C - -LOJb /tmp/gcokie "${ggURL}&confirm=${getcode}&id=${ggID}"' -echo -e "Downloading from "$gURL"...\n" -eval $cmd diff --git a/examples/python/reconstruction_system/scripts/requirements.txt b/examples/python/reconstruction_system/scripts/requirements.txt deleted file mode 100644 index e4f93bc60d1..00000000000 --- a/examples/python/reconstruction_system/scripts/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -opencv-python -joblib diff --git a/examples/python/reconstruction_system/scripts/synchronize_frames.py b/examples/python/reconstruction_system/scripts/synchronize_frames.py deleted file mode 100644 index d5d34d921fa..00000000000 --- a/examples/python/reconstruction_system/scripts/synchronize_frames.py +++ /dev/null @@ -1,115 +0,0 @@ -# ---------------------------------------------------------------------------- -# - Open3D: www.open3d.org - -# ---------------------------------------------------------------------------- -# The MIT License (MIT) -# -# Copyright (c) 2018-2021 www.open3d.org -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# ---------------------------------------------------------------------------- - -# examples/python/reconstruction_system/scripts/synchronize_frames.py - -import math -import os -import sys -import shutil -import argparse - -pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -sys.path.append(pyexample_path) - -from open3d_example import * -# original code is written by Andrew. W. Chen -# input: openni style unsynchronized color and depth images -# output: synchronized color and depth images - - -def run_synchronization(args): - folder_path = args.dataset - color_files, depth_files = get_rgbd_file_lists(folder_path) - if args.debug_mode: - print(depth_files) - print(color_files) - - # filename format is: - # frame-timestamp.filetype - timestamps = { - 'depth': [None] * len(depth_files), - 'color': [None] * len(color_files) - } - for i, name in enumerate(depth_files): - depth_timestamp = int( - os.path.basename(depth_files[i]).replace('-', '.').split('.')[1]) - timestamps['depth'][i] = depth_timestamp - for i, name in enumerate(color_files): - color_timestamp = int( - os.path.basename(color_files[i]).replace('-', '.').split('.')[1]) - timestamps['color'][i] = color_timestamp - - # associations' index is the color frame, and the value at - # that index is the best depth frame for the color frame - associations = [] - depth_idx = 0 - for i in range(len(color_files)): - best_dist = float('inf') - while depth_idx <= len(depth_files) - 1 and i <= len(color_files) - 1: - dist = math.fabs(timestamps['depth'][depth_idx] - \ - timestamps['color'][i]) - if dist > best_dist: - break - best_dist = dist - depth_idx += 1 - if depth_idx > timestamps['depth'][-1]: - print("Ended at color frame %d, depth frame %d" % - (i, depth_idx)) - associations.append(depth_idx - 1) - if args.debug_mode: - print("%d %d %d %d" % - (i, depth_idx - 1, timestamps['depth'][depth_idx - 1], - timestamps['color'][i])) - - os.rename(os.path.join(folder_path, "depth"), - os.path.join(folder_path, "temp")) - if not os.path.exists(os.path.join(folder_path, "depth")): - os.makedirs(os.path.join(folder_path, "depth")) - for i, assn in enumerate(associations): - temp_name = os.path.join(folder_path, "temp", - os.path.basename(depth_files[assn])) - new_name = os.path.join(folder_path, "depth/%06d.png" % (i + 1)) - if args.debug_mode: - print(temp_name) - print(new_name) - if not exists(temp_name): - assert (i + 1 == len(color_files)) - os.remove(color_files[-1]) - else: - os.rename(temp_name, new_name) - shutil.rmtree(os.path.join(folder_path, "temp")) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - description="Synchronize color and depth images") - parser.add_argument("dataset", help="path to the dataset") - parser.add_argument("--debug_mode", - help="turn on debug mode", - action="store_true") - args = parser.parse_args() - run_synchronization(args) diff --git a/examples/python/t_reconstruction_system/common.py b/examples/python/t_reconstruction_system/common.py index bbc303c22f6..e190543f078 100644 --- a/examples/python/t_reconstruction_system/common.py +++ b/examples/python/t_reconstruction_system/common.py @@ -26,22 +26,89 @@ # examples/python/reconstruction_system/common.py +import open3d as o3d + import os +import sys +import json import numpy as np -import open3d as o3d import glob +from os.path import isfile, join, splitext, dirname, basename +from warnings import warn + + +def extract_rgbd_frames(rgbd_video_file): + """ + Extract color and aligned depth frames and intrinsic calibration from an + RGBD video file (currently only RealSense bag files supported). Folder + structure is: + <directory of rgbd_video_file/<rgbd_video_file name without extension>/ + {depth/00000.jpg,color/00000.png,intrinsic.json} + """ + frames_folder = join(dirname(rgbd_video_file), + basename(splitext(rgbd_video_file)[0])) + path_intrinsic = join(frames_folder, "intrinsic.json") + if isfile(path_intrinsic): + warn(f"Skipping frame extraction for {rgbd_video_file} since files are" + " present.") + else: + rgbd_video = o3d.t.io.RGBDVideoReader.create(rgbd_video_file) + rgbd_video.save_frames(frames_folder) + with open(path_intrinsic) as intr_file: + intr = json.load(intr_file) + depth_scale = intr["depth_scale"] + return frames_folder, path_intrinsic, depth_scale + + +def lounge_dataloader(config): + # Get the dataset. + lounge_rgbd = o3d.data.LoungeRGBDImages() + # Override default config parameters with dataset specific parameters. + config.path_dataset = lounge_rgbd.extract_dir + config.path_trajectory = lounge_rgbd.trajectory_log_path + config.depth_folder = "depth" + config.color_folder = "color" + return config + + +def bedroom_dataloader(config): + # Get the dataset. + bedroom_rgbd = o3d.data.BedroomRGBDImages() + # Override default config parameters with dataset specific parameters. + config.path_dataset = bedroom_rgbd.extract_dir + config.path_trajectory = bedroom_rgbd.trajectory_log_path + config.depth_folder = "depth" + config.color_folder = "image" + return config + + +def jack_jack_dataloader(config): + # Get the dataset. + jackjack_rgbd = o3d.data.JackJackL515Bag() + # Override default config parameters with dataset specific parameters. + print("Extracting frames from RGBD video file") + config.path_dataset = jackjack_rgbd.path + config.depth_folder = "depth" + config.color_folder = "color" + return config + + +def get_default_dataset(config): + print('Config file was not provided, falling back to default dataset.') + if config.default_dataset == 'lounge': + config = lounge_dataloader(config) + elif config.default_dataset == 'bedroom': + config = bedroom_dataloader(config) + elif config.default_dataset == 'jack_jack': + config = jack_jack_dataloader(config) + else: + print( + "The requested dataset is not available. Available dataset options include lounge and jack_jack." + ) + sys.exit(1) - -def get_default_testdata(): - example_path = os.path.abspath( - os.path.join(__file__, os.path.pardir, os.path.pardir, os.path.pardir)) - - redwood_rgbd = o3d.data.SampleRedwoodRGBDImages() - path_dataset = redwood_rgbd.extract_dir - print('Dataset not found, falling back to test examples {}'.format( - path_dataset)) - - return path_dataset + print('Loaded data from {}'.format(config.path_dataset)) + return config def load_depth_file_names(config): diff --git a/examples/python/t_reconstruction_system/dense_slam.py b/examples/python/t_reconstruction_system/dense_slam.py index 8a15a2d161c..63211390c79 100644 --- a/examples/python/t_reconstruction_system/dense_slam.py +++ b/examples/python/t_reconstruction_system/dense_slam.py @@ -35,7 +35,7 @@ import time from config import ConfigParser -from common import load_rgbd_file_names, save_poses, load_intrinsic, extract_trianglemesh, get_default_testdata +from common import get_default_dataset, load_rgbd_file_names, save_poses, load_intrinsic, extract_trianglemesh, get_default_testdata, extract_rgbd_frames def slam(depth_file_names, color_file_names, intrinsic, config): @@ -93,13 +93,26 @@ def slam(depth_file_names, color_file_names, intrinsic, config): help='YAML config file path. Please refer to default_config.yml as a ' 'reference. It overrides the default config file, but will be ' 'overridden by other command line inputs.') + parser.add('--default_dataset', + help='Default dataset is used when config file is not provided. ' + 'Default dataset may be selected from the following options: ' + '[lounge, bedroom, jack_jack]', + default='lounge') parser.add('--path_npz', help='path to the npz file that stores voxel block grid.', default='output.npz') config = parser.get_config() if config.path_dataset == '': - config.path_dataset = get_default_testdata() + config = get_default_dataset(config) + + # Extract RGB-D frames and intrinsic from bag file. + if config.path_dataset.endswith(".bag"): + assert os.path.isfile( + config.path_dataset), (f"File {config.path_dataset} not found.") + print("Extracting frames from RGBD video file") + config.path_dataset, config.path_intrinsic, config.depth_scale = extract_rgbd_frames( + config.path_dataset) depth_file_names, color_file_names = load_rgbd_file_names(config) intrinsic = load_intrinsic(config) diff --git a/examples/python/t_reconstruction_system/dense_slam_gui.py b/examples/python/t_reconstruction_system/dense_slam_gui.py index 8ec8a3c38e8..ad197bd2308 100644 --- a/examples/python/t_reconstruction_system/dense_slam_gui.py +++ b/examples/python/t_reconstruction_system/dense_slam_gui.py @@ -29,18 +29,18 @@ # P.S. This example is used in documentation, so, please ensure the changes are # synchronized. +import open3d as o3d +import open3d.core as o3c import open3d.visualization.gui as gui import open3d.visualization.rendering as rendering -import open3d as o3d -import open3d.core as o3c from config import ConfigParser import os, sys import numpy as np import threading import time -from common import load_rgbd_file_names, save_poses, load_intrinsic, extract_trianglemesh, get_default_testdata +from common import load_rgbd_file_names, save_poses, load_intrinsic, extract_trianglemesh, get_default_dataset, extract_rgbd_frames def set_enabled(widget, enable): @@ -462,13 +462,26 @@ def update_main(self): help='YAML config file path. Please refer to default_config.yml as a ' 'reference. It overrides the default config file, but will be ' 'overridden by other command line inputs.') + parser.add('--default_dataset', + help='Default dataset is used when config file is not provided. ' + 'Default dataset may be selected from the following options: ' + '[lounge, bedroom, jack_jack]', + default='lounge') parser.add('--path_npz', help='path to the npz file that stores voxel block grid.', default='output.npz') config = parser.get_config() if config.path_dataset == '': - config.path_dataset = get_default_testdata() + config = get_default_dataset(config) + + # Extract RGB-D frames and intrinsic from bag file. + if config.path_dataset.endswith(".bag"): + assert os.path.isfile( + config.path_dataset), (f"File {config.path_dataset} not found.") + print("Extracting frames from RGBD video file") + config.path_dataset, config.path_intrinsic, config.depth_scale = extract_rgbd_frames( + config.path_dataset) app = gui.Application.instance app.initialize() diff --git a/examples/python/t_reconstruction_system/integrate.py b/examples/python/t_reconstruction_system/integrate.py index c3047aee47b..f4f95cb168f 100644 --- a/examples/python/t_reconstruction_system/integrate.py +++ b/examples/python/t_reconstruction_system/integrate.py @@ -119,9 +119,7 @@ def integrate(depth_file_names, color_file_names, depth_intrinsic, config = parser.get_config() if config.path_dataset == '': - config.path_dataset = get_default_testdata() - config.path_trajectory = os.path.join(config.path_dataset, - 'trajectory.log') + config = get_default_testdata(config) if config.integrate_color: depth_file_names, color_file_names = load_rgbd_file_names(config) diff --git a/examples/python/t_reconstruction_system/integrate_custom.py b/examples/python/t_reconstruction_system/integrate_custom.py index ae154c96cf3..1eecbfd4bc9 100644 --- a/examples/python/t_reconstruction_system/integrate_custom.py +++ b/examples/python/t_reconstruction_system/integrate_custom.py @@ -37,7 +37,7 @@ import matplotlib.pyplot as plt from config import ConfigParser -from common import load_rgbd_file_names, load_depth_file_names, save_poses, load_intrinsic, load_extrinsics, get_default_testdata +from common import get_default_dataset, load_rgbd_file_names, load_depth_file_names, save_poses, load_intrinsic, load_extrinsics, extract_rgbd_frames from tqdm import tqdm @@ -170,6 +170,11 @@ def integrate(depth_file_names, color_file_names, intrinsic, extrinsics, help='YAML config file path. Please refer to default_config.yml as a ' 'reference. It overrides the default config file, but will be ' 'overridden by other command line inputs.') + parser.add('--default_dataset', + help='Default dataset is used when config file is not provided. ' + 'Default dataset may be selected from the following options: ' + '[lounge, jack_jack]', + default='lounge') parser.add('--integrate_color', action='store_true') parser.add('--path_trajectory', help='path to the trajectory .log or .json file.') @@ -179,9 +184,15 @@ def integrate(depth_file_names, color_file_names, intrinsic, extrinsics, config = parser.get_config() if config.path_dataset == '': - config.path_dataset = get_default_testdata() - config.path_trajectory = os.path.join(config.path_dataset, - 'trajectory.log') + config = get_default_dataset(config) + + # Extract RGB-D frames and intrinsic from bag file. + if config.path_dataset.endswith(".bag"): + assert os.path.isfile( + config.path_dataset), (f"File {config.path_dataset} not found.") + print("Extracting frames from RGBD video file") + config.path_dataset, config.path_intrinsic, config.depth_scale = extract_rgbd_frames( + config.path_dataset) if config.integrate_color: depth_file_names, color_file_names = load_rgbd_file_names(config) diff --git a/examples/python/t_reconstruction_system/ray_casting.py b/examples/python/t_reconstruction_system/ray_casting.py index cd4f5ec5da2..50e4c690a57 100644 --- a/examples/python/t_reconstruction_system/ray_casting.py +++ b/examples/python/t_reconstruction_system/ray_casting.py @@ -38,7 +38,7 @@ from tqdm import tqdm from config import ConfigParser -from common import load_depth_file_names, load_intrinsic, load_extrinsics, get_default_testdata +from common import load_depth_file_names, load_intrinsic, load_extrinsics, get_default_dataset, extract_rgbd_frames import matplotlib.pyplot as plt import numpy as np @@ -50,7 +50,11 @@ help='YAML config file path. Please refer to default_config.yml as a ' 'reference. It overrides the default config file, but will be ' 'overridden by other command line inputs.') - + parser.add('--default_dataset', + help='Default dataset is used when config file is not provided. ' + 'Default dataset may be selected from the following options: ' + '[lounge, jack_jack]', + default='lounge') parser.add('--path_trajectory', help='path to the trajectory .log or .json file.') parser.add('--path_npz', @@ -59,9 +63,15 @@ config = parser.get_config() if config.path_dataset == '': - config.path_dataset = get_default_testdata() - config.path_trajectory = os.path.join(config.path_dataset, - 'trajectory.log') + config = get_default_dataset(config) + + # Extract RGB-D frames and intrinsic from bag file. + if config.path_dataset.endswith(".bag"): + assert os.path.isfile( + config.path_dataset), (f"File {config.path_dataset} not found.") + print("Extracting frames from RGBD video file") + config.path_dataset, config.path_intrinsic, config.depth_scale = extract_rgbd_frames( + config.path_dataset) vbg = o3d.t.geometry.VoxelBlockGrid.load(config.path_npz) depth_file_names = load_depth_file_names(config)