Skip to content

Commit

Permalink
Weighted random sampling
Browse files Browse the repository at this point in the history
  • Loading branch information
arntanguy committed Nov 17, 2017
0 parents commit f51a78c
Show file tree
Hide file tree
Showing 11 changed files with 1,106 additions and 0 deletions.
1 change: 1 addition & 0 deletions .clang-format
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
compile_commands.json
*.pyc
build/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "cmake"]
path = cmake
url = git://github.com/jrl-umi3218/jrl-cmakemodules.git
29 changes: 29 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 2.8)

include(cmake/base.cmake)
include(cmake/eigen.cmake)
include(cmake/boost.cmake)

set(PROJECT_NAME gram_savitzky_golay)
set(PROJECT_DESCRIPTION "Sample pointcloud from meshes")
set(PROJECT_URL "")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

setup_project()
search_for_eigen()
enable_testing()

find_package(PCL 1.7 REQUIRED COMPONENTS common io)
include_directories(${PCL_INCLUDE_DIRS})

add_required_dependency(assimp)

# Enable C++11
add_definitions(-std=c++11 -O3)
add_definitions(${PCL_DEFINITIONS})

include_directories(include)
add_subdirectory(src)

setup_project_finalize()

674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
mesh_sampling
==

C++ Implementation of pointcloud generation from mesh sampling methods.
So far, the following samplers have been implemented:

- Weighted random sampling: generates a given number of points uniformely distributed according to triangle areas.
See [this blog post](https://medium.com/@daviddelaiglesiacastro/3f-point-cloud-generation-from-3f-triangular-mesh-bbb602ecf238) for details on the method.

It is provided as-is, and could probably be optimized should the need arise. Feel free to submit merge requests.


Example
==

```cpp
// Model in a format supported by assimp
std::string model_path = "your_model.stl";

// Create an instance of the Importer class
Assimp::Importer importer;
// And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll
// propably to request more postprocessing than we do in this example.
const aiScene* scene = importer.ReadFile( model_path,
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);

// If the import failed, report it
if( !scene)
{
std::cerr << importer.GetErrorString() << std::endl; ;
return false;
}

WeightedRandomSampling sampling(scene);
// Sample 10000 points on your scene
auto cloud = sampling.weighted_random_sampling(10000);

pcl::io::savePCDFileASCII ("/tmp/test_pcd.pcd", *cloud);
```
1 change: 1 addition & 0 deletions cmake
Submodule cmake added at 7e56da
122 changes: 122 additions & 0 deletions include/mesh_sampling/weighted_random_sampling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2017 CNRS-UM LIRMM
// Copyright 2017 Arnaud TANGUY <[email protected]>
//
// This file is part of mesh_sampling.
//
// mesh_sampling is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// mesh_sampling is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with mesh_sampling. If not, see <http://www.gnu.org/licenses/>.


#pragma once
#include <memory>
#include <random>
#include <vector>
#include <algorithm>
#include <Eigen/Core>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>

class aiScene;
class aiMesh;
class aiFace;

namespace mesh_sampling
{

double triangle_area(const Eigen::Vector3f& v1, const Eigen::Vector3f& v2, const Eigen::Vector3f& v3);
Eigen::Vector3f random_point_in_triangle(const Eigen::Vector3f& v1, const Eigen::Vector3f& v2, const Eigen::Vector3f& v3);


/**
* @brief Generates indices based on probabilities
*
* @param probabilities The probabilities associated with each entry in samples.
* @param n number of generated samples
*
* @return return n sampled indices from the probability distribution. Each
* index will be between [0, probabilities.size()[
*/
template<typename SampleT, typename ProbaT>
std::vector<SampleT> weighted_random_choice_indices(const std::vector<ProbaT>& probabilities, const size_t n)
{
std::default_random_engine generator;
std::discrete_distribution<int> distribution(probabilities.begin(), probabilities.end());

std::vector<int> indices(n);
std::generate(indices.begin(), indices.end(), [&generator, &distribution]() { return distribution(generator); });
return indices;
}

/**
* @brief Implementation of python's numpy.random.choice
* Generates a random sample from a given 1-D array
* Since range lazy iterators are not available in C++11, using this function
* might necessitate generating a large samples array, whereby python would be
* able to take advantage of lazy generation.
*
* @param samples a random sample is generated from its elements
* @param probabilities The probabilities associated with each entry in samples.
* @param n number of samples
*
* @return The generated random samples
*/
template<typename SampleT, typename ProbaT>
std::vector<SampleT> weighted_random_choice(const std::vector<SampleT>& samples, const std::vector<ProbaT>& probabilities, const size_t n)
{
const auto& indices = weighted_random_choice_indices(probabilities, n);
std::vector<SampleT> vec(n);
std::transform(indices.begin(), indices.end(), vec.begin(), [&samples](int index) { return samples[index]; });
return vec;
}


template<typename T>
T randMToN(T M, T N)
{
return M + (static_cast<T>(std::rand()) / ( RAND_MAX / (N-M) ) ) ;
}

/**
* @brief Create pointcloud from MESH using weighted random sampling
*
* See the pyntcloud python library for more details:
* https://github.com/daavoo/pyntcloud
* https://github.com/daavoo/pyntcloud/blob/master/pyntcloud/samplers/s_mesh.py
* https://medium.com/@daviddelaiglesiacastro/3f-point-cloud-generation-from-3f-triangular-mesh-bbb602ecf238
*/
class WeightedRandomSampling
{
private:
const aiScene *scene;

std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > v1_xyz,v2_xyz,v3_xyz;
std::vector<double> areas;
double total_area = 0;

void process_triangle(const aiMesh* mesh, const aiFace& face);
void process_mesh(const aiMesh* mesh);
void process_scene(const aiScene *scene);
public:
WeightedRandomSampling(const aiScene* scene);
/**
* @brief Compute a weighted random sampling of the scene.
*
* @param N Number of samples
* If N = 0, then the the number of triangles in the scene will be used to
* generate samples.
*
* @return Sampled pointcloud from scene
*/
std::unique_ptr<pcl::PointCloud<pcl::PointXYZ>> weighted_random_sampling(const size_t N = 0);
};
} /* mesh_sampling */
16 changes: 16 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
add_library(mesh_sampling SHARED
weighted_random_sampling.cpp
)
pkg_config_use_dependency(mesh_sampling assimp)
target_link_libraries(mesh_sampling ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES})

install(TARGETS mesh_sampling
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)

install(
DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include)

add_executable(example example.cpp)
target_link_libraries(example mesh_sampling)
60 changes: 60 additions & 0 deletions src/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2017 CNRS-UM LIRMM
// Copyright 2017 Arnaud TANGUY <[email protected]>
//
// This file is part of mesh_sampling.
//
// mesh_sampling is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// mesh_sampling is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with mesh_sampling. If not, see <http://www.gnu.org/licenses/>.

#include <iostream>
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags

#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>

#include <mesh_sampling/weighted_random_sampling.h>

using namespace mesh_sampling;

int main(int /* argc */, char** /* argv */)
{
std::string model_path = "../../getafe.stl";

// Create an instance of the Importer class
Assimp::Importer importer;
// And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll
// propably to request more postprocessing than we do in this example.
const aiScene* scene = importer.ReadFile( model_path,
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);

// If the import failed, report it
if( !scene)
{
std::cerr << importer.GetErrorString() << std::endl; ;
return false;
}

WeightedRandomSampling sampling(scene);
auto cloud = sampling.weighted_random_sampling();

pcl::io::savePCDFileASCII ("/tmp/test_pcd.pcd", *cloud);
pcl::io::savePLYFileASCII("/tmp/test.ply", *cloud);

}
Loading

0 comments on commit f51a78c

Please sign in to comment.