Skip to content

Commit

Permalink
Add new capture methods capture2d/capture3d/capture2d3d
Browse files Browse the repository at this point in the history
These methods are intended to replace `capture` which is now deprecated.
  • Loading branch information
johningve committed Nov 28, 2024
1 parent fd763de commit 34c46f0
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 1 deletion.
125 changes: 124 additions & 1 deletion modules/zivid/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,127 @@ def __str__(self):
def __eq__(self, other):
return self.__impl == other._Camera__impl

def capture2d3d(self, settings):
"""Capture a 2D+3D frame.
This method captures both a 3D point cloud and a 2D color image. Use this method when you want to capture
colored point clouds. This method will throw if `Settings.color` is not set. Use `capture3d` for capturing a 3D
point cloud without a 2D color image.
These remarks below apply for all capture functions:
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
patterns. Therefore, after this method has returned, the camera can be moved, or objects in the scene can be
moved, or a capture from another camera with overlapping field of view can be triggered, without affecting the
point cloud.
When this method returns, there is still remaining data to transfer from the camera to the PC, and the
processing of the final point cloud is not completed. Transfer and processing of the point cloud will continue
in the background. When you call a method on the returned `Frame` object that requires the capture to be
finished, for example `Frame.point_cloud`, that method will block until the processing is finished and the point
cloud is available. If an exception occurs after the acquisition of images is complete (during transfer or
processing of the capture), then that exception is instead thrown when you access the `Frame` object.
The capture functions can be invoked back-to-back, for doing rapid back-to-back acquisition of multiple (2D or
3D) captures on the same camera. This is for example useful if you want to do one high-resolution 2D capture
followed by a lower-resolution 3D capture. The acquisition of the next capture will begin quickly after
acquisition of the previous capture completed, even when there is remaining transfer and processing for the
first capture. This allows pipelining several 2D and/or 3D captures, by doing acquisition in parallel with data
transfer and processing.
Note: There can be maximum of two in-progress uncompleted 3D (or 2D+3D) captures simultaneously per Zivid
camera. If you invoke `capture2d3d` or `capture3d` when there are two uncompleted 3D captures in-progress, then
the capture will not start until the first of the in-progress 3D captures has finished all transfer and
processing. There is a similar limit of maximum two in-process 2D captures per camera.
Capture functions can also be called on multiple cameras simultaneously. However, if the cameras have
overlapping field-of-view then you need to take consideration and sequence the capture calls to avoid the
captures interfering with each other.
Args:
settings: Settings to use for the capture.
Returns:
A frame containing a 3D point cloud, a 2D color image, and metadata.
Raises:
TypeError: If the settings argument is not a Settings instance.
"""
if not isinstance(settings, Settings):
raise TypeError(
"Unsupported type for argument settings. Got {}, expected {}.".format(
type(settings), Settings.__name__
)
)
return Frame(self.__impl.capture2D3D(_to_internal_settings(settings)))

def capture3d(self, settings):
"""Capture a single 3D frame.
This method is used to capture a 3D frame without a 2D color image. It ignores all color settings in the input
settings. See `capture2d3d` for capturing a 2D+3D frame.
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
patterns. For more information, see the remarks section of `capture2d3d` above. Those remarks apply for both 2D,
3D, and 2D+3D captures.
Args:
settings: Settings to use for the capture.
Returns:
A frame containing a 3D point cloud and metadata.
Raises:
TypeError: If the settings argument is not a Settings
"""
if not isinstance(settings, Settings):
raise TypeError(
"Unsupported type for argument settings. Got {}, expected {}.".format(
type(settings), Settings.__name__
)
)
return Frame(self.__impl.capture3D(_to_internal_settings(settings)))

def capture2d(self, settings):
"""Capture a single 2D frame.
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
patterns. For more information, see the remarks section of `capture2d3d` above. Those remarks apply for both 2D,
3D, and 2D+3D captures.
This overload is provided for convenience. Note that only the Settings2D part under `Settings.color` will be
used for the capture. The other parts of the settings will be ignored.
This method will throw if `Settings.color` is not set.
Args:
settings: Settings to use for the capture. Can be either a Settings2D instance or a Settings instance.
Returns:
A Frame2D containing a 2D image and metadata
Raises:
TypeError: If the settings argument is not a Settings2D or a Settings
"""
if isinstance(settings, Settings2D):
return Frame2D(self.__impl.capture2D(_to_internal_settings2d(settings)))
if isinstance(settings, Settings):
return Frame2D(self.__impl.capture2D(_to_internal_settings(settings)))
raise TypeError(
"Unsupported settings type, expected: {expected_types}, got: {value_type}".format(
expected_types=" or ".join([Settings.__name__, Settings2D.__name__]),
value_type=type(settings),
)
)

def capture(self, settings):
"""Capture a single frame or a single 2D frame.
This method is deprecated as of SDK 2.14, and will be removed in the next SDK major version (3.0). Use
`capture2d3d` instead for capturing 2D+3D frames, use `capture3d` for capturing 3D frames without a 2D color
image, or use `capture2d` for capturing a 2D color image only.
This method shares the common remarks about capture functions as found under `capture2d3d`.
Args:
settings: Settings to be used to capture. Can be either a Settings or Settings2D instance
Expand All @@ -63,7 +181,12 @@ def capture(self, settings):
return Frame(self.__impl.capture(_to_internal_settings(settings)))
if isinstance(settings, Settings2D):
return Frame2D(self.__impl.capture(_to_internal_settings2d(settings)))
raise TypeError("Unsupported settings type: {}".format(type(settings)))
raise TypeError(
"Unsupported settings type, expected: {expected_types}, got: {value_type}".format(
expected_types=" or ".join([Settings.__name__, Settings2D.__name__]),
value_type=type(settings),
)
)

@property
def info(self):
Expand Down
6 changes: 6 additions & 0 deletions src/ReleasableCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ namespace ZividPython
.def(py::self != py::self) // NOLINT
.def("disconnect", &ReleasableCamera::disconnect)
.def("connect", &ReleasableCamera::connect)
.def("capture2D3D", &ReleasableCamera::capture2D3D)
.def("capture3D", &ReleasableCamera::capture3D)
.def("capture2D", py::overload_cast<const Zivid::Settings2D &>(&ReleasableCamera::capture2D),
py::arg("settings_2d"))
.def("capture2D", py::overload_cast<const Zivid::Settings &>(&ReleasableCamera::capture2D),
py::arg("settings"))
.def("capture", py::overload_cast<const Zivid::Settings &>(&ReleasableCamera::capture), py::arg("settings"))
.def("capture",
py::overload_cast<const Zivid::Settings2D &>(&ReleasableCamera::capture),
Expand Down
4 changes: 4 additions & 0 deletions src/include/ZividPython/ReleasableCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ namespace ZividPython
ZIVID_PYTHON_ADD_COMPARE(!=)
ZIVID_PYTHON_FORWARD_0_ARGS_WRAP_RETURN(ReleasableCamera, connect)
ZIVID_PYTHON_FORWARD_0_ARGS(disconnect)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture2D3D, const Zivid::Settings &, settings)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture3D, const Zivid::Settings &, settings)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture2D, const Zivid::Settings2D &, settings2D)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture2D, const Zivid::Settings &, settings)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture, const Zivid::Settings &, settings)
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture, const Zivid::Settings2D &, settings2D)
ZIVID_PYTHON_FORWARD_0_ARGS(state)
Expand Down
86 changes: 86 additions & 0 deletions test/test_camera_capture.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,92 @@
import pytest


def test_capture2d3d_one_2d_and_one_3d(shared_file_camera):
import zivid

acquisitions3d = [zivid.Settings.Acquisition()]
acquisitions2d = [zivid.Settings2D.Acquisition()]
settings = zivid.Settings(
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
)

with shared_file_camera.capture2d3d(settings) as frame:
assert frame
assert isinstance(frame, zivid.frame.Frame)


def test_capture2d3d_two_2d_and_one_3d(shared_file_camera):
import zivid

acquisitions3d = [zivid.Settings.Acquisition()]
acquisitions2d = [zivid.Settings2D.Acquisition(), zivid.Settings2D.Acquisition()]
settings = zivid.Settings(
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
)

with shared_file_camera.capture2d3d(settings) as frame:
assert frame
assert isinstance(frame, zivid.frame.Frame)


def test_capture2d3d_one_2d_and_two_3d(shared_file_camera):
import zivid

acquisitions3d = [zivid.Settings.Acquisition(), zivid.Settings.Acquisition()]
acquisitions2d = [zivid.Settings2D.Acquisition()]
settings = zivid.Settings(
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
)

with shared_file_camera.capture2d3d(settings) as frame:
assert frame
assert isinstance(frame, zivid.frame.Frame)


def test_capture2d3d_two_2d_and_two_3d(shared_file_camera):
import zivid

acquisitions3d = [zivid.Settings.Acquisition(), zivid.Settings.Acquisition()]
acquisitions2d = [zivid.Settings2D.Acquisition(), zivid.Settings2D.Acquisition()]
settings = zivid.Settings(
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
)

with shared_file_camera.capture2d3d(settings) as frame:
assert frame
assert isinstance(frame, zivid.frame.Frame)


def test_capture3d_one_acquisition(shared_file_camera):
import zivid

acquisitions = [zivid.Settings.Acquisition()]
settings = zivid.Settings(acquisitions=acquisitions)
with shared_file_camera.capture3d(settings) as frame:
assert frame
assert isinstance(frame, zivid.frame.Frame)


def test_capture2d_with_settings2d(shared_file_camera):
import zivid

acquisitions = [zivid.Settings2D.Acquisition()]
settings = zivid.Settings2D(acquisitions=acquisitions)
with shared_file_camera.capture2d(settings) as frame:
assert frame
assert isinstance(frame, zivid.Frame2D)


def test_capture2d_with_settings(shared_file_camera):
import zivid

acquisitions = [zivid.Settings2D.Acquisition()]
settings = zivid.Settings(color=zivid.Settings2D(acquisitions=acquisitions))
with shared_file_camera.capture2d(settings) as frame:
assert frame
assert isinstance(frame, zivid.Frame2D)


def test_one_acquisition_in_list(shared_file_camera):
import zivid

Expand Down

0 comments on commit 34c46f0

Please sign in to comment.