Skip to content

Commit

Permalink
Implement point_cloud.copy_image() function
Browse files Browse the repository at this point in the history
This is equivalent to C++ API `PointCloud::copyImageRGBA`,
`PointCloud::copyImageBGRA` and `PointCloud::copyImageSRGB`. The
function accepts a color format as an argument and returns `Image`
object with the specified color format. This is helpful when saving a
color image from point cloud data.
  • Loading branch information
vawale committed Dec 10, 2024
1 parent 4236a49 commit ae571af
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 4 deletions.
34 changes: 34 additions & 0 deletions modules/zivid/point_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import numpy

import _zivid
from zivid.image import Image


class PointCloud:
Expand Down Expand Up @@ -102,6 +103,39 @@ def copy_data(self, data_format):
) from ex
return numpy.array(data_format_class(self.__impl))

def copy_image(self, data_format):
"""Copy the point cloud colors as 8-bit image in input format.
Supported data formats:
rgba: Image(Height,Width,4) of uint8
bgra: Image(Height,Width,4) of uint8
srgb: Image(Height,Width,4) of uint8
Args:
data_format: A string specifying the image data format
Returns:
An image instance containing color data
Raises:
ValueError: if the requested data format does not exist
"""
self.__impl.assert_not_released()

supported_color_formats = ["rgba", "bgra", "srgb"]

if data_format == "rgba":
return Image(self.__impl.copy_image_rgba())
if data_format == "bgra":
return Image(self.__impl.copy_image_bgra())
if data_format == "srgb":
return Image(self.__impl.copy_image_srgb())
raise ValueError(
"Unsupported color format: {data_format}. Supported formats: {all_formats}".format(
data_format=data_format, all_formats=supported_color_formats
)
)

def transform(self, matrix):
"""Transform the point cloud in-place by a 4x4 transformation matrix.
Expand Down
12 changes: 8 additions & 4 deletions src/ReleasablePointCloud.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <ZividPython/Matrix.h>
#include <ZividPython/ReleasablePointCloud.h>

#include <Zivid/PointCloud.h>
#include <ZividPython/Matrix.h>

#include <pybind11/pybind11.h>

Expand All @@ -22,9 +22,13 @@ namespace ZividPython
[](ReleasablePointCloud &pointCloud, Zivid::PointCloud::Downsampling downsampling) {
pointCloud.downsample(downsampling);
})
.def("downsampled", [](ReleasablePointCloud &pointCloud, Zivid::PointCloud::Downsampling downsampling) {
return pointCloud.downsampled(downsampling);
});
.def("downsampled",
[](ReleasablePointCloud &pointCloud, Zivid::PointCloud::Downsampling downsampling) {
return pointCloud.downsampled(downsampling);
})
.def("copy_image_rgba", &ReleasablePointCloud::copyImageRGBA)
.def("copy_image_bgra", &ReleasablePointCloud::copyImageBGRA)
.def("copy_image_srgb", &ReleasablePointCloud::copyImageSRGB);

py::enum_<Zivid::PointCloud::Downsampling>{ pyClass, "Downsampling" }
.value("by2x2", Zivid::PointCloud::Downsampling::by2x2)
Expand Down
4 changes: 4 additions & 0 deletions src/include/ZividPython/ReleasablePointCloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <Zivid/PointCloud.h>
#include <ZividPython/Releasable.h>
#include <ZividPython/ReleasableImage.h>
#include <ZividPython/Wrappers.h>

namespace ZividPython
Expand All @@ -19,6 +20,9 @@ namespace ZividPython
downsampled,
Zivid::PointCloud::Downsampling,
downsampling)
ZIVID_PYTHON_FORWARD_0_ARGS_WRAP_RETURN(ReleasableImageRGBA, copyImageRGBA)
ZIVID_PYTHON_FORWARD_0_ARGS_WRAP_RETURN(ReleasableImageBGRA, copyImageBGRA)
ZIVID_PYTHON_FORWARD_0_ARGS_WRAP_RETURN(ReleasableImageSRGB, copyImageSRGB)
};

void wrapClass(pybind11::class_<ReleasablePointCloud> pyClass);
Expand Down
35 changes: 35 additions & 0 deletions test/test_point_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,41 @@ def test_point_cloud_rgba(point_cloud):
np.testing.assert_array_equal(bgra[:, :, 3], rgba[:, :, 3])


def test_point_cloud_copy_image(point_cloud):
import numpy as np
import zivid

image_rgba = point_cloud.copy_image("rgba")
assert isinstance(image_rgba, zivid.Image)
assert image_rgba.height == point_cloud.height
assert image_rgba.width == point_cloud.width

image_bgra = point_cloud.copy_image("bgra")
assert isinstance(image_bgra, zivid.Image)
assert image_bgra.height == point_cloud.height
assert image_bgra.width == point_cloud.width

image_srgb = point_cloud.copy_image("srgb")
assert isinstance(image_srgb, zivid.Image)
assert image_srgb.height == point_cloud.height
assert image_srgb.width == point_cloud.width

rgba = point_cloud.copy_data("rgba")
np.testing.assert_array_equal(image_rgba.copy_data(), rgba)

bgra = point_cloud.copy_data("bgra")
np.testing.assert_array_equal(image_bgra.copy_data(), bgra)

srgb = point_cloud.copy_data("srgb")
np.testing.assert_array_equal(image_srgb.copy_data(), srgb)

# Check errors when argument is wrong or missing
with pytest.raises(ValueError):
point_cloud.copy_image("bogus-format")
with pytest.raises(TypeError):
point_cloud.copy_image()


def test_point_cloud_normals(point_cloud):
import numpy as np

Expand Down

0 comments on commit ae571af

Please sign in to comment.