Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@
*.opensdf
*.bat
*.zip
.vs/*
.vs/*


*.DS_Store
CMakeLists.txt.user
Python/build/
Python/dist/
Python/pypoissonrecon.cpp
Python/pypoissonrecon.egg-info/
100 changes: 100 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
## -----------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.20)
project(AdaptiveMultigridSolvers)

set(CMAKE_VERBOSE_MAKEFILE ON)

## -----------------------------------------------------------------------------
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# set custom compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
set(CFLAGS "-std=c++14 -pthread -Wno-deprecated -Wno-invalid-offsetof")
set(LFLAGS "-lstdc++ -lpthread")
else()
set(CFLAGS, "-std=c++14 -pthread -Wno-deprecated -Wno-invalid-offsetof -Wno-dangling-else")
set(LFLAGS, "-lstdc++")
endif()


set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CFLAGS} -g3")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CFLAGS} -Ofast -DRELEASE -funroll-loops -ffast-math")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LFLAGS} -Ofast")

## -----------------------------------------------------------------------------
find_package(OpenMP REQUIRED)

## -----------------------------------------------------------------------------
find_package(PNG) # PNG depends on zlib and adds zlib to path already
if(PNG_FOUND)
#message("-- png lib found: include_dir=(${PNG_INCLUDE_DIRS}), libs=(${PNG_LIBRARIES})")
else()

set(PNG_PATH "${PROJECT_SOURCE_DIR}/PNG")
message("-- png lib not found: will build from (${PNG_PATH})")

set(PNG_INCLUDE_DIRS ${PNG_PATH})
set(PNG_LIBRARIES "png") # will result in libpng

file(GLOB_RECURSE SRCS_PNG "${PNG_PATH}/*.c")
add_library(${PNG_LIBRARIES} SHARED ${SRCS_PNG})
endif()

## -----------------------------------------------------------------------------
find_package(ZLIB) # dont really need to check for zlib if png was success
if(ZLIB_FOUND)
#message("-- zlib found: include_dir=(${ZLIB_INCLUDE_DIRS}), libs=(${ZLIB_LIBRARIES})")
else()
set(ZLIB_PATH "${PROJECT_SOURCE_DIR}/ZLIB")
message("-- zlib not found: will build from (${ZLIB_PATH})")

set(ZLIB_INCLUDE_DIRS ${ZLIB_PATH})
set(ZLIB_LIBRARIES "z") # will result in libz

file(GLOB_RECURSE SRCS_ZLIB "${ZLIB_PATH}/*.c")
add_library(${ZLIB_LIBRARIES} SHARED ${SRCS_ZLIB})
endif()

## -----------------------------------------------------------------------------
find_package(JPEG)
if(JPEG_FOUND)
#message("-- jpeg lib found: include_dir=(${JPEG_INCLUDE_DIRS}), libs=(${JPEG_LIBRARIES})")
else()
set(JPEG_PATH "${PROJECT_SOURCE_DIR}/JPEG")
message("-- jpeg lib not found: will build from (${JPEG_PATH})")

set(JPEG_INCLUDE_DIRS ${JPEG})
set(JPEG_LIBRARIES "jpeg") # will result in libjpeg

file(GLOB_RECURSE SRCS_JPEG "${JPEG_PATH}/*.c")
add_library(${JPEG_LIBRARIES} SHARED ${SRCS_JPEG})
endif()


## -----------------------------------------------------------------------------
# all include paths
include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/Src)
include_directories(${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${JPEG_INCLUDE_DIRS})


## -----------------------------------------------------------------------------
## build poisson reconstruction library and executable
## -----------------------------------------------------------------------------
add_library(poisson_recon_lib SHARED
${PROJECT_SOURCE_DIR}/Src/PoissonReconLib.h
${PROJECT_SOURCE_DIR}/Src/PoissonReconLib.cpp)

target_link_libraries(poisson_recon_lib
${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES})


add_executable(poisson_recon
${PROJECT_SOURCE_DIR}/Src/PoissonRecon.cpp)

target_link_libraries(poisson_recon
poisson_recon_lib
${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES})

## -----------------------------------------------------------------------------
13 changes: 13 additions & 0 deletions Python/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Python Bindings for Poisson Reconstruction Library

##### Installation
```
$ python setup.py build_ext
$ python setup.py install --prefix=<path_to_installation>
```

##### Contributed by

* The original [Matlab bindings](https://github.com/daeyun/poisson-surface-reconstruction) were developed by [Daeyun Shin](https://github.com/daeyun).
* 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.
* Modernized to version 13.72 and contributed directly to the main repository by [Harsh Bhatia](https://github.com/bhatiaharsh) for improved versioning and management.
188 changes: 188 additions & 0 deletions Python/pypoissonrecon.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#cython: language_level=3str

## 2021.07.21: code adapted from https://github.com/mmolero/pypoisson
## https://github.com/mmolero/pypoisson/blob/4f6a651d20ff2bab5ec0d0f8d0a14cc6cef3ef51/src/pypoisson.pyx

cimport numpy as np
import numpy as np
from libcpp.vector cimport vector
from libcpp.string cimport string
from libc.stdlib cimport malloc, free
from libcpp cimport bool

np.import_array()

cdef extern from "../Src/PoissonReconLib.h":
cdef int PoissonReconLib(int argc, char* argv[])
cdef vector[double] double_data
cdef vector[int] int_data
cdef vector[double] mem_data

def poisson_reconstruction(points, normals,
depth=8, full_depth=5, scale=1.1,
samples_per_node=1.0,
enable_polygon_mesh=False, enable_density=False,
nthreads=8, verbose=False):

"""
Python Binding of Poisson Surface Reconstruction
Usage:

faces, vertices = poisson_reconstruction(points, normals, depth=10)


Parameters
----------

points: array-like

list of oriented vertices with the x-, y-, and z-coordinates of the positions

normals: array-like

list of the x-, y-, and z-coordinates of the normals

depth: Integer

This integer is the maximum depth of the tree that will be used for surface reconstruction.
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.
Note that since the reconstructor adapts the octree to the sampling density, the specified reconstruction depth is only an upper bound.
The default value for this parameter is 8.

full_depth: Integer

This integer specifies the depth beyond depth the octree will be adapted.
At coarser depths, the octree will be complete, containing all 2^d x 2^d x 2^d nodes.
The default value for this parameter is 5.

scale: float

This floating point value specifies the ratio between the diameter of the cube used for reconstruction and the diameter of the samples' bounding cube.
The default value is 1.1.

samples_per_node: float

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.
For noise-free samples, small values in the range [1.0 - 5.0] can be used.
For more noisy samples, larger values in the range [15.0 - 20.0] may be needed to provide a smoother, noise-reduced, reconstruction.
The default value is 1.0.

enable_polygon_mesh: Bool
Enabling this flag tells the reconstructor to output a polygon mesh (rather than triangulating the results of Marching Cubes).
The default value for this parameter is False.

enable_density: Bool
Enabling this flag tells the reconstructor to output the estimated depth values of the iso-surface vertices
The default value for this parameter is False.

nthreads: int
This parameter specifies the number of threads across which the solver should be parallelized.
The default value for this parameter is 8.

verbose: Bool
Enable verbose mode.



Returns
-------

faces: array-like
faces of the reconstructed mesh

vertices: array-like

vertices of the reconstructed mesh




"""

return _poisson_reconstruction(np.ascontiguousarray(np.float64(points)),
np.ascontiguousarray(np.float64(normals)),
depth, full_depth, scale, samples_per_node,
enable_polygon_mesh, enable_density,
nthreads, verbose)



cdef _poisson_reconstruction(np.float64_t[:, ::1] points,
np.float64_t[:, ::1] normals,
int depth=8,
int full_depth=5,
double scale=1.10,
double samples_per_node=1.0,
bool enable_polygon_mesh=False,
bool enable_density=False,
int nthreads=0,
bool verbose=False):

cdef:
char **c_argv
string arg_depth = str(depth).encode()
string arg_full_depth = str(full_depth).encode()
string arg_scale = str(scale).encode()
string arg_samples_per_node = str(samples_per_node).encode()
string arg_nthreads = str(nthreads).encode()

int_data.clear()
double_data.clear()
mem_data.clear()

point_nrows, point_ncols = np.shape(points)
normal_nrows, normal_ncols = np.shape(normals)

mem_data.resize(point_ncols * point_nrows + normal_ncols * normal_nrows)

for i in range(point_nrows):
for j in range(point_ncols):
mem_data[j + i*(point_ncols + normal_ncols)] = points[i,j]
mem_data[j + point_ncols + i *(point_ncols + normal_ncols)] = normals[i,j]


args = [b"PoissonRecon", b"--in", b"none", b"--out", b"none",
b"--depth", arg_depth.c_str(),
b"--fullDepth", arg_full_depth.c_str(),
b"--scale", arg_scale.c_str(),
b"--samplesPerNode", arg_samples_per_node.c_str(),
b"--threads", arg_nthreads.c_str()
]

if verbose == True:
args += [b"--verbose"]
if enable_polygon_mesh:
args += [b"--polygonMesh"]
if enable_density:
args += [b"--density"]

c_argv = <char**> malloc(sizeof(char*) * len(args))
for idx, s in enumerate(args):
c_argv[idx] = s

try:
PoissonReconLib(len(args), c_argv)
finally:
free(c_argv)


face_cols, vertex_cols = 3, 3
face_rows = int_data.size() // face_cols
vertex_rows = double_data.size() // vertex_cols

cdef int *ptr_faces = &int_data[0]
cdef double *ptr_vertices = &double_data[0]

faces = np.zeros((face_rows*face_cols,), dtype=np.int32 )
vertices = np.zeros((vertex_rows*vertex_cols,), dtype=np.float64)

for i in range(face_rows*face_cols):
faces[i] = ptr_faces[i]

for i in range(vertex_rows*vertex_cols):
vertices[i] = ptr_vertices[i]

int_data.clear()
double_data.clear()

return faces.reshape(face_rows,face_cols), vertices.reshape(vertex_rows,vertex_cols)
68 changes: 68 additions & 0 deletions Python/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import os
import numpy

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

# ------------------------------------------------------------------------------
# paths to these external libraries
libs = ['png', 'z', 'jpeg']

# TODO: need to properly pass in the paths to these external libs
ext_inc_dir = ['/opt/local/include']
ext_lib_dir = ['/opt/local/lib']

# ------------------------------------------------------------------------------
# path to the project directory
proj_dir = os.path.dirname(os.path.realpath('.'))

# code to be build for this extension module
sources = [os.path.join(proj_dir, 'Src', 'PoissonReconLib.cpp'),
'pypoissonrecon.pyx']

include_dirs = ext_inc_dir + [proj_dir]
lib_dirs = ext_lib_dir

# ------------------------------------------------------------------------------
# flags taken from original Makefile
CXX_FLAGS = "-fopenmp -std=c++14 -pthread -fPIC -Wno-deprecated -Wno-invalid-offsetof "
CXX_LINKER_FLAGS = "-fopenmp -lstdc++ -lpthread "

# let's just assume we are building release
if True:
CXX_FLAGS += "-Ofast -DRELEASE -funroll-loops -ffast-math "
CXX_LINKER_FLAGS += "-Ofast "

# if we wanted to build debug
else:
CXX_FLAGS += "-g3 "
CXX_LINKER_FLAGS += ""

# flags to suppress further warnings
if True:
CXX_FLAGS += "-Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-local-typedefs "
CXX_FLAGS += "-Wno-delete-non-virtual-dtor -Wno-class-memaccess -Wno-strict-aliasing "
CXX_FLAGS += "-Wno-sign-compare -Wno-reorder -Wno-dangling-else "
CXX_FLAGS += "-Wno-maybe-uninitialized -Wno-format-overflow "

# ------------------------------------------------------------------------------
extn_mod = Extension('pypoissonrecon', language='c++',
sources = sources,
include_dirs = include_dirs + [numpy.get_include()],
extra_compile_args = CXX_FLAGS.split(),
extra_link_args = CXX_LINKER_FLAGS.split(),
libraries=libs,
library_dirs=lib_dirs)

# ------------------------------------------------------------------------------
setup(
name='pypoissonrecon',
version='13.72',
description='Poisson Surface Reconstruction (Adaptive Multigrid Solvers)',
author='',
author_email='',
url='https://github.com/mkazhdan/PoissonRecon',
cmdclass = {'build_ext': build_ext},
ext_modules = [extn_mod]
)
# ------------------------------------------------------------------------------
Loading