Skip to content

Commit 97d4c8d

Browse files
committed
Add new capture methods
This commit adds the capture methods `capture_2d`, `capture_3d`, and `capture_2d_3d`. These methods are intended to replace `capture` which is now deprecated.
1 parent f5199b8 commit 97d4c8d

File tree

4 files changed

+236
-1
lines changed

4 files changed

+236
-1
lines changed

modules/zivid/camera.py

+122-1
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,125 @@ def __str__(self):
4848
def __eq__(self, other):
4949
return self.__impl == other._Camera__impl
5050

51+
def capture_2d_3d(self, settings):
52+
"""Capture a 2D+3D frame.
53+
54+
This method captures both a 3D point cloud and a 2D color image. Use this method when you want to capture
55+
colored point clouds. This method will throw if `Settings.color` is not set. Use `capture_3d` for capturing a 3D
56+
point cloud without a 2D color image.
57+
58+
These remarks below apply for all capture functions:
59+
60+
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
61+
patterns. Therefore, after this method has returned, the camera can be moved, or objects in the scene can be
62+
moved, or a capture from another camera with overlapping field of view can be triggered, without affecting the
63+
point cloud.
64+
65+
When this method returns, there is still remaining data to transfer from the camera to the PC, and the
66+
processing of the final point cloud is not completed. Transfer and processing of the point cloud will continue
67+
in the background. When you call a method on the returned `Frame` object that requires the capture to be
68+
finished, for example `Frame.point_cloud`, that method will block until the processing is finished and the point
69+
cloud is available. If an exception occurs after the acquisition of images is complete (during transfer or
70+
processing of the capture), then that exception is instead thrown when you access the `Frame` object.
71+
72+
The capture functions can be invoked back-to-back, for doing rapid back-to-back acquisition of multiple (2D or
73+
3D) captures on the same camera. This is for example useful if you want to do one high-resolution 2D capture
74+
followed by a lower-resolution 3D capture. The acquisition of the next capture will begin quickly after
75+
acquisition of the previous capture completed, even when there is remaining transfer and processing for the
76+
first capture. This allows pipelining several 2D and/or 3D captures, by doing acquisition in parallel with data
77+
transfer and processing.
78+
79+
Note: There can be maximum of two in-progress uncompleted 3D (or 2D+3D) captures simultaneously per Zivid
80+
camera. If you invoke `capture_2d_3d` or `capture_3d` when there are two uncompleted 3D captures in-progress,
81+
then the capture will not start until the first of the in-progress 3D captures has finished all transfer and
82+
processing. There is a similar limit of maximum two in-process 2D captures per camera.
83+
84+
Capture functions can also be called on multiple cameras simultaneously. However, if the cameras have
85+
overlapping field-of-view then you need to take consideration and sequence the capture calls to avoid the
86+
captures interfering with each other.
87+
88+
Args:
89+
settings: Settings to use for the capture.
90+
91+
Returns:
92+
A frame containing a 3D point cloud, a 2D color image, and metadata.
93+
94+
Raises:
95+
TypeError: If the settings argument is not a Settings instance.
96+
"""
97+
if not isinstance(settings, Settings):
98+
raise TypeError(
99+
"Unsupported type for argument settings. Got {}, expected {}.".format(
100+
type(settings), Settings.__name__
101+
)
102+
)
103+
return Frame(self.__impl.capture_2d_3d(_to_internal_settings(settings)))
104+
105+
def capture_3d(self, settings):
106+
"""Capture a single 3D frame.
107+
108+
This method is used to capture a 3D frame without a 2D color image. It ignores all color settings in the input
109+
settings. See `capture_2d_3d` for capturing a 2D+3D frame.
110+
111+
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
112+
patterns. For more information, see the remarks section of `capture_2d_3d` above. Those remarks apply for both
113+
2D, 3D, and 2D+3D captures.
114+
115+
Args:
116+
settings: Settings to use for the capture.
117+
118+
Returns:
119+
A frame containing a 3D point cloud and metadata.
120+
121+
Raises:
122+
TypeError: If the settings argument is not a Settings
123+
"""
124+
if not isinstance(settings, Settings):
125+
raise TypeError(
126+
"Unsupported type for argument settings. Got {}, expected {}.".format(
127+
type(settings), Settings.__name__
128+
)
129+
)
130+
return Frame(self.__impl.capture_3d(_to_internal_settings(settings)))
131+
132+
def capture_2d(self, settings):
133+
"""Capture a single 2D frame.
134+
135+
This method returns right after the acquisition of the images is complete, and the camera has stopped projecting
136+
patterns. For more information, see the remarks section of `capture_2d_3d` above. Those remarks apply for both
137+
2D, 3D, and 2D+3D captures.
138+
139+
Args:
140+
settings: Settings to use for the capture. Can be either a Settings2D instance or a Settings instance.
141+
If a Settings instance is provided, only the Settings.color part is used. An exception is thrown
142+
if the Settings.color part is not set.
143+
144+
Returns:
145+
A Frame2D containing a 2D image and metadata
146+
147+
Raises:
148+
TypeError: If the settings argument is not a Settings2D or a Settings.
149+
"""
150+
if isinstance(settings, Settings2D):
151+
return Frame2D(self.__impl.capture_2d(_to_internal_settings2d(settings)))
152+
if isinstance(settings, Settings):
153+
return Frame2D(self.__impl.capture_2d(_to_internal_settings(settings)))
154+
raise TypeError(
155+
"Unsupported settings type, expected: {expected_types}, got: {value_type}".format(
156+
expected_types=" or ".join([Settings.__name__, Settings2D.__name__]),
157+
value_type=type(settings),
158+
)
159+
)
160+
51161
def capture(self, settings):
52162
"""Capture a single frame or a single 2D frame.
53163
164+
This method is deprecated as of SDK 2.14, and will be removed in the next SDK major version (3.0). Use
165+
`capture_2d_3d` instead for capturing 2D+3D frames, use `capture_3d` for capturing 3D frames without a 2D color
166+
image, or use `capture_2d` for capturing a 2D color image only.
167+
168+
This method shares the common remarks about capture functions as found under `capture_2d_3d`.
169+
54170
Args:
55171
settings: Settings to be used to capture. Can be either a Settings or Settings2D instance
56172
@@ -64,7 +180,12 @@ def capture(self, settings):
64180
return Frame(self.__impl.capture(_to_internal_settings(settings)))
65181
if isinstance(settings, Settings2D):
66182
return Frame2D(self.__impl.capture(_to_internal_settings2d(settings)))
67-
raise TypeError("Unsupported settings type: {}".format(type(settings)))
183+
raise TypeError(
184+
"Unsupported settings type, expected: {expected_types}, got: {value_type}".format(
185+
expected_types=" or ".join([Settings.__name__, Settings2D.__name__]),
186+
value_type=type(settings),
187+
)
188+
)
68189

69190
@property
70191
def info(self):

src/ReleasableCamera.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ namespace ZividPython
1717
.def(py::self != py::self) // NOLINT
1818
.def("disconnect", &ReleasableCamera::disconnect)
1919
.def("connect", &ReleasableCamera::connect)
20+
.def("capture_2d_3d", &ReleasableCamera::capture2D3D)
21+
.def("capture_3d", &ReleasableCamera::capture3D)
22+
.def("capture_2d",
23+
py::overload_cast<const Zivid::Settings2D &>(&ReleasableCamera::capture2D),
24+
py::arg("settings_2d"))
25+
.def("capture_2d",
26+
py::overload_cast<const Zivid::Settings &>(&ReleasableCamera::capture2D),
27+
py::arg("settings"))
2028
.def("capture", py::overload_cast<const Zivid::Settings &>(&ReleasableCamera::capture), py::arg("settings"))
2129
.def("capture",
2230
py::overload_cast<const Zivid::Settings2D &>(&ReleasableCamera::capture),

src/include/ZividPython/ReleasableCamera.h

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace ZividPython
2020
ZIVID_PYTHON_ADD_COMPARE(!=)
2121
ZIVID_PYTHON_FORWARD_0_ARGS_WRAP_RETURN(ReleasableCamera, connect)
2222
ZIVID_PYTHON_FORWARD_0_ARGS(disconnect)
23+
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture2D3D, const Zivid::Settings &, settings)
24+
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture3D, const Zivid::Settings &, settings)
25+
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture2D, const Zivid::Settings2D &, settings2D)
26+
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture2D, const Zivid::Settings &, settings)
2327
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame, capture, const Zivid::Settings &, settings)
2428
ZIVID_PYTHON_FORWARD_1_ARGS_WRAP_RETURN(ReleasableFrame2D, capture, const Zivid::Settings2D &, settings2D)
2529
ZIVID_PYTHON_FORWARD_0_ARGS(state)

test/test_camera_capture.py

+102
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,108 @@
11
import pytest
22

33

4+
def test_capture_2d_3d_one_2d_and_one_3d(shared_file_camera):
5+
import zivid
6+
7+
acquisitions3d = [zivid.Settings.Acquisition()]
8+
acquisitions2d = [zivid.Settings2D.Acquisition()]
9+
settings = zivid.Settings(
10+
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
11+
)
12+
13+
with shared_file_camera.capture_2d_3d(settings) as frame:
14+
assert frame
15+
assert isinstance(frame, zivid.frame.Frame)
16+
assert len(frame.settings.acquisitions) == 1
17+
assert frame.settings.color
18+
assert len(frame.settings.color.acquisitions) == 1
19+
20+
21+
def test_capture_2d_3d_two_2d_and_one_3d(shared_file_camera):
22+
import zivid
23+
24+
acquisitions3d = [zivid.Settings.Acquisition()]
25+
acquisitions2d = [zivid.Settings2D.Acquisition(), zivid.Settings2D.Acquisition()]
26+
settings = zivid.Settings(
27+
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
28+
)
29+
30+
with shared_file_camera.capture_2d_3d(settings) as frame:
31+
assert frame
32+
assert isinstance(frame, zivid.frame.Frame)
33+
assert len(frame.settings.acquisitions) == 1
34+
assert frame.settings.color
35+
assert len(frame.settings.color.acquisitions) == 2
36+
37+
38+
def test_capture_2d_3d_one_2d_and_two_3d(shared_file_camera):
39+
import zivid
40+
41+
acquisitions3d = [zivid.Settings.Acquisition(), zivid.Settings.Acquisition()]
42+
acquisitions2d = [zivid.Settings2D.Acquisition()]
43+
settings = zivid.Settings(
44+
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
45+
)
46+
47+
with shared_file_camera.capture_2d_3d(settings) as frame:
48+
assert frame
49+
assert isinstance(frame, zivid.frame.Frame)
50+
assert len(frame.settings.acquisitions) == 2
51+
assert frame.settings.color
52+
assert len(frame.settings.color.acquisitions) == 1
53+
54+
55+
def test_capture_2d_3d_two_2d_and_two_3d(shared_file_camera):
56+
import zivid
57+
58+
acquisitions3d = [zivid.Settings.Acquisition(), zivid.Settings.Acquisition()]
59+
acquisitions2d = [zivid.Settings2D.Acquisition(), zivid.Settings2D.Acquisition()]
60+
settings = zivid.Settings(
61+
acquisitions=acquisitions3d, color=zivid.Settings2D(acquisitions=acquisitions2d)
62+
)
63+
64+
with shared_file_camera.capture_2d_3d(settings) as frame:
65+
assert frame
66+
assert isinstance(frame, zivid.frame.Frame)
67+
assert len(frame.settings.acquisitions) == 2
68+
assert frame.settings.color
69+
assert len(frame.settings.color.acquisitions) == 2
70+
71+
72+
def test_capture_3d_one_acquisition(shared_file_camera):
73+
import zivid
74+
75+
acquisitions = [zivid.Settings.Acquisition()]
76+
settings = zivid.Settings(acquisitions=acquisitions)
77+
with shared_file_camera.capture_3d(settings) as frame:
78+
assert frame
79+
assert isinstance(frame, zivid.frame.Frame)
80+
assert len(frame.settings.acquisitions) == 1
81+
assert frame.settings.color is None
82+
83+
84+
def test_capture_2d_with_settings_2d(shared_file_camera):
85+
import zivid
86+
87+
acquisitions = [zivid.Settings2D.Acquisition()]
88+
settings = zivid.Settings2D(acquisitions=acquisitions)
89+
with shared_file_camera.capture_2d(settings) as frame:
90+
assert frame
91+
assert isinstance(frame, zivid.Frame2D)
92+
assert len(frame.settings.acquisitions) == 1
93+
94+
95+
def test_capture_2d_with_settings(shared_file_camera):
96+
import zivid
97+
98+
acquisitions = [zivid.Settings2D.Acquisition()]
99+
settings = zivid.Settings(color=zivid.Settings2D(acquisitions=acquisitions))
100+
with shared_file_camera.capture_2d(settings) as frame:
101+
assert frame
102+
assert isinstance(frame, zivid.Frame2D)
103+
assert len(frame.settings.acquisitions) == 1
104+
105+
4106
def test_one_acquisition_in_list(shared_file_camera):
5107
import zivid
6108

0 commit comments

Comments
 (0)