Skip to content

Commit

Permalink
add ransac registration
Browse files Browse the repository at this point in the history
  • Loading branch information
neka-nat committed Mar 16, 2024
1 parent caa0955 commit dafcdaa
Show file tree
Hide file tree
Showing 16 changed files with 865 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
id: cuda-toolkit
with:
cuda: '11.7.0'
use-github-cache: false
use-local-cache: false
- name: Install dependencies
run: |
./scripts/actions/install_deps_ubuntu.sh
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
id: cuda-toolkit
with:
cuda: '11.7.0'
use-github-cache: false
- name: nvcc check
shell: powershell
run: |
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ elseif (UNIX)
message(STATUS "Compiling on Unix")
endif ()

find_package(OpenMP)
if(OpenMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
find_package(CUDA REQUIRED)
if(NOT CMAKE_CUDA_ARCHITECTURES)
set(CMAKE_CUDA_ARCHITECTURES 86)
Expand Down
8 changes: 8 additions & 0 deletions src/cupoch/geometry/pointcloud.cu
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ PointCloud &PointCloud::Transform(const Eigen::Matrix4f &transformation) {
return *this;
}

PointCloud &PointCloud::Transform(cudaStream_t stream1, cudaStream_t stream2,
const Eigen::Matrix4f &transformation) {
TransformPoints<3>(stream1, transformation, points_);
TransformNormals(stream2, transformation, normals_);
cudaSafeCall(cudaDeviceSynchronize());
return *this;
}

std::shared_ptr<PointCloud> PointCloud::Crop(
const AxisAlignedBoundingBox<3> &bbox) const {
if (bbox.IsEmpty()) {
Expand Down
2 changes: 2 additions & 0 deletions src/cupoch/geometry/pointcloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class PointCloud : public GeometryBase3D {
AxisAlignedBoundingBox<3> GetAxisAlignedBoundingBox() const override;
OrientedBoundingBox GetOrientedBoundingBox() const;
PointCloud &Transform(const Eigen::Matrix4f &transformation) override;
PointCloud &Transform(cudaStream_t stream1, cudaStream_t stream2,
const Eigen::Matrix4f &transformation);
PointCloud &Translate(const Eigen::Vector3f &translation,
bool relative = true) override;
PointCloud &Scale(const float scale, bool center = true) override;
Expand Down
4 changes: 3 additions & 1 deletion src/cupoch/registration/colored_icp.cu
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public:
const geometry::PointCloud &target,
const CorrespondenceSet &corres) const override;
Eigen::Matrix4f ComputeTransformation(
cudaStream_t stream1, cudaStream_t stream2,
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres) const override;
Expand Down Expand Up @@ -216,6 +217,7 @@ struct compute_jacobian_and_residual_functor
};

Eigen::Matrix4f TransformationEstimationForColoredICP::ComputeTransformation(
cudaStream_t stream1, cudaStream_t stream2,
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres) const {
Expand Down Expand Up @@ -244,7 +246,7 @@ Eigen::Matrix4f TransformationEstimationForColoredICP::ComputeTransformation(
thrust::tie(JTJ, JTr, r2) =
utility::ComputeJTJandJTr<Eigen::Matrix6f, Eigen::Vector6f, 2,
compute_jacobian_and_residual_functor>(
func, (int)corres.size());
stream1, func, (int)corres.size());

bool is_success;
Eigen::Matrix4f extrinsic;
Expand Down
171 changes: 171 additions & 0 deletions src/cupoch/registration/correspondence_checker.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* Copyright (c) 2024 Neka-Nat
* 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.
**/
#include "cupoch/registration/correspondence_checker.h"

#include <Eigen/Dense>
#include <thrust/logical.h>

#include "cupoch/geometry/pointcloud.h"
#include "cupoch/utility/console.h"

namespace cupoch {
namespace registration {

namespace {
struct edge_length_checker_functor {
float similarity_threshold_;
size_t corres_size_;
const Eigen::Vector3f* source_points_;
const Eigen::Vector3f* target_points_;
const Eigen::Vector2i* corres_;
edge_length_checker_functor(
float similarity_threshold,
size_t corres_size,
const Eigen::Vector3f* source_points,
const Eigen::Vector3f* target_points,
const Eigen::Vector2i* corres)
: similarity_threshold_(similarity_threshold),
corres_size_(corres_size),
source_points_(source_points),
target_points_(target_points),
corres_(corres) {}
__device__ bool operator()(int idx) {
int i = idx / corres_size_;
int j = idx % corres_size_;
if (i == j) return true;
float dis_source = (source_points_[corres_[i](0)] - source_points_[corres_[j](0)]).norm();
float dis_target = (target_points_[corres_[i](1)] - target_points_[corres_[j](1)]).norm();
return dis_source >= dis_target * similarity_threshold_ &&
dis_target >= dis_source * similarity_threshold_;
}

};

struct distance_checker_functor {
float distance_threshold_;
const Eigen::Vector3f* source_points_;
const Eigen::Vector3f* target_points_;
const Eigen::Matrix4f transformation_;
distance_checker_functor(
float distance_threshold,
const Eigen::Vector3f* source_points,
const Eigen::Vector3f* target_points,
const Eigen::Matrix4f transformation)
: distance_threshold_(distance_threshold),
source_points_(source_points),
target_points_(target_points),
transformation_(transformation) {}
__device__ bool operator()(const Eigen::Vector2i& corr) {
const auto &pt = source_points_[corr(0)];
Eigen::Vector3f pt_trans =
(transformation_ * Eigen::Vector4f(pt(0), pt(1), pt(2), 1.0))
.block<3, 1>(0, 0);
return (target_points_[
corr(1)] - pt_trans).norm() <= distance_threshold_;
}
};

struct normal_checker_functor {
float cos_normal_angle_threshold_;
const Eigen::Vector3f* source_points_;
const Eigen::Vector3f* target_points_;
const Eigen::Vector3f* source_normals_;
const Eigen::Vector3f* target_normals_;
const Eigen::Matrix4f transformation_;
normal_checker_functor(
float cos_normal_angle_threshold,
const Eigen::Vector3f* source_points,
const Eigen::Vector3f* target_points,
const Eigen::Vector3f* source_normals,
const Eigen::Vector3f* target_normals,
const Eigen::Matrix4f transformation)
: cos_normal_angle_threshold_(cos_normal_angle_threshold),
source_points_(source_points),
target_points_(target_points),
source_normals_(source_normals),
target_normals_(target_normals),
transformation_(transformation) {}
__device__ bool operator()(const Eigen::Vector2i& corr) {
const auto &normal = source_normals_[corr(0)];
Eigen::Vector3f normal_trans =
(transformation_ *
Eigen::Vector4f(normal(0), normal(1), normal(2), 0.0))
.block<3, 1>(0, 0);
return target_normals_[corr(1)].dot(normal) >= cos_normal_angle_threshold_;
}
};
}

bool CorrespondenceCheckerBasedOnEdgeLength::Check(
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres,
const Eigen::Matrix4f & /*transformation*/) const {
return thrust::all_of(
thrust::make_counting_iterator<size_t>(0),
thrust::make_counting_iterator(corres.size() * corres.size()),
edge_length_checker_functor(
similarity_threshold_,
corres.size(),
thrust::raw_pointer_cast(source.points_.data()),
thrust::raw_pointer_cast(target.points_.data()),
thrust::raw_pointer_cast(corres.data())));
}

bool CorrespondenceCheckerBasedOnDistance::Check(
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres,
const Eigen::Matrix4f &transformation) const {
return thrust::all_of(
corres.begin(), corres.end(),
distance_checker_functor(
distance_threshold_,
thrust::raw_pointer_cast(source.points_.data()),
thrust::raw_pointer_cast(target.points_.data()),
transformation));
}

bool CorrespondenceCheckerBasedOnNormal::Check(
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres,
const Eigen::Matrix4f &transformation) const {
if (!source.HasNormals() || !target.HasNormals()) {
utility::LogWarning(
"[CorrespondenceCheckerBasedOnNormal::Check] Pointcloud has no "
"normals.");
return true;
}
float cos_normal_angle_threshold = std::cos(normal_angle_threshold_);
return thrust::all_of(
corres.begin(), corres.end(),
normal_checker_functor(
cos_normal_angle_threshold,
thrust::raw_pointer_cast(source.points_.data()),
thrust::raw_pointer_cast(target.points_.data()),
thrust::raw_pointer_cast(source.normals_.data()),
thrust::raw_pointer_cast(target.normals_.data()),
transformation));
}

} // namespace registration
} // namespace cupoch
Loading

0 comments on commit dafcdaa

Please sign in to comment.