Skip to content

Commit 407ffca

Browse files
committed
Added python module
update gitignore for python temp files
1 parent f4e41ee commit 407ffca

File tree

6 files changed

+298
-1
lines changed

6 files changed

+298
-1
lines changed

.gitignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,12 @@
66
*.opensdf
77
*.bat
88
*.zip
9-
.vs/*
9+
.vs/*
10+
11+
12+
*.DS_Store
13+
CMakeLists.txt.user
14+
Python/build/
15+
Python/dist/
16+
Python/pypoissonrecon.cpp
17+
Python/pypoissonrecon.egg-info/

Python/ReadMe.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Python Bindings for Poisson Reconstruction Library
2+
3+
##### Installation
4+
```
5+
$ python setup.py build_ext
6+
$ python setup.py install --prefix=<path_to_installation>
7+
```
8+
9+
##### Contributed by
10+
11+
* The original [Matlab bindings](https://github.com/daeyun/poisson-surface-reconstruction) were developed by [Daeyun Shin](https://github.com/daeyun).
12+
* Adapted to Python by [Miguel Molero](https://github.com/mmolero/pypoisson) as a separate project [pypoisson](https://github.com/mmolero/pypoisson), which ultimately got outdated.
13+
* Modernized to version 13.72 and contributed directly to the main repository by [Harsh Bhatia](https://github.com/bhatiaharsh) for improved versioning and management.

Python/pypoissonrecon.pyx

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#cython: language_level=3str
2+
3+
cimport numpy as np
4+
import numpy as np
5+
from libcpp.vector cimport vector
6+
from libcpp.string cimport string
7+
from libc.stdlib cimport malloc, free
8+
from libcpp cimport bool
9+
10+
np.import_array()
11+
12+
cdef extern from "../Src/PoissonReconLib.h":
13+
cdef int PoissonReconLib(int argc, char* argv[])
14+
cdef vector[double] double_data
15+
cdef vector[int] int_data
16+
cdef vector[double] mem_data
17+
18+
def poisson_reconstruction(points, normals,
19+
depth=8, full_depth=5, scale=1.1,
20+
samples_per_node=1.0, cg_depth=0.0,
21+
enable_polygon_mesh=False, enable_density=False,
22+
nthreads=0, verbose=False):
23+
24+
"""
25+
Python Binding of Poisson Surface Reconstruction
26+
Usage:
27+
28+
faces, vertices = poisson_reconstruction(points, normals, depth=10)
29+
30+
31+
Parameters
32+
----------
33+
34+
points: array-like
35+
36+
list of oriented vertices with the x-, y-, and z-coordinates of the positions
37+
38+
normals: array-like
39+
40+
list of the x-, y-, and z-coordinates of the normals
41+
42+
depth: Integer
43+
44+
This integer is the maximum depth of the tree that will be used for surface reconstruction.
45+
Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than 2^d x 2^d x 2^d.
46+
Note that since the reconstructor adapts the octree to the sampling density, the specified reconstruction depth is only an upper bound.
47+
The default value for this parameter is 8.
48+
49+
full_depth: Integer
50+
51+
This integer specifies the depth beyond depth the octree will be adapted.
52+
At coarser depths, the octree will be complete, containing all 2^d x 2^d x 2^d nodes.
53+
The default value for this parameter is 5.
54+
55+
scale: float
56+
57+
This floating point value specifies the ratio between the diameter of the cube used for reconstruction and the diameter of the samples' bounding cube.
58+
The default value is 1.1.
59+
60+
samples_per_node: float
61+
62+
This floating point value specifies the minimum number of sample points that should fall within an octree node as the octree construction is adapted to sampling density.
63+
For noise-free samples, small values in the range [1.0 - 5.0] can be used.
64+
For more noisy samples, larger values in the range [15.0 - 20.0] may be needed to provide a smoother, noise-reduced, reconstruction.
65+
The default value is 1.0.
66+
67+
cg_depth: Integer
68+
69+
This integer is the depth up to which a conjugate-gradients solver will be used to solve the linear system.
70+
Beyond this depth Gauss-Seidel relaxation will be used.
71+
The default value for this parameter is 0.
72+
73+
enable_polygon_mesh: Bool
74+
Enabling this flag tells the reconstructor to output a polygon mesh (rather than triangulating the results of Marching Cubes).
75+
The default value for this parameter is False.
76+
77+
enable_density: Bool
78+
Enabling this flag tells the reconstructor to output the estimated depth values of the iso-surface vertices
79+
The default value for this parameter is False.
80+
81+
nthreads: int
82+
Number of omp threads to use. Default = 0 = all available threads.
83+
84+
verbose: Bool
85+
Enable verbose mode.
86+
87+
88+
89+
Returns
90+
-------
91+
92+
faces: array-like
93+
faces of the reconstructed mesh
94+
95+
vertices: array-like
96+
97+
vertices of the reconstructed mesh
98+
99+
100+
101+
102+
"""
103+
104+
return _poisson_reconstruction(np.ascontiguousarray(np.float64(points)),
105+
np.ascontiguousarray(np.float64(normals)),
106+
depth, full_depth, scale, samples_per_node,
107+
cg_depth, enable_polygon_mesh, enable_density,
108+
nthreads, verbose)
109+
110+
111+
112+
cdef _poisson_reconstruction(np.float64_t[:, ::1] points,
113+
np.float64_t[:, ::1] normals,
114+
int depth=8,
115+
int full_depth=5,
116+
double scale=1.10,
117+
double samples_per_node=1.0,
118+
double cg_depth=0.0,
119+
bool enable_polygon_mesh=False,
120+
bool enable_density=False,
121+
int nthreads=0,
122+
bool verbose=False):
123+
124+
cdef:
125+
char **c_argv
126+
string arg_depth = str(depth).encode()
127+
string arg_full_depth = str(full_depth).encode()
128+
string arg_scale = str(scale).encode()
129+
string arg_samples_per_node = str(samples_per_node).encode()
130+
string arg_cg_depth = str(cg_depth).encode()
131+
string arg_nthreads = str(nthreads).encode()
132+
133+
int_data.clear()
134+
double_data.clear()
135+
mem_data.clear()
136+
137+
point_nrows, point_ncols = np.shape(points)
138+
normal_nrows, normal_ncols = np.shape(normals)
139+
140+
mem_data.resize(point_ncols * point_nrows + normal_ncols * normal_nrows)
141+
142+
for i in range(point_nrows):
143+
for j in range(point_ncols):
144+
mem_data[j + i*(point_ncols + normal_ncols)] = points[i,j]
145+
mem_data[j + point_ncols + i *(point_ncols + normal_ncols)] = normals[i,j]
146+
147+
148+
args = [b"PoissonRecon", b"--in", b"none", b"--out", b"none", b"--depth", arg_depth.c_str(),
149+
b"--fullDepth", arg_full_depth.c_str(), b"--scale", arg_scale.c_str(),
150+
b"--samplesPerNode", arg_samples_per_node.c_str(),
151+
b"--cgDepth", arg_cg_depth.c_str()]
152+
153+
if verbose == True:
154+
args += [b"--verbose"]
155+
156+
if nthreads > 0:
157+
args += [b"--threads", arg_nthreads.c_str()]
158+
159+
if enable_polygon_mesh:
160+
args += [b"--polygonMesh"]
161+
if enable_density:
162+
args += [b"--density"]
163+
164+
c_argv = <char**> malloc(sizeof(char*) * len(args))
165+
for idx, s in enumerate(args):
166+
c_argv[idx] = s
167+
168+
try:
169+
PoissonReconLib(len(args), c_argv)
170+
finally:
171+
free(c_argv)
172+
173+
174+
face_cols, vertex_cols = 3, 3
175+
face_rows = int_data.size() // face_cols
176+
vertex_rows = double_data.size() // vertex_cols
177+
178+
cdef int *ptr_faces = &int_data[0]
179+
cdef double *ptr_vertices = &double_data[0]
180+
181+
faces = np.zeros((face_rows*face_cols,), dtype=np.int32 )
182+
vertices = np.zeros((vertex_rows*vertex_cols,), dtype=np.float64)
183+
184+
for i in range(face_rows*face_cols):
185+
faces[i] = ptr_faces[i]
186+
187+
for i in range(vertex_rows*vertex_cols):
188+
vertices[i] = ptr_vertices[i]
189+
190+
int_data.clear()
191+
double_data.clear()
192+
193+
return faces.reshape(face_rows,face_cols), vertices.reshape(vertex_rows,vertex_cols)

Python/setup.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import os
2+
import numpy
3+
4+
from setuptools import setup, Extension
5+
from setuptools.command.build_ext import build_ext
6+
7+
# ------------------------------------------------------------------------------
8+
# paths to these external libraries
9+
libs = ['png', 'z', 'jpeg']
10+
11+
# TODO: need to properly pass in the paths to these external libs
12+
ext_inc_dir = ['/opt/local/include']
13+
ext_lib_dir = ['/opt/local/lib']
14+
15+
# ------------------------------------------------------------------------------
16+
# path to the project directory
17+
proj_dir = os.path.dirname(os.path.realpath('.'))
18+
19+
# code to be build for this extension module
20+
sources = [os.path.join(proj_dir, 'Src', 'PoissonReconLib.cpp'),
21+
'pypoissonrecon.pyx']
22+
23+
include_dirs = ext_inc_dir + [proj_dir]
24+
lib_dirs = ext_lib_dir
25+
26+
# ------------------------------------------------------------------------------
27+
# flags taken from original Makefile
28+
CXX_FLAGS = "-fopenmp -std=c++14 -pthread -fPIC -Wno-deprecated -Wno-invalid-offsetof "
29+
CXX_LINKER_FLAGS = "-fopenmp -lstdc++ -lpthread "
30+
31+
# let's just assume we are building release
32+
if True:
33+
CXX_FLAGS += "-Ofast -DRELEASE -funroll-loops -ffast-math "
34+
CXX_LINKER_FLAGS += "-Ofast "
35+
36+
# if we wanted to build debug
37+
else:
38+
CXX_FLAGS += "-g3 "
39+
CXX_LINKER_FLAGS += ""
40+
41+
# flags to suppress further warnings
42+
if True:
43+
CXX_FLAGS += "-Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-local-typedefs "
44+
CXX_FLAGS += "-Wno-delete-non-virtual-dtor -Wno-class-memaccess -Wno-strict-aliasing "
45+
CXX_FLAGS += "-Wno-sign-compare -Wno-reorder -Wno-dangling-else "
46+
CXX_FLAGS += "-Wno-maybe-uninitialized -Wno-format-overflow "
47+
48+
# ------------------------------------------------------------------------------
49+
extn_mod = Extension('pypoissonrecon', language='c++',
50+
sources = sources,
51+
include_dirs = include_dirs + [numpy.get_include()],
52+
extra_compile_args = CXX_FLAGS.split(),
53+
extra_link_args = CXX_LINKER_FLAGS.split(),
54+
libraries=libs,
55+
library_dirs=lib_dirs)
56+
57+
# ------------------------------------------------------------------------------
58+
setup(
59+
name='pypoissonrecon',
60+
version='13.72',
61+
description='Poisson Surface Reconstruction (Adaptive Multigrid Solvers)',
62+
author='',
63+
author_email='',
64+
url='https://github.com/mkazhdan/PoissonRecon',
65+
cmdclass = {'build_ext': build_ext},
66+
ext_modules = [extn_mod]
67+
)
68+
# ------------------------------------------------------------------------------

Src/PoissonReconLib.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S
2626
DAMAGE.
2727
*/
2828

29+
#include <vector>
30+
std::vector<double> double_data;
31+
std::vector<int> int_data;
32+
std::vector<double> mem_data;
33+
bool* is_verbose;
34+
bool is_writing_to_memory = true;
35+
bool is_reading_from_memory = true;
36+
bool is_writing_int;
37+
2938
#include "PreProcessor.h"
3039

3140
#undef USE_DOUBLE // If enabled, double-precesion is used

Src/PoissonReconLib.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,10 @@ DAMAGE.
2828

2929
#pragma once
3030

31+
#include <vector>
32+
extern std::vector<double> double_data;
33+
extern std::vector<int> int_data;
34+
extern std::vector<double> mem_data;
35+
extern bool* is_verbose;
36+
3137
int PoissonReconLib(int argc, char **argv);

0 commit comments

Comments
 (0)