-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement experimental point cloud export API
- Loading branch information
Showing
10 changed files
with
469 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ | |
Frame, | ||
FrameInfo, | ||
PointCloud, | ||
point_cloud_export, | ||
Settings, | ||
version, | ||
Settings2D, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"""Module for exporting point cloud data to various formats. This API may change in the future.""" | ||
|
||
from zivid.experimental.point_cloud_export._export_frame import export_frame |
49 changes: 49 additions & 0 deletions
49
modules/zivid/experimental/point_cloud_export/_export_frame.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from zivid.frame import Frame | ||
from zivid.experimental.point_cloud_export.file_format import ZDF, PLY, XYZ, PCD | ||
|
||
import _zivid | ||
|
||
|
||
def export_frame(frame, file_format): | ||
"""Save frame to a file. | ||
The file format is specified by the file_format argument. The file format can be ZDF, PLY, XYZ, or PCD. | ||
If the format is PCD, this function stores the ordered point cloud with a header that indicates an unordered point | ||
cloud. Since SDK 2.5, it is possible to export PCD with correct header by setting | ||
`Configuration/APIBreakingBugFixes/FileFormats/PCD/UseOrganizedFormat` in Config.yml file. See | ||
https://support.zivid.com/en/latest/reference-articles/point-cloud-structure-and-output-formats.html#organized-pcd-format. | ||
Args: | ||
frame: Frame to export. | ||
file_format: File format specification. | ||
Raises: | ||
TypeError: If frame is not a Frame. | ||
TypeError: If file_format is not a file format specification. | ||
""" | ||
if not isinstance(frame, Frame): | ||
raise TypeError( | ||
"Unsupported type for argument frame. Got {}, expected {}".format( | ||
type(frame), Frame | ||
) | ||
) | ||
if not any( | ||
[ | ||
isinstance(file_format, ZDF), | ||
isinstance(file_format, PLY), | ||
isinstance(file_format, XYZ), | ||
isinstance(file_format, PCD), | ||
] | ||
): | ||
raise TypeError( | ||
"Unsupported type for argument file_format. Got {}, expected {}".format( | ||
type(file_format), | ||
" or ".join([t.__name__ for t in [ZDF, PLY, XYZ, PCD]]), | ||
) | ||
) | ||
|
||
format_impl_attr = f"_{type(file_format).__name__}__impl" | ||
_zivid.point_cloud_export.export_frame( | ||
frame._Frame__impl, getattr(file_format, format_impl_attr) | ||
) |
183 changes: 183 additions & 0 deletions
183
modules/zivid/experimental/point_cloud_export/file_format.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import _zivid | ||
|
||
|
||
class ColorSpace: | ||
"""Color space for saving point cloud.""" | ||
|
||
linear_rgb = "linear_rgb" | ||
srgb = "srgb" | ||
|
||
@staticmethod | ||
def valid_values(): | ||
"""Get valid values for color space.""" | ||
return [ColorSpace.linear_rgb, ColorSpace.srgb] | ||
|
||
@classmethod | ||
def _to_internal(cls, value): | ||
if value == ColorSpace.linear_rgb: | ||
return _zivid.point_cloud_export.ColorSpace.linear_rgb | ||
if value == ColorSpace.srgb: | ||
return _zivid.point_cloud_export.ColorSpace.srgb | ||
raise ValueError( | ||
"Invalid color space '{}'. Valid color spaces are: {}".format( | ||
value, cls.valid_values() | ||
) | ||
) | ||
|
||
|
||
class ZDF: | ||
"""Specification for saving frame in ZDF (*.zdf) format.""" | ||
|
||
def __init__(self, file_name): | ||
"""Create a ZDF file format specification with file name. | ||
Args: | ||
file_name: File name. | ||
""" | ||
if not isinstance(file_name, str): | ||
raise TypeError( | ||
"Unsupported type for argument file_name. Got {}, expected {}".format( | ||
type(file_name), str | ||
) | ||
) | ||
self.__impl = _zivid.point_cloud_export.file_format.ZDF(file_name) | ||
|
||
def __str__(self): | ||
return str(self.__impl) | ||
|
||
|
||
class PLY: | ||
"""Specification for saving frame in PLY (*.ply) format. | ||
PLY is a file format developed at Stanford. To learn more about the PLY file format, | ||
see https://paulbourke.net/dataformats/ply/. | ||
""" | ||
|
||
class Layout: | ||
"""Layout for saving point cloud.""" | ||
|
||
ordered = "ordered" | ||
unordered = "unordered" | ||
|
||
@staticmethod | ||
def valid_values(): | ||
"""Get valid values for layout.""" | ||
return [PLY.Layout.ordered, PLY.Layout.unordered] | ||
|
||
@classmethod | ||
def _to_internal(cls, value): | ||
if value == PLY.Layout.ordered: | ||
return _zivid.point_cloud_export.file_format.PLY.Layout.ordered | ||
if value == PLY.Layout.unordered: | ||
return _zivid.point_cloud_export.file_format.PLY.Layout.unordered | ||
raise ValueError( | ||
"Invalid layout '{}'. Valid layouts are: {}".format( | ||
value, cls.valid_values() | ||
) | ||
) | ||
|
||
def __init__(self, file_name, layout=Layout.ordered, color_space=ColorSpace.srgb): | ||
"""Create a PLY file format specification with file name. | ||
Args: | ||
file_name: File name. | ||
layout: Layout of point cloud. Default is ordered. | ||
color_space: Color space of point cloud. Default is sRGB. | ||
""" | ||
if not isinstance(file_name, str): | ||
raise TypeError( | ||
"Unsupported type for argument file_name. Got {}, expected {}".format( | ||
type(file_name), str | ||
) | ||
) | ||
if not isinstance(layout, str): | ||
raise TypeError( | ||
"Unsupported type for argument layout. Got {}, expected {}".format( | ||
type(layout), str | ||
) | ||
) | ||
if not isinstance(color_space, str): | ||
raise TypeError( | ||
"Unsupported type for argument color_space. Got {}, expected {}".format( | ||
type(color_space), str | ||
) | ||
) | ||
self.__impl = _zivid.point_cloud_export.file_format.PLY( | ||
file_name, | ||
PLY.Layout._to_internal(layout), | ||
ColorSpace._to_internal(color_space), | ||
) | ||
|
||
def __str__(self): | ||
return str(self.__impl) | ||
|
||
|
||
class XYZ: | ||
"""Specification for saving frame in ASCII (*.xyz) format | ||
ASCII characters are used to store cartesian coordinates of XYZ points and RGB color values. | ||
""" | ||
|
||
def __init__(self, file_name, color_space=ColorSpace.srgb): | ||
"""Create a XYZ file format specification with file name. | ||
Sets color space to linear RGB. | ||
Args: | ||
file_name: File name. | ||
color_space: Color space of point cloud. Default is sRGB. | ||
""" | ||
if not isinstance(file_name, str): | ||
raise TypeError( | ||
"Unsupported type for argument file_name. Got {}, expected {}".format( | ||
type(file_name), str | ||
) | ||
) | ||
if not isinstance(color_space, str): | ||
raise TypeError( | ||
"Unsupported type for argument color_space. Got {}, expected {}".format( | ||
type(color_space), str | ||
) | ||
) | ||
self.__impl = _zivid.point_cloud_export.file_format.XYZ( | ||
file_name, ColorSpace._to_internal(color_space) | ||
) | ||
|
||
def __str__(self): | ||
return str(self.__impl) | ||
|
||
|
||
class PCD: | ||
"""Specification for saving frame in PCD (*.pcd) format. | ||
PCD is a file format native to the Point Cloud Library (PCL). To learn more about | ||
the PCD file format, see | ||
https://pcl.readthedocs.io/projects/tutorials/en/latest/pcd_file_format.html#pcd-file-format. | ||
""" | ||
|
||
def __init__(self, file_name, color_space=ColorSpace.srgb): | ||
"""Create a PCD file format specification with file name. | ||
Args: | ||
file_name: File name. | ||
color_space: Color space of point cloud. Default is sRGB. | ||
""" | ||
if not isinstance(file_name, str): | ||
raise TypeError( | ||
"Unsupported type for argument file_name. Got {}, expected {}".format( | ||
type(file_name), str | ||
) | ||
) | ||
if not isinstance(color_space, str): | ||
raise TypeError( | ||
"Unsupported type for argument color_space. Got {}, expected {}".format( | ||
type(color_space), str | ||
) | ||
) | ||
self.__impl = _zivid.point_cloud_export.file_format.PCD( | ||
file_name, | ||
ColorSpace._to_internal(color_space), | ||
) | ||
|
||
def __str__(self): | ||
return str(self.__impl) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -135,7 +135,13 @@ def _main(): | |
author="Zivid AS", | ||
author_email="[email protected]", | ||
license="BSD 3-Clause", | ||
packages=["zivid", "zivid._calibration", "zivid.experimental", "_zivid"], | ||
packages=[ | ||
"zivid", | ||
"zivid._calibration", | ||
"zivid.experimental", | ||
"zivid.experimental.point_cloud_export", | ||
"_zivid", | ||
], | ||
package_dir={"": "modules"}, | ||
install_requires=["numpy"], | ||
cmake_args=[ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
#include <ZividPython/PointCloudExport.h> | ||
|
||
#include <ZividPython/ReleasableFrame.h> | ||
|
||
#include <utility> | ||
|
||
namespace py = pybind11; | ||
|
||
namespace | ||
{ | ||
template<typename FileFormat> | ||
auto wrapFileFormat(py::class_<FileFormat> pyClass) | ||
{ | ||
return pyClass.def(py::init<const std::string &>(), py::arg("file_name")) | ||
.def("to_string", &FileFormat::toString); | ||
} | ||
|
||
template<typename FileFormat> | ||
auto exportFrame(const ZividPython::ReleasableFrame &frame, const FileFormat &fileFormat) | ||
{ | ||
return Zivid::Experimental::PointCloudExport::exportFrame(frame.impl(), fileFormat); | ||
} | ||
} // namespace | ||
|
||
namespace ZividPython | ||
{ | ||
void wrapEnum(py::enum_<Zivid::Experimental::PointCloudExport::ColorSpace> pyEnum) | ||
{ | ||
pyEnum.value("srgb", Zivid::Experimental::PointCloudExport::ColorSpace::sRGB) | ||
.value("linear_rgb", Zivid::Experimental::PointCloudExport::ColorSpace::linearRGB) | ||
.export_values(); | ||
} | ||
|
||
void wrapClass(py::class_<Zivid::Experimental::PointCloudExport::FileFormat::ZDF> pyClass) | ||
{ | ||
wrapFileFormat(std::move(pyClass)); | ||
} | ||
|
||
void wrapClass(py::class_<Zivid::Experimental::PointCloudExport::FileFormat::PLY> pyClass) | ||
{ | ||
using Layout = Zivid::Experimental::PointCloudExport::FileFormat::PLY::Layout; | ||
ZIVID_PYTHON_WRAP_ENUM_CLASS(pyClass, Layout); | ||
|
||
wrapFileFormat(std::move(pyClass)) | ||
.def(py::init<const std::string &, Layout, Zivid::Experimental::PointCloudExport::ColorSpace>(), | ||
py::arg("file_name"), | ||
py::arg("layout"), | ||
py::arg("color_space")); | ||
} | ||
|
||
void wrapEnum(py::enum_<Zivid::Experimental::PointCloudExport::FileFormat::PLY::Layout> pyEnum) | ||
{ | ||
pyEnum.value("ordered", Zivid::Experimental::PointCloudExport::FileFormat::PLY::Layout::ordered) | ||
.value("unordered", Zivid::Experimental::PointCloudExport::FileFormat::PLY::Layout::unordered) | ||
.export_values(); | ||
} | ||
|
||
void wrapClass(py::class_<Zivid::Experimental::PointCloudExport::FileFormat::XYZ> pyClass) | ||
{ | ||
wrapFileFormat(std::move(pyClass)) | ||
.def(py::init<const std::string &, Zivid::Experimental::PointCloudExport::ColorSpace>(), | ||
py::arg("file_name"), | ||
py::arg("color_space")); | ||
} | ||
|
||
void wrapClass(py::class_<Zivid::Experimental::PointCloudExport::FileFormat::PCD> pyClass) | ||
{ | ||
wrapFileFormat(std::move(pyClass)) | ||
.def(py::init<const std::string &, Zivid::Experimental::PointCloudExport::ColorSpace>(), | ||
py::arg("file_name"), | ||
py::arg("color_space")); | ||
} | ||
|
||
namespace PointCloudExport | ||
{ | ||
namespace FileFormat | ||
{ | ||
void wrapAsSubmodule(py::module &dest) | ||
{ | ||
using ZDF = Zivid::Experimental::PointCloudExport::FileFormat::ZDF; | ||
ZIVID_PYTHON_WRAP_CLASS(dest, ZDF); | ||
|
||
using PLY = Zivid::Experimental::PointCloudExport::FileFormat::PLY; | ||
ZIVID_PYTHON_WRAP_CLASS(dest, PLY); | ||
|
||
using XYZ = Zivid::Experimental::PointCloudExport::FileFormat::XYZ; | ||
ZIVID_PYTHON_WRAP_CLASS(dest, XYZ); | ||
|
||
using PCD = Zivid::Experimental::PointCloudExport::FileFormat::PCD; | ||
ZIVID_PYTHON_WRAP_CLASS(dest, PCD); | ||
} | ||
} // namespace FileFormat | ||
|
||
void wrapAsSubmodule(py::module &dest) | ||
{ | ||
using ColorSpace = Zivid::Experimental::PointCloudExport::ColorSpace; | ||
ZIVID_PYTHON_WRAP_ENUM_CLASS(dest, ColorSpace); | ||
|
||
wrapNamespaceAsSubmodule(dest, FileFormat::wrapAsSubmodule, "FileFormat"); | ||
|
||
dest.def("export_frame", | ||
py::overload_cast<const ReleasableFrame &, | ||
const Zivid::Experimental::PointCloudExport::FileFormat::ZDF &>( | ||
&exportFrame<Zivid::Experimental::PointCloudExport::FileFormat::ZDF>)) | ||
.def("export_frame", | ||
py::overload_cast<const ReleasableFrame &, | ||
const Zivid::Experimental::PointCloudExport::FileFormat::PLY &>( | ||
&exportFrame<Zivid::Experimental::PointCloudExport::FileFormat::PLY>)) | ||
.def("export_frame", | ||
py::overload_cast<const ReleasableFrame &, | ||
const Zivid::Experimental::PointCloudExport::FileFormat::XYZ &>( | ||
&exportFrame<Zivid::Experimental::PointCloudExport::FileFormat::XYZ>)) | ||
.def("export_frame", | ||
py::overload_cast<const ReleasableFrame &, | ||
const Zivid::Experimental::PointCloudExport::FileFormat::PCD &>( | ||
&exportFrame<Zivid::Experimental::PointCloudExport::FileFormat::PCD>)); | ||
} | ||
} // namespace PointCloudExport | ||
} // namespace ZividPython |
Oops, something went wrong.