diff --git a/examples/cpp/TICPOdometry.cpp b/examples/cpp/TICPOdometry.cpp index 32080a3e4d7..2c41ed07498 100644 --- a/examples/cpp/TICPOdometry.cpp +++ b/examples/cpp/TICPOdometry.cpp @@ -160,23 +160,23 @@ class ExampleWindow : public ReconstructionWindow { // Initialize visualizer. if (visualize_output_) { { - // lock to protect `pcd_.curren_scan_` before modifying + // lock to protect `curren_scan_` and `bbox_` before modifying // the value, ensuring the visualizer thread doesn't read the // data, while we are modifying it. - std::lock_guard lock(pcd_.lock_); + std::lock_guard lock(pcd_and_bbox_.lock_); - // Copying the pointcloud to pcd_.current_scan_ on the `main - // thread` on CPU, which is later passed to the visualizer for - // rendering. - pcd_.current_scan_ = pointclouds_device_[0].CPU(); + // Copying the pointcloud to pcd_and_bbox_.current_scan_ on the + // `main thread` on CPU, which is later passed to the visualizer + // for rendering. + pcd_and_bbox_.current_scan_ = pointclouds_device_[0].CPU(); // Removing `normal` attribute before passing it to // the visualizer might give us some performance benifits. - pcd_.current_scan_.RemovePointAttr("normals"); + pcd_and_bbox_.current_scan_.RemovePointAttr("normals"); } gui::Application::GetInstance().PostToMainThread(this, [&]() { - std::lock_guard lock(pcd_.lock_); + std::lock_guard lock(pcd_and_bbox_.lock_); // Setting background for the visualizer. [In this case: Black]. this->widget3d_->GetScene()->SetBackground({0, 0, 0, 1.0}); @@ -184,12 +184,14 @@ class ExampleWindow : public ReconstructionWindow { // Adding the first frame of the sequence to the visualizer, // and rendering it using the material set for `current scan`. this->widget3d_->GetScene()->AddGeometry( - filenames_[0], &pcd_.current_scan_, mat_); + filenames_[0], &pcd_and_bbox_.current_scan_, mat_); // Getting bounding box and center to setup camera view. - auto bbox = this->widget3d_->GetScene()->GetBoundingBox(); - auto center = bbox.GetCenter().cast(); - this->widget3d_->SetupCamera(verticalFoV, bbox, center); + pcd_and_bbox_.bbox_ = + this->widget3d_->GetScene()->GetBoundingBox(); + auto center = pcd_and_bbox_.bbox_.GetCenter().cast(); + this->widget3d_->SetupCamera(verticalFoV, pcd_and_bbox_.bbox_, + center); }); } // ------------------------------------------------------------------ @@ -263,26 +265,35 @@ class ExampleWindow : public ReconstructionWindow { std::stringstream out_; { - // lock `pcd_.current_scan_` before modifying the value, to - // protect the case, when visualizer is accessing it - // at the same time we are modifying it. - std::lock_guard lock(pcd_.lock_); + // lock `current_scan_` and `bbox_` before modifying the + // value, to protect the case, when visualizer is accessing + // it at the same time we are modifying it. + std::lock_guard lock(pcd_and_bbox_.lock_); // For visualization it is required that the pointcloud // must be on CPU device. // The `target` pointcloud is transformed to it's global // position in the model by it's `frame to model transform`. - pcd_.current_scan_ = + pcd_and_bbox_.current_scan_ = target.Transform(cumulative_transform.To(device_, dtype_)) .CPU(); + // Translate bounding box to current scan frame to model + // transform. + pcd_and_bbox_.bbox_ = pcd_and_bbox_.bbox_.Translate( + core::eigen_converter::TensorToEigenMatrixXd( + cumulative_transform.Clone() + .Slice(0, 0, 3) + .Slice(1, 3, 4)), + /*relative = */ false); + total_points_in_frame += - pcd_.current_scan_.GetPoints().GetLength(); + pcd_and_bbox_.current_scan_.GetPoints().GetLength(); // Removing `normal` attribute before passing it to // the visualizer might give us some performance benifits. - pcd_.current_scan_.RemovePointAttr("normals"); + pcd_and_bbox_.current_scan_.RemovePointAttr("normals"); } if (i != 0) { @@ -305,7 +316,8 @@ class ExampleWindow : public ReconstructionWindow { // so, we don't need to use locks for such cases. this->SetOutput(out_); - std::lock_guard lock(pcd_.lock_); + std::lock_guard lock( + pcd_and_bbox_.lock_); // We render the `source` or the previous // "current scan" pointcloud by using the material @@ -317,15 +329,14 @@ class ExampleWindow : public ReconstructionWindow { // a different material. In next iteration we will // change the material to the `model` material. this->widget3d_->GetScene()->AddGeometry( - filenames_[i + 1], &pcd_.current_scan_, - mat_); - - // Bounding box and camera setup. - auto bbox = this->widget3d_->GetScene() - ->GetBoundingBox(); - auto center = bbox.GetCenter().cast(); - this->widget3d_->SetupCamera(verticalFoV, bbox, - center); + filenames_[i + 1], + &pcd_and_bbox_.current_scan_, mat_); + + // Setup camera. + auto center = pcd_and_bbox_.bbox_.GetCenter() + .cast(); + this->widget3d_->SetupCamera( + verticalFoV, pcd_and_bbox_.bbox_, center); }); } // -------------------------------------------------------------- @@ -533,8 +544,6 @@ class ExampleWindow : public ReconstructionWindow { t::io::ReadPointCloud(path, pointcloud_local, {"auto", false, false, true}); - // Cpnverting attributes to Floar32 and currently only - // Float32 pointcloud is supported by the tensor // registration module. for (std::string attr : {"points", "colors", "normals"}) { if (pointcloud_local.HasPointAttr(attr)) { @@ -555,7 +564,7 @@ class ExampleWindow : public ReconstructionWindow { pointcloud_local.GetPoints() .Slice(0, 0, -1) .Slice(1, 2, 3) - .To(dtype_, true)); + .To(dtype_, false)); // Normals are required by `PointToPlane` registration method. // Currenly Normal Estimation is not supported by @@ -640,7 +649,7 @@ class ExampleWindow : public ReconstructionWindow { } private: - // lock to protect `pcd_.current_scan_` before modifying + // lock to protect `current_scan_` and `bbox_` before modifying // the value, ensuring the visualizer thread doesn't read the // data, while we are modifying it. struct { @@ -648,7 +657,10 @@ class ExampleWindow : public ReconstructionWindow { std::mutex lock_; // Pointcloud to store the "current scan", used for visualization. t::geometry::PointCloud current_scan_; - } pcd_; + // Bounding box. It is translated by the translation component of the + // cumulative transformation. + geometry::AxisAlignedBoundingBox bbox_; + } pcd_and_bbox_; // Checks if the GUI is closed, and if so, stop the code. std::atomic is_done_; diff --git a/examples/cpp/TICPReconstruction.cpp b/examples/cpp/TICPReconstruction.cpp index fbb002cdaa6..3dd30864ded 100644 --- a/examples/cpp/TICPReconstruction.cpp +++ b/examples/cpp/TICPReconstruction.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,7 +43,7 @@ using namespace open3d::t::pipelines::registration; float verticalFoV = 25; const Eigen::Vector3f CENTER_OFFSET(-10.0f, 0.0f, 30.0f); -// const Eigen::Vector3f CENTER_OFFSET(0.5f, -0.5f, -5.0f); + const std::string CLOUD_NAME = "points"; const std::string SRC_CLOUD = "source_pointcloud"; @@ -54,28 +56,72 @@ std::vector initial_transform_flat = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; -class ReconstructionWindow : public gui::Window { - using Super = gui::Window; +//------------------------------------------------------------------------------ +class PropertyPanel : public gui::VGrid { + using Super = gui::VGrid; public: - ReconstructionWindow() : gui::Window("Open3D - Reconstruction", 1600, 900) { - widget3d_ = std::make_shared(); - AddChild(widget3d_); - widget3d_->SetScene( - std::make_shared(GetRenderer())); + PropertyPanel(int spacing, int left_margin) + : gui::VGrid(2, spacing, gui::Margins(left_margin, 0, 0, 0)) { + default_label_color_ = + std::make_shared("temp")->GetTextColor(); } - ~ReconstructionWindow() {} + void AddIntSlider(const std::string& name, + std::atomic* num_addr, + int default_val, + int min_val, + int max_val, + const std::string& tooltip = "") { + auto s = std::make_shared(gui::Slider::INT); + s->SetLimits(min_val, max_val); + s->SetValue(default_val); + *num_addr = default_val; + s->SetOnValueChanged([num_addr, this](int new_val) { + *num_addr = new_val; + this->NotifyChanged(); + }); + auto label = std::make_shared(name.c_str()); + label->SetTooltip(tooltip.c_str()); + AddChild(label); + AddChild(s); + } -protected: - std::shared_ptr widget3d_; + void SetEnabled(bool enable) override { + Super::SetEnabled(enable); + for (auto child : GetChildren()) { + child->SetEnabled(enable); + auto label = std::dynamic_pointer_cast(child); + if (label) { + if (enable) { + label->SetTextColor(default_label_color_); + } else { + label->SetTextColor(gui::Color(0.5f, 0.5f, 0.5f, 1.0f)); + } + } + } + } + +private: + gui::Color default_label_color_; + std::function on_changed_; + + void NotifyChanged() { + if (on_changed_) { + on_changed_(); + } + } }; //------------------------------------------------------------------------------ -class ExampleWindow : public ReconstructionWindow { +class ReconstructionWindow : public gui::Window { + using Super = gui::Window; + public: - ExampleWindow(const std::string& path_config, const core::Device& device) - : device_(device), + ReconstructionWindow(const std::string& path_config, + const core::Device& device) + : gui::Window("Open3D - Reconstruction", 1280, 800), + device_(device), host_(core::Device("CPU:0")), dtype_(core::Dtype::Float32) { ReadConfigFile(path_config); @@ -84,17 +130,6 @@ class ExampleWindow : public ReconstructionWindow { transformation_ = core::Tensor(initial_transform_flat, {4, 4}, core::Dtype::Float64, host_); - // Warm Up. - std::vector warm_up_criteria = { - ICPConvergenceCriteria(0.01, 0.01, 1)}; - result_ = RegistrationMultiScaleICP( - source_.To(device_), target_.To(device_), {1.0}, - warm_up_criteria, {1.5}, - core::Tensor::Eye(4, core::Dtype::Float64, host_), - *estimation_); - - std::cout << " [Debug] Warm up transformation: " - << result_.transformation_.ToString() << std::endl; is_done_ = false; // --------------------- VISUALIZER --------------------- @@ -102,21 +137,19 @@ class ExampleWindow : public ReconstructionWindow { src_cloud_mat_ = rendering::Material(); src_cloud_mat_.shader = "defaultUnlit"; - // src_cloud_mat_.base_color = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f); tar_cloud_mat_ = rendering::Material(); tar_cloud_mat_.shader = "defaultUnlit"; - // tar_cloud_mat_.base_color = Eigen::Vector4f(0.7f, 0.7f, 0.7f, 1.0f); src_corres_mat_ = rendering::Material(); src_corres_mat_.shader = "defaultUnlit"; src_corres_mat_.base_color = Eigen::Vector4f(0.f, 1.0f, 0.0f, 1.0f); - src_corres_mat_.point_size = 3.0f; + src_corres_mat_.point_size = 4.0f; tar_corres_mat_ = rendering::Material(); tar_corres_mat_.shader = "defaultUnlit"; tar_corres_mat_.base_color = Eigen::Vector4f(1.f, 0.0f, 0.0f, 1.0f); - tar_corres_mat_.point_size = 3.0f; + tar_corres_mat_.point_size = 4.0f; // ------------------------------------------------------ SetOnClose([this]() { @@ -124,65 +157,154 @@ class ExampleWindow : public ReconstructionWindow { return true; // false would cancel the close }); update_thread_ = std::thread([this]() { this->UpdateMain(); }); - } - ~ExampleWindow() { update_thread_.join(); } + auto& theme = GetTheme(); + int em = theme.font_size; + int left_margin = em; + int vspacing = int(std::round(1.0f * float(em))); + int spacing = int(std::round(0.5f * float(em))); + gui::Margins margins(int(std::round(0.5f * float(em)))); -private: - std::thread update_thread_; + widget3d_ = std::make_shared(); + AddChild(widget3d_); - void UpdateMain() { - core::Tensor initial_transform = core::Tensor::Eye( - 4, core::Dtype::Float64, core::Device("CPU:0")); - core::Tensor cumulative_transform = initial_transform.Clone(); - - // ------------------------ VISUALIZER ------------------------------ - // Intialize visualizer. - { - // lock to protect `source_` and `target_` before modifying the - // value, ensuring the visualizer thread doesn't read the data, - // while we are modifying it. - std::lock_guard lock(pcd_.lock_); + panel_ = std::make_shared(spacing, margins); + AddChild(panel_); - // Copying the pointcloud on CPU, as required by the visualizer. - pcd_.source_ = source_.CPU(); - pcd_.target_ = target_.CPU(); - } + auto b = std::make_shared(" Resume/Pause"); + b->SetOnClicked([b, this](bool is_on) { + if (!this->is_started_) { + // ----------------- VISUALIZER ----------------- + // Intialize visualizer. + { + // lock to protect `source_` and `target_` + // before modifying the value, ensuring the + // visualizer thread doesn't read the data, + // while we are modifying it. + std::lock_guard lock(pcd_.lock_); - gui::Application::GetInstance().PostToMainThread(this, [this]() { - // lock to protect `pcd_.source_` and `pcd.target_` - // before passing it to the visualizer, ensuring we don't - // modify the value, when visualizer is reading it. - std::lock_guard lock(pcd_.lock_); + // Copying the pointcloud on CPU, as required by + // the visualizer. + pcd_.source_ = source_.CPU(); + pcd_.target_ = target_.CPU(); + } - // Setting the background. - this->widget3d_->GetScene()->SetBackground({0, 0, 0, 1}); - - // Adding the target pointcloud. - this->widget3d_->GetScene()->AddGeometry(DST_CLOUD, &pcd_.target_, - tar_cloud_mat_); - - // Adding the source pointcloud, and correspondences pointclouds. - // This works as a pointcloud container, i.e. reserves the - // resources. Later we will just use `UpdateGeometry` which is - // efficient when the number of points in the updated pointcloud - // are same or less than the geometry added initially. - this->widget3d_->GetScene()->GetScene()->AddGeometry( - SRC_CLOUD, pcd_.source_, src_cloud_mat_); - this->widget3d_->GetScene()->GetScene()->AddGeometry( - SRC_CORRES, pcd_.source_, src_corres_mat_); - this->widget3d_->GetScene()->GetScene()->AddGeometry( - TAR_CORRES, pcd_.source_, tar_corres_mat_); - - // Getting bounding box and center to setup camera view. - auto bbox = this->widget3d_->GetScene()->GetBoundingBox(); - auto center = bbox.GetCenter().cast(); - this->widget3d_->SetupCamera(18, bbox, center); - this->widget3d_->LookAt(center, center - Eigen::Vector3f{-10, 5, 8}, + gui::Application::GetInstance().PostToMainThread( + this, [this]() { + // lock to protect `pcd_.source_` and + // `pcd.target_` before passing it to + // the visualizer, ensuring we don't + // modify the value, when visualizer is + // reading it. + std::lock_guard lock(pcd_.lock_); + + // Setting the background. + this->widget3d_->GetScene()->SetBackground( + {0, 0, 0, 1}); + + // Adding the target pointcloud. + this->widget3d_->GetScene()->AddGeometry( + DST_CLOUD, &pcd_.target_, tar_cloud_mat_); + + // Adding the source pointcloud, and + // correspondences pointclouds. This + // works as a pointcloud container, i.e. + // reserves the resources. Later we will + // just use `UpdateGeometry` which is + // efficient when the number of points + // in the updated pointcloud are same or + // less than the geometry added + // initially. + this->widget3d_->GetScene() + ->GetScene() + ->AddGeometry(SRC_CLOUD, pcd_.source_, + src_cloud_mat_); + this->widget3d_->GetScene() + ->GetScene() + ->AddGeometry(SRC_CORRES, pcd_.source_, + src_corres_mat_); + this->widget3d_->GetScene() + ->GetScene() + ->AddGeometry(TAR_CORRES, pcd_.target_, + tar_corres_mat_); + + // Getting bounding box and center to + // setup camera view. + auto bbox = this->widget3d_->GetScene() + ->GetBoundingBox(); + auto center = bbox.GetCenter().cast(); + this->widget3d_->SetupCamera(18, bbox, center); + this->widget3d_->LookAt( + center, center - Eigen::Vector3f{-10, 5, 8}, {0.0f, -1.0f, 0.0f}); + }); + // ----------------------------------------------------- + + this->is_started_ = true; + } + this->is_running_ = !(this->is_running_); + this->adjustable_props_->SetEnabled(true); }); - // ----------------------------------------------------- + panel_->AddChild(b); + panel_->AddFixed(vspacing); + + adjustable_props_ = + std::make_shared(spacing, left_margin); + adjustable_props_->AddIntSlider( + "Animation Delay (ms)", &delay_, 100, 100, 500, + "Animation interval between ICP iterations."); + panel_->AddChild(adjustable_props_); + panel_->AddFixed(vspacing); + + output_ = std::make_shared(""); + panel_->AddChild(std::make_shared("Output")); + panel_->AddChild(output_); + + widget3d_->SetScene( + std::make_shared(GetRenderer())); + } + + ~ReconstructionWindow() { update_thread_.join(); } + + void Layout(const gui::LayoutContext& context) override { + int em = context.theme.font_size; + int panel_width = 20 * em; + // int panel_height = 500; + // The usable part of the window may not be the full size if there + // is a menu. + auto content_rect = GetContentRect(); + + panel_->SetFrame(gui::Rect(content_rect.x, content_rect.y, panel_width, + content_rect.height)); + int x = panel_->GetFrame().GetRight(); + widget3d_->SetFrame(gui::Rect(x, content_rect.y, + content_rect.GetRight() - x, + content_rect.height)); + + Super::Layout(context); + } + +protected: + std::shared_ptr panel_; + std::shared_ptr output_; + std::shared_ptr widget3d_; + + std::shared_ptr adjustable_props_; + + std::atomic delay_; + + // General logic + std::atomic is_running_; + std::atomic is_started_; + std::atomic is_done_; + std::thread update_thread_; + + void SetOutput(const std::string& output) { + output_->SetText(output.c_str()); + } + + void UpdateMain() { // ----- Class members passed to function arguments // ----- in t::pipeline::registration::RegistrationMultiScaleICP const t::geometry::PointCloud source = source_.To(device_); @@ -220,8 +342,8 @@ class ExampleWindow : public ReconstructionWindow { criterias.size() == max_correspondence_distances.size())) { utility::LogError( " [RegistrationMultiScaleICP]: Size of criterias, " - "voxel_size," - " max_correspondence_distances vectors must be same."); + "voxel_size, max_correspondence_distances vectors " + "must be same."); } if ((estimation.GetTransformationEstimationType() == @@ -305,6 +427,12 @@ class ExampleWindow : public ReconstructionWindow { "{:.4f}", i + 1, j, result.fitness_, result.inlier_rmse_); + while (!is_started_ || !is_running_) { + // If we aren't running, sleep a little bit so that we don't + // use 100% of the CPU just checking if we need to run. + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + // ComputeTransformation returns transformation matrix of // dtype Float64. core::Tensor update = estimation.ComputeTransformation( @@ -341,20 +469,26 @@ class ExampleWindow : public ReconstructionWindow { {result.correspondence_set_.second}) .To(host_)); - pcd_.source_ = source_.Clone().Transform( - transformation.To(dtype_)); + pcd_.source_ = + source_.CPU().Transform(transformation.To(dtype_)); } + std::stringstream out_; + out_ << " RMSE: " << std::setprecision(4) << result.inlier_rmse_ + << std::endl; + // To update visualizer, we go to the `main thread`, // bring the data on the `main thread`, ensure there is no race // condition with the data, and pass it to the visualizer for // rendering, using `AddGeometry`, or update an existing // pointcloud using `UpdateGeometry`, then setup camera. gui::Application::GetInstance().PostToMainThread( - this, [this]() { + this, [this, i, out_ = out_.str()]() { + this->SetOutput(out_); + // Locking to protect: pcd_.source_, // pcd_.correspondence_src_, pcd_correpondece_tar_. - std::lock_guard lock(pcd_lock_); + std::lock_guard lock(pcd_.lock_); this->widget3d_->GetScene() ->GetScene() @@ -396,7 +530,8 @@ class ExampleWindow : public ReconstructionWindow { // Delays each iteration to allow clear visualization of // each iteration. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds( + ReconstructionWindow::delay_)); } } // ------------------ VISUALIZER ---------------------------- @@ -546,16 +681,64 @@ class ExampleWindow : public ReconstructionWindow { t::io::ReadPointCloud(path_target_, target, {"auto", false, false, true}); - // Cpnverting attributes to Floar32 and currently only + // First perform device transfer, as all attributes must be on same + // device. + source = source.To(device_, false); + target = target.To(device_, false); + + // Converting point and normals attributes to Floar32 and currently only // Float32 pointcloud is supported by the tensor registration module. - for (std::string attr : {"points", "colors", "normals"}) { - if (source.HasPointAttr(attr)) { - source.SetPointAttr(attr, source.GetPointAttr(attr).To(dtype_)); + source.SetPoints(source.GetPoints().To(dtype_)); + if (source.HasPointNormals()) { + source.SetPointNormals(source.GetPointNormals().To(dtype_)); + } + // Converting attributes to Floar32 and currently only + // Float32 pointcloud is supported by the tensor registration module. + target.SetPoints(target.GetPoints().To(dtype_)); + if (target.HasPointNormals()) { + target.SetPointNormals(target.GetPointNormals().To(dtype_)); + } + + // Color may be of Float32, Float64, UInt8, UInt16. + if (source.HasPointColors()) { + // UInt8 scale is [0, 255], while Float scale is [0.0, 1.0]. + if (source.GetPointColors().GetDtype() == core::Dtype::UInt8) { + source.SetPointColors(source.GetPointColors().To(dtype_).Div( + static_cast( + std::numeric_limits::max()))); + } else if (source.GetPointColors().GetDtype() == + core::Dtype::UInt16) { + source.SetPointColors(source.GetPointColors().To(dtype_).Div( + static_cast( + std::numeric_limits::max()))); + } else if (source.GetPointColors().GetDtype() == + core::Dtype::Float64) { + source.SetPointColors(source.GetPointColors().To(dtype_)); + } else if (source.GetPointColors().GetDtype() != + core::Dtype::Float32) { + utility::LogError( + " Unsupported dtype for color attribute. Supported " + "dtypes include Float32, Float64, UInt8 and UInt16."); } } - for (std::string attr : {"points", "colors", "normals"}) { - if (target.HasPointAttr(attr)) { - target.SetPointAttr(attr, target.GetPointAttr(attr).To(dtype_)); + if (target.HasPointColors()) { + if (target.GetPointColors().GetDtype() == core::Dtype::UInt8) { + target.SetPointColors(target.GetPointColors().To(dtype_).Div( + static_cast( + std::numeric_limits::max()))); + } else if (target.GetPointColors().GetDtype() == + core::Dtype::UInt16) { + target.SetPointColors(target.GetPointColors().To(dtype_).Div( + static_cast( + std::numeric_limits::max()))); + } else if (target.GetPointColors().GetDtype() == + core::Dtype::Float64) { + target.SetPointColors(target.GetPointColors().To(dtype_)); + } else if (target.GetPointColors().GetDtype() != + core::Dtype::Float32) { + utility::LogError( + " Unsupported dtype for color attribute. Supported " + "dtypes include Float32, Float64, UInt8 and UInt16."); } } @@ -569,7 +752,7 @@ class ExampleWindow : public ReconstructionWindow { core::Tensor target_normals = t::geometry::PointCloud::FromLegacyPointCloud(target_legacy) .GetPointNormals() - .To(dtype_); + .To(device_, dtype_); target.SetPointNormals(target_normals); } @@ -649,9 +832,6 @@ class ExampleWindow : public ReconstructionWindow { core::Dtype dtype_; private: - std::mutex pcd_lock_; - - std::atomic is_done_; open3d::visualization::rendering::Material src_cloud_mat_; open3d::visualization::rendering::Material tar_cloud_mat_; open3d::visualization::rendering::Material src_corres_mat_; @@ -716,9 +896,11 @@ int main(int argc, char* argv[]) { utility::SetVerbosityLevel(utility::VerbosityLevel::Debug); auto& app = gui::Application::GetInstance(); + app.Initialize(argc, (const char**)argv); - app.AddWindow(std::make_shared(path_config, - core::Device(argv[1]))); + app.AddWindow(std::make_shared( + path_config, core::Device(argv[1]))); + app.Run(); return 0; } diff --git a/examples/cpp/registration_example_util/TICPOdomConfigKitti.txt b/examples/cpp/registration_example_util/TICPOdomConfigKitti.txt index 88009d7f1de..bbe00420ff0 100644 --- a/examples/cpp/registration_example_util/TICPOdomConfigKitti.txt +++ b/examples/cpp/registration_example_util/TICPOdomConfigKitti.txt @@ -24,7 +24,7 @@ dataset_path = ../../../examples/test_data/open3d_downloads/datasets/kitti_sampl # Range of frames is start_index to end_index. start_index = 0 -end_index = 400 +end_index = 1000 # Registration method can be PointToPoint or PointToPlane. registration_method = PointToPlane diff --git a/examples/cpp/registration_example_util/TICPOdomConfigLyft.txt b/examples/cpp/registration_example_util/TICPOdomConfigLyft.txt index acfeb5351a1..979c9610f83 100644 --- a/examples/cpp/registration_example_util/TICPOdomConfigLyft.txt +++ b/examples/cpp/registration_example_util/TICPOdomConfigLyft.txt @@ -21,7 +21,7 @@ dataset_path = ../../../examples/test_data/open3d_downloads/datasets/lyft_sample # Range of frames is start_index to end_index. start_index = 0 -end_index = 400 +end_index = 500 # Registration method can be PointToPoint or PointToPlane. registration_method = PointToPlane diff --git a/examples/cpp/registration_example_util/download_kitti.py b/examples/cpp/registration_example_util/download_kitti.py index cfb950a5ea1..dd7699b1463 100644 --- a/examples/cpp/registration_example_util/download_kitti.py +++ b/examples/cpp/registration_example_util/download_kitti.py @@ -54,17 +54,33 @@ def bin_to_pcd(binFileName): # preprocess and save in .ply format. -def preprocess_and_save(source_folder, destination_folder, voxel_size=0.02): +def preprocess_and_save(source_folder, + destination_folder, + voxel_size=0.05, + start_idx=0, + end_idx=1000): # get all files from the folder, and sort by name. filenames = get_file_list(source_folder, ".bin") - print("Converting .bin to .ply files and pre-processing.") + print( + "Converting .bin to .ply files and pre-processing from frame {} to index {}" + .format(start_idx, end_idx)) + + if (end_idx < start_idx): + raise RuntimeError("End index must be smaller than start index.") + if (end_idx > len(filenames)): + end_idx = len(filenames) + print( + "WARNING: End index is greater than total file length, taking file length as end index." + ) + + filenames = filenames[start_idx:end_idx] for path in filenames: # convert kitti bin format to pcd format. pcd = bin_to_pcd(path) # downsample and estimate normals. - voxel_down_pcd = pcd.voxel_down_sample(voxel_size=0.02) + voxel_down_pcd = pcd.voxel_down_sample(voxel_size=0.05) voxel_down_pcd.estimate_normals( search_param=o3d.geometry.KDTreeSearchParamKNN(), fast_normal_computation=False) @@ -134,8 +150,8 @@ def get_kitti_sample_dataset(dataset_path, dataset_name): print("") else: print( - "The folder: %s, already exists. To re-download, kindly delete the folder and re-run this script." - % path) + "The folder: {}, already exists. To re-download, kindly delete the folder and re-run this script." + .format(path)) def find_source_pcd_folder_path(dataset_name): @@ -148,58 +164,8 @@ def find_source_pcd_folder_path(dataset_name): valid_dataset_list = [ - "2011_09_26_drive_0001", "2011_09_26_drive_0002", "2011_09_26_drive_0005", - "2011_09_26_drive_0009", "2011_09_26_drive_0011", "2011_09_26_drive_0013", - "2011_09_26_drive_0014", "2011_09_26_drive_0015", "2011_09_26_drive_0017", - "2011_09_26_drive_0018", "2011_09_26_drive_0019", "2011_09_26_drive_0020", - "2011_09_26_drive_0022", "2011_09_26_drive_0023", "2011_09_26_drive_0027", - "2011_09_26_drive_0028", "2011_09_26_drive_0029", "2011_09_26_drive_0032", - "2011_09_26_drive_0035", "2011_09_26_drive_0036", "2011_09_26_drive_0039", - "2011_09_26_drive_0046", "2011_09_26_drive_0048", "2011_09_26_drive_0051", - "2011_09_26_drive_0052", "2011_09_26_drive_0056", "2011_09_26_drive_0057", - "2011_09_26_drive_0059", "2011_09_26_drive_0060", "2011_09_26_drive_0061", - "2011_09_26_drive_0064", "2011_09_26_drive_0070", "2011_09_26_drive_0079", - "2011_09_26_drive_0084", "2011_09_26_drive_0086", "2011_09_26_drive_0087", - "2011_09_26_drive_0091", "2011_09_26_drive_0093", "2011_09_26_drive_0095", - "2011_09_26_drive_0096", "2011_09_26_drive_0101", "2011_09_26_drive_0104", - "2011_09_26_drive_0106", "2011_09_26_drive_0113", "2011_09_26_drive_0117", - "2011_09_26_drive_0119", "2011_09_28_drive_0001", "2011_09_28_drive_0002", - "2011_09_28_drive_0016", "2011_09_28_drive_0021", "2011_09_28_drive_0034", - "2011_09_28_drive_0035", "2011_09_28_drive_0037", "2011_09_28_drive_0038", - "2011_09_28_drive_0039", "2011_09_28_drive_0043", "2011_09_28_drive_0045", - "2011_09_28_drive_0047", "2011_09_28_drive_0053", "2011_09_28_drive_0054", - "2011_09_28_drive_0057", "2011_09_28_drive_0065", "2011_09_28_drive_0066", - "2011_09_28_drive_0068", "2011_09_28_drive_0070", "2011_09_28_drive_0071", - "2011_09_28_drive_0075", "2011_09_28_drive_0077", "2011_09_28_drive_0078", - "2011_09_28_drive_0080", "2011_09_28_drive_0082", "2011_09_28_drive_0086", - "2011_09_28_drive_0087", "2011_09_28_drive_0089", "2011_09_28_drive_0090", - "2011_09_28_drive_0094", "2011_09_28_drive_0095", "2011_09_28_drive_0096", - "2011_09_28_drive_0098", "2011_09_28_drive_0100", "2011_09_28_drive_0102", - "2011_09_28_drive_0103", "2011_09_28_drive_0104", "2011_09_28_drive_0106", - "2011_09_28_drive_0108", "2011_09_28_drive_0110", "2011_09_28_drive_0113", - "2011_09_28_drive_0117", "2011_09_28_drive_0119", "2011_09_28_drive_0121", - "2011_09_28_drive_0122", "2011_09_28_drive_0125", "2011_09_28_drive_0126", - "2011_09_28_drive_0128", "2011_09_28_drive_0132", "2011_09_28_drive_0134", - "2011_09_28_drive_0135", "2011_09_28_drive_0136", "2011_09_28_drive_0138", - "2011_09_28_drive_0141", "2011_09_28_drive_0143", "2011_09_28_drive_0145", - "2011_09_28_drive_0146", "2011_09_28_drive_0149", "2011_09_28_drive_0153", - "2011_09_28_drive_0154", "2011_09_28_drive_0155", "2011_09_28_drive_0156", - "2011_09_28_drive_0160", "2011_09_28_drive_0161", "2011_09_28_drive_0162", - "2011_09_28_drive_0165", "2011_09_28_drive_0166", "2011_09_28_drive_0167", - "2011_09_28_drive_0168", "2011_09_28_drive_0171", "2011_09_28_drive_0174", - "2011_09_28_drive_0177", "2011_09_28_drive_0179", "2011_09_28_drive_0183", - "2011_09_28_drive_0184", "2011_09_28_drive_0185", "2011_09_28_drive_0186", - "2011_09_28_drive_0187", "2011_09_28_drive_0191", "2011_09_28_drive_0192", - "2011_09_28_drive_0195", "2011_09_28_drive_0198", "2011_09_28_drive_0199", - "2011_09_28_drive_0201", "2011_09_28_drive_0204", "2011_09_28_drive_0205", - "2011_09_28_drive_0208", "2011_09_28_drive_0209", "2011_09_28_drive_0214", - "2011_09_28_drive_0216", "2011_09_28_drive_0220", "2011_09_28_drive_0222", - "2011_09_28_drive_0225", "2011_09_29_drive_0004", "2011_09_29_drive_0026", - "2011_09_29_drive_0071", "2011_09_29_drive_0108", "2011_09_30_drive_0016", - "2011_09_30_drive_0018", "2011_09_30_drive_0020", "2011_09_30_drive_0027", - "2011_09_30_drive_0028", "2011_09_30_drive_0033", "2011_09_30_drive_0034", - "2011_09_30_drive_0072", "2011_10_03_drive_0027", "2011_10_03_drive_0034", - "2011_10_03_drive_0042", "2011_10_03_drive_0047", "2011_10_03_drive_0058" + "2011_09_26_drive_0009", "2011_09_30_drive_0018", "2011_09_30_drive_0027", + "2011_09_30_drive_0028", "2011_10_03_drive_0027", "2011_10_03_drive_0034" ] if __name__ == '__main__': @@ -207,11 +173,23 @@ def find_source_pcd_folder_path(dataset_name): parser.add_argument( '--dataset_name', type=str, - default="2011_09_26_drive_0009", + default="2011_09_30_drive_0028", help='Kitti city sequence name [Example: "2011_09_26_drive_0009"].') parser.add_argument('--print_available_datasets', action='store_true', help='visualize ray casting every 100 frames') + parser.add_argument('--voxel_size', + type=float, + default=0.05, + help='voxel size of the pointcloud.') + parser.add_argument('--start_index', + type=int, + default=0, + help='start index of the dataset frame.') + parser.add_argument('--end_index', + type=int, + default=1000, + help='maximum end index of the dataset frame.') args = parser.parse_args() @@ -243,7 +221,8 @@ def find_source_pcd_folder_path(dataset_name): print("Source raw kitti lidar data: ", source_folder) # convert bin to pcd, pre-process and save. - preprocess_and_save(source_folder, destination_path, 0.02) + preprocess_and_save(source_folder, destination_path, args.voxel_size, + args.start_index, args.end_index) print("Data fetching completed. Output pointcloud frames: ", destination_path)