diff --git a/cpp/open3d/geometry/PointCloud.cpp b/cpp/open3d/geometry/PointCloud.cpp index 3e55bc3acd6..b0b6e0130ae 100644 --- a/cpp/open3d/geometry/PointCloud.cpp +++ b/cpp/open3d/geometry/PointCloud.cpp @@ -541,23 +541,25 @@ std::shared_ptr PointCloud::FarthestPointDownSample( return SelectByIndex(selected_indices); } -std::shared_ptr PointCloud::Crop( - const AxisAlignedBoundingBox &bbox) const { +std::shared_ptr PointCloud::Crop(const AxisAlignedBoundingBox &bbox, + bool invert) const { if (bbox.IsEmpty()) { utility::LogError( "AxisAlignedBoundingBox either has zeros size, or has wrong " "bounds."); } - return SelectByIndex(bbox.GetPointIndicesWithinBoundingBox(points_)); + return SelectByIndex(bbox.GetPointIndicesWithinBoundingBox(points_), + invert); } -std::shared_ptr PointCloud::Crop( - const OrientedBoundingBox &bbox) const { +std::shared_ptr PointCloud::Crop(const OrientedBoundingBox &bbox, + bool invert) const { if (bbox.IsEmpty()) { utility::LogError( "AxisAlignedBoundingBox either has zeros size, or has wrong " "bounds."); } - return SelectByIndex(bbox.GetPointIndicesWithinBoundingBox(points_)); + return SelectByIndex(bbox.GetPointIndicesWithinBoundingBox(points_), + invert); } std::tuple, std::vector> diff --git a/cpp/open3d/geometry/PointCloud.h b/cpp/open3d/geometry/PointCloud.h index b55840106b6..334bdc9f0f5 100644 --- a/cpp/open3d/geometry/PointCloud.h +++ b/cpp/open3d/geometry/PointCloud.h @@ -185,7 +185,9 @@ class PointCloud : public Geometry3D { /// clipped. /// /// \param bbox AxisAlignedBoundingBox to crop points. - std::shared_ptr Crop(const AxisAlignedBoundingBox &bbox) const; + /// \param invert Optional boolean to invert cropping. + std::shared_ptr Crop(const AxisAlignedBoundingBox &bbox, + bool invert = false) const; /// \brief Function to crop pointcloud into output pointcloud /// @@ -193,7 +195,9 @@ class PointCloud : public Geometry3D { /// clipped. /// /// \param bbox OrientedBoundingBox to crop points. - std::shared_ptr Crop(const OrientedBoundingBox &bbox) const; + /// \param invert Optional boolean to invert cropping. + std::shared_ptr Crop(const OrientedBoundingBox &bbox, + bool invert = false) const; /// \brief Function to remove points that have less than \p nb_points in a /// sphere of a given radius. diff --git a/cpp/pybind/geometry/pointcloud.cpp b/cpp/pybind/geometry/pointcloud.cpp index d9e2ce935c6..835ec3123b1 100644 --- a/cpp/pybind/geometry/pointcloud.cpp +++ b/cpp/pybind/geometry/pointcloud.cpp @@ -86,16 +86,16 @@ void pybind_pointcloud(py::module &m) { "num_samples"_a) .def("crop", (std::shared_ptr(PointCloud::*)( - const AxisAlignedBoundingBox &) const) & + const AxisAlignedBoundingBox &, bool) const) & PointCloud::Crop, "Function to crop input pointcloud into output pointcloud", - "bounding_box"_a) + "bounding_box"_a, "invert"_a = false) .def("crop", (std::shared_ptr(PointCloud::*)( - const OrientedBoundingBox &) const) & + const OrientedBoundingBox &, bool) const) & PointCloud::Crop, "Function to crop input pointcloud into output pointcloud", - "bounding_box"_a) + "bounding_box"_a, "invert"_a = false) .def("remove_non_finite_points", &PointCloud::RemoveNonFinitePoints, "Removes all points from the point cloud that have a nan " "entry, or infinite entries. It also removes the " @@ -289,7 +289,8 @@ camera. Given depth value d at (u, v) image coordinate, the corresponding 3d poi "number of points[0-1]"}}); docstring::ClassMethodDocInject( m, "PointCloud", "crop", - {{"bounding_box", "AxisAlignedBoundingBox to crop points"}}); + {{"bounding_box", "AxisAlignedBoundingBox to crop points"}, + {"invert", "optional boolean to invert cropping"}}); docstring::ClassMethodDocInject( m, "PointCloud", "remove_non_finite_points", {{"remove_nan", "Remove NaN values from the PointCloud"}, diff --git a/cpp/tests/geometry/PointCloud.cpp b/cpp/tests/geometry/PointCloud.cpp index 379b8ad0941..21bfe5659bf 100644 --- a/cpp/tests/geometry/PointCloud.cpp +++ b/cpp/tests/geometry/PointCloud.cpp @@ -982,6 +982,38 @@ TEST(PointCloud, Crop_OrientedBoundingBox) { })); } +TEST(PointCloud, Crop_AxisAlignedBoundingBox_Invert) { + geometry::AxisAlignedBoundingBox aabb({0, 0, 0}, {2, 2, 2}); + geometry::PointCloud pcd({{0, 0, 0}, + {2, 2, 2}, + {1, 1, 1}, + {1, 1, 2}, + {3, 1, 1}, + {-1, 1, 1}}); + pcd.normals_ = {{0, 0, 0}, {1, 0, 0}, {2, 0, 0}, + {3, 0, 0}, {4, 0, 0}, {5, 0, 0}}; + pcd.colors_ = {{0.0, 0.0, 0.0}, {0.1, 0.0, 0.0}, {0.2, 0.0, 0.0}, + {0.3, 0.0, 0.0}, {0.4, 0.0, 0.0}, {0.5, 0.0, 0.0}}; + pcd.covariances_ = { + 0.0 * Eigen::Matrix3d::Identity(), + 1.0 * Eigen::Matrix3d::Identity(), + 2.0 * Eigen::Matrix3d::Identity(), + 3.0 * Eigen::Matrix3d::Identity(), + 4.0 * Eigen::Matrix3d::Identity(), + 5.0 * Eigen::Matrix3d::Identity(), + }; + std::shared_ptr pc_crop = pcd.Crop(aabb, true); + ExpectEQ(pc_crop->points_, + std::vector({{3, 1, 1}, {-1, 1, 1}})); + ExpectEQ(pc_crop->normals_, + std::vector({{4, 0, 0}, {5, 0, 0}})); + ExpectEQ(pc_crop->colors_, + std::vector({{0.4, 0.0, 0.0}, {0.5, 0.0, 0.0}})); + ExpectEQ(pc_crop->covariances_, + std::vector({4.0 * Eigen::Matrix3d::Identity(), + 5.0 * Eigen::Matrix3d::Identity()})); +} + TEST(PointCloud, EstimateNormals) { geometry::PointCloud pcd({ {0, 0, 0},