Skip to main content

Read in PLY files using a wrapper over miniply

Project description

pypi MIT

pyminiply is a Python library for rapidly reading PLY files. It is a Python wrapper around the fast C++ PLY reading library provided by miniply. Thanks @vilya!

The main advantage of pyminiply over other PLY reading libraries is its performance. See the benchmarks below for more details.

Installation

The recommended way to install pyminiply is via PyPI:

pip install pyminiply

You can also clone the repository and install it from source:

git clone https://github.com/pyvista/pyminiply.git
cd pyminiply
git submodule update --init --recursive
pip install .

Usage

Load in the vertices, indices, normals, UV, and color information from a PLY file:

>>> import pyminiply
>>> vertices, indices, normals, uv, color = pyminiply.read("example.ply")
>>> vertices
array([[ 5.0000000e-01, -5.0000000e-01, -5.5511151e-17],
       [ 4.0000001e-01, -5.0000000e-01, -4.4408922e-17],
       [ 3.0000001e-01, -5.0000000e-01, -3.3306692e-17],
       ...,
       [-4.2500001e-01,  5.0000000e-01,  4.7184480e-17],
       [-4.7499999e-01,  4.4999999e-01,  5.2735593e-17],
       [-5.0000000e-01,  4.2500001e-01,  5.5511151e-17]], dtype=float32)
>>> indices
array([[   0,  442,  441],
       [ 442,  122,  443],
       [ 443,  121,  441],
       ...,
       [1677,  438, 1679],
       [1679,  439, 1676],
       [1677, 1679, 1676]], dtype=int32)
>>> normals
array([[-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       ...,
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00]], dtype=float32)
>>> uv
array([[0.        , 0.        ],
       [0.1       , 0.        ],
       [0.2       , 0.        ],
       ...,
       [0.92499995, 1.        ],
       [0.975     , 0.95      ],
       [1.        , 0.92499995]], dtype=float32)
>>> color
array([[  0,   0,   0],
       [  0,   0,   0],
       [  0,   0,   0],
       ...,
       [254, 254, 254],
       [254, 254, 254],
       [255, 255, 255]], dtype=uint8)

You can also read in the PLY file as a PyVista PolyData and immediately plot it.

 >>> import pyminiply
 >>> mesh = pyminiply.read_as_mesh("example.ply")
 >>> mesh
 PolyData (0x7f0653579c00)
   N Cells:    200
   N Points:   121
   N Strips:   0
   X Bounds:   -5.000e-01, 5.000e-01
   Y Bounds:   -5.000e-01, 5.000e-01
   Z Bounds:   -5.551e-17, 5.551e-17
   N Arrays:   2

>>> mesh.plot()
https://github.com/pyvista/pyminiply/raw/main/demo.png

Benchmark

The main reason behind writing yet another PLY file reader for Python is to leverage the highly performant miniply library.

There is already an benchmark demonstrating how miniply outperforms in comparison to competing C and C++ libraries at ply_io_benchmark when reading PLY files. The benchmark here shows how pyminiply performs relative to other Python PLY file readers.

Here are the timings from reading in a 1,000,000 point binary PLY file:

Library

Time (seconds)

pyminiply

0.046

open3d

0.149

PyVista (VTK)

0.409

meshio

0.512

plyfile

8.939

Benchmark source:

import time

import numpy as np
import pyvista as pv
import pyminiply
import plyfile
import meshio
import open3d

filename = 'tmp.ply'
mesh = pv.Plane(i_resolution=999, j_resolution=999).triangulate()
mesh.clear_data()
mesh.save(filename)

# pyminiply
tstart = time.time()
pyminiply.read(filename)
tend = time.time() - tstart; print(f'pyminiply:   {tend:.3f}')

# open3d
tstart = time.time()
open3d.io.read_point_cloud(filename)
tend = time.time() - tstart; print(f'open3d:      {tend:.3f}')

# VTK/PyVista
tstart = time.time()
pv.read(filename)
tend = time.time() - tstart; print(f'VTK/PyVista: {tend:.3f}')

tstart = time.time()
meshio.read(filename)
tend = time.time() - tstart; print(f'meshio:      {tend:.3f}')

# plyfile
tstart = time.time()
plyfile.PlyData.read(filename)
tend = time.time() - tstart; print(f'plyfile:     {tend:.3f}')

Comparison with VTK and PyVista

Here’s an additional benchmark comparing VTK/PyVista with pyminiply:

import numpy as np
import time
import pyvista as pv
import matplotlib.pyplot as plt
import pyminiply

times = []
filename = 'tmp.ply'
for res in range(50, 800, 50):
    mesh = pv.Plane(i_resolution=res, j_resolution=res).triangulate().subdivide(2)
    mesh.clear_data()
    mesh.save(filename)

    tstart = time.time()
    pv_mesh = pv.read(filename)
    vtk_time = time.time() - tstart

    tstart = time.time()
    ply_mesh = pyminiply.read_as_mesh(filename)
    ply_reader_time =  time.time() - tstart

    assert np.allclose(pv_mesh['Normals'], ply_mesh['Normals'])
    assert np.allclose(pv_mesh.points, ply_mesh.points)
    assert np.allclose(pv_mesh._connectivity_array, ply_mesh._connectivity_array)

    times.append([mesh.n_points, vtk_time, ply_reader_time])
    print(times[-1])


times = np.array(times)
plt.figure(1)
plt.title('PLY load time')
plt.plot(times[:, 0], times[:, 1], label='VTK')
plt.plot(times[:, 0], times[:, 2], label='pyminiply')
plt.xlabel('Number of Points')
plt.ylabel('Time to Load (seconds)')
plt.legend()

plt.figure(2)
plt.title('PLY load time (Log-Log)')
plt.loglog(times[:, 0], times[:, 1], label='VTK')
plt.loglog(times[:, 0], times[:, 2], label='pyminiply')
plt.xlabel('Number of Points')
plt.ylabel('Time to Load (seconds)')
plt.legend()
plt.show()
https://github.com/pyvista/pyminiply/raw/main/bench0.png https://github.com/pyvista/pyminiply/raw/main/bench1.png

License and Acknowledgments

This project relies on miniply and credit goes to the original author for the excellent C++ library. That work is licensed under the MIT License.

The work in this repository is also licensed under the MIT License.

Support

If you are having issues, please feel free to raise an Issue.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyminiply-0.1.1.tar.gz (28.4 kB view hashes)

Uploaded Source

Built Distributions

pyminiply-0.1.1-cp312-cp312-win_amd64.whl (52.7 kB view hashes)

Uploaded CPython 3.12 Windows x86-64

pyminiply-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (478.3 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pyminiply-0.1.1-cp312-cp312-macosx_10_9_x86_64.whl (67.3 kB view hashes)

Uploaded CPython 3.12 macOS 10.9+ x86-64

pyminiply-0.1.1-cp312-cp312-macosx_10_9_universal2.whl (123.8 kB view hashes)

Uploaded CPython 3.12 macOS 10.9+ universal2 (ARM64, x86-64)

pyminiply-0.1.1-cp311-cp311-win_amd64.whl (52.8 kB view hashes)

Uploaded CPython 3.11 Windows x86-64

pyminiply-0.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (476.8 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pyminiply-0.1.1-cp311-cp311-macosx_10_9_x86_64.whl (67.3 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ x86-64

pyminiply-0.1.1-cp311-cp311-macosx_10_9_universal2.whl (123.9 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ universal2 (ARM64, x86-64)

pyminiply-0.1.1-cp310-cp310-win_amd64.whl (52.8 kB view hashes)

Uploaded CPython 3.10 Windows x86-64

pyminiply-0.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (463.9 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pyminiply-0.1.1-cp310-cp310-macosx_10_9_x86_64.whl (67.2 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ x86-64

pyminiply-0.1.1-cp310-cp310-macosx_10_9_universal2.whl (123.8 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ universal2 (ARM64, x86-64)

pyminiply-0.1.1-cp39-cp39-win_amd64.whl (53.1 kB view hashes)

Uploaded CPython 3.9 Windows x86-64

pyminiply-0.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (465.8 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pyminiply-0.1.1-cp39-cp39-macosx_10_9_x86_64.whl (67.6 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ x86-64

pyminiply-0.1.1-cp39-cp39-macosx_10_9_universal2.whl (124.6 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ universal2 (ARM64, x86-64)

pyminiply-0.1.1-cp38-cp38-win_amd64.whl (53.4 kB view hashes)

Uploaded CPython 3.8 Windows x86-64

pyminiply-0.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (468.6 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

pyminiply-0.1.1-cp38-cp38-macosx_10_9_x86_64.whl (67.6 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ x86-64

pyminiply-0.1.1-cp38-cp38-macosx_10_9_universal2.whl (124.6 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64)

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page