Skip to content

Commit 3111d23

Browse files
csu-bot-zividandersfagerli
authored andcommitted
Samples: Automatic updates to public repository
This commit modifies capture_from_file_camera.py, allowing file camera to be loaded from client input, which is useful since file cameras are now available for each Zivid camera model. If a ZDF file is saved with diagnostics mode on, the Zivid CSU team can create a Zivid file camera and send it to you. This commit adds capture_from_file_camera_vis_3d.py, which is the same as capture_from_file_camera.py but with visualization. The capture tutorial is updated to support the new file cameras. This commit updates roi_box_via_checkerboard.py to use the newly added Zivid SDK ROI feature. The option to estimate intrinsics from the point cloud is added to get_camera_intrinsics.py. This commit also modifies sample descriptions and standardizes variable names across the samples.
1 parent 2c010de commit 3111d23

12 files changed

Lines changed: 300 additions & 227 deletions

File tree

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ max-args=7
1313
max-locals=20
1414
max-returns=9
1515
max-bool-expr=6
16-
max-statements=55
16+
max-statements=60
1717

1818
[FORMAT]
1919
max-line-length=225

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ from the camera can be used.
4545
from YML file.
4646
- [capture\_assistant](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/basic/capture_assistant.py) - Use Capture Assistant to capture point clouds, with color,
4747
from the Zivid camera.
48-
- [capture\_from\_file\_camera](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/basic/capture_from_file_camera.py) - Capture point clouds, with color, from the Zivid file
48+
- [capture\_from\_file\_camera](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/basic/capture_from_file_camera.py) - Capture point clouds, with color, with the Zivid file
4949
camera.
5050
- [capture\_hdr](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/basic/capture_hdr.py) - Capture point clouds, with color, from the Zivid camera.
5151
- [capture\_hdr\_complete\_settings](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/basic/capture_hdr_complete_settings.py) - Capture point clouds, with color, from the Zivid camera
@@ -64,19 +64,21 @@ from the camera can be used.
6464
with settings from YML file and diagnostics enabled.
6565
- [firmware\_updater](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/firmware_updater.py) - Update firmware on the Zivid camera.
6666
- [get\_camera\_intrinsics](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/get_camera_intrinsics.py) - Read intrinsic parameters from the Zivid camera (OpenCV
67-
model).
67+
model) or estimate them from the point cloud.
6868
- [print\_version\_info](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/print_version_info.py) - Print version information for Python, zivid-python and
6969
Zivid SDK, then list cameras and print camera info for each
7070
connected camera.
7171
- [warmup](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/warmup.py) - A basic warm-up method for a Zivid camera with specified
7272
time and capture cycle.
7373
- **maintenance**
7474
- [correct\_camera\_in\_field](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/maintenance/correct_camera_in_field.py) - Correct the dimension trueness of a Zivid camera.
75-
- [reset\_camera\_in\_field](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/maintenance/reset_camera_in_field.py) - Reset in-field correction on a camera.
75+
- [reset\_camera\_in\_field](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/maintenance/reset_camera_in_field.py) - Reset infield correction on a camera.
7676
- [verify\_camera\_in\_field](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/maintenance/verify_camera_in_field.py) - Check the dimension trueness of a Zivid camera.
7777
- **applications**
7878
- **basic**
7979
- **visualization**
80+
- [capture\_from\_file\_camera\_vis\_3d](https://github.com/zivid/zivid-python-samples/tree/master//source/applications/basic/visualization/capture_from_file_camera_vis_3d.py) - Capture point clouds, with color, with the Zivid file
81+
camera.
8082
- [capture\_hdr\_vis\_normals](https://github.com/zivid/zivid-python-samples/tree/master//source/applications/basic/visualization/capture_hdr_vis_normals.py) - Capture Zivid point clouds, compute normals and
8183
convert to color map and display.
8284
- [capture\_vis\_3d](https://github.com/zivid/zivid-python-samples/tree/master//source/applications/basic/visualization/capture_vis_3d.py) - Capture point clouds, with color, from the Zivid

source/applications/advanced/hand_eye_calibration/ur_hand_eye_calibration/universal_robots_perform_hand_eye_calibration.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,11 @@ def perform_hand_eye_calibration(
399399
raise RuntimeError(f"Failed to detect feature points from frame {frame_file_path}")
400400

401401
print(f"Read robot pose from pos{idata:02d}.yaml")
402-
pose = load_and_assert_affine_matrix(pose_file_path)
402+
pose_matrix = load_and_assert_affine_matrix(pose_file_path)
403403

404-
calibration_inputs.append(zivid.calibration.HandEyeInput(pose, detection_result))
404+
calibration_inputs.append(
405+
zivid.calibration.HandEyeInput(zivid.calibration.Pose(pose_matrix), detection_result)
406+
)
405407
else:
406408
break
407409

source/applications/advanced/roi_box_via_checkerboard.py

Lines changed: 62 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,212 +1,101 @@
11
"""
22
Filter the point cloud based on a ROI box given relative to the Zivid Calibration Board.
33
4-
The ZDF file for this sample can be found under the main instructions for Zivid samples.
4+
The ZFC file for this sample can be downloaded from https://support.zivid.com/en/latest/api-reference/samples/sample-data.html.
55
66
"""
77

8-
import argparse
9-
from pathlib import Path
10-
from typing import Tuple
8+
from typing import List
119

1210
import numpy as np
1311
import zivid
1412
from sample_utils.display import display_depthmap, display_pointcloud
1513
from sample_utils.paths import get_sample_data_path
16-
from zivid.point_cloud import PointCloud
1714

1815

19-
def _options() -> argparse.Namespace:
20-
"""Function to read user arguments.
16+
def _transform_points(points: List[np.ndarray], transform: np.ndarray) -> List[np.ndarray]:
17+
"""Perform a homogenous transformation to every point in 'points' and return the transformed points.
18+
19+
Args:
20+
points: list of 3D points to be transformed
21+
transform: homogenous transform (4x4)
2122
2223
Returns:
23-
Arguments from user
24+
transformed_points: list of transformed 3D points
2425
2526
"""
26-
parser = argparse.ArgumentParser(description=__doc__)
27-
28-
parser.add_argument(
29-
"--zdf-path",
30-
required=False,
31-
type=Path,
32-
default=get_sample_data_path() / "BinWithCalibrationBoard.zdf",
33-
help="Path to the ZDF file",
34-
)
27+
rotation_matrix = transform[:3, :3]
28+
translation_vector = transform[:3, 3]
3529

36-
parser.add_argument(
37-
"--roi-box-bottom-left-corner-x",
38-
required=False,
39-
type=float,
40-
default=-80,
41-
help="Distance in X coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system",
42-
)
30+
transformed_points = []
31+
for point in points:
32+
transformed_points.append(rotation_matrix @ point + translation_vector)
4333

44-
parser.add_argument(
45-
"--roi-box-bottom-left-corner-y",
46-
required=False,
47-
type=float,
48-
default=280,
49-
help="Distance in Y coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system",
50-
)
34+
return transformed_points
5135

52-
parser.add_argument(
53-
"--roi-box-bottom-left-corner-z",
54-
required=False,
55-
type=float,
56-
default=5,
57-
help="Distance in Z coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system",
58-
)
5936

60-
parser.add_argument(
61-
"--box-dimension-in-axis-x",
62-
required=False,
63-
type=float,
64-
default=600,
65-
help="Bin dimension in X axis of the checkerboard coordinate system",
66-
)
67-
68-
parser.add_argument(
69-
"--box-dimension-in-axis-y",
70-
required=False,
71-
type=float,
72-
default=400,
73-
help="Bin dimension in Y axis of the checkerboard coordinate system",
74-
)
75-
76-
parser.add_argument(
77-
"--box-dimension-in-axis-z",
78-
required=False,
79-
type=float,
80-
default=80,
81-
help="Bin dimension in Z axis of the checkerboard coordinate system",
82-
)
37+
def _main() -> None:
38+
app = zivid.Application()
8339

84-
parser.add_argument(
85-
"--downsample",
86-
required=False,
87-
type=str,
88-
choices=["by2x2", "by3x3", "by4x4"],
89-
help="Downsampling rate; possible value: by2x2, by3x3, and by4x4",
90-
)
40+
file_camera = get_sample_data_path() / "BinWithCalibrationBoard.zfc"
9141

92-
return parser.parse_args()
42+
print(f"Creating virtual camera using file: {file_camera}")
43+
camera = app.create_file_camera(file_camera)
9344

45+
settings = zivid.Settings([zivid.Settings.Acquisition()])
9446

95-
def roi_box_point_cloud(
96-
point_cloud: PointCloud,
97-
roi_box_bottom_left_corner_x: float,
98-
roi_box_bottom_left_corner_y: float,
99-
roi_box_bottom_left_corner_z: float,
100-
box_dimension_in_axis_x: float,
101-
box_dimension_in_axis_y: float,
102-
box_dimension_in_axis_z: float,
103-
) -> Tuple[np.ndarray, np.ndarray]:
104-
"""Filter point cloud based on ROI box by providing box location and dimensions.
47+
original_point_cloud = camera.capture(settings).point_cloud()
10548

106-
This function assumes that the point cloud is transformed to the checkerboard frame.
49+
print("Displaying the original point cloud")
50+
display_pointcloud(original_point_cloud.copy_data("xyz"), original_point_cloud.copy_data("rgba")[:, :, :3])
10751

108-
Args:
109-
point_cloud: Zivid point cloud
110-
roi_box_bottom_left_corner_x: Distance in X coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system
111-
roi_box_bottom_left_corner_y: Distance in Y coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system
112-
roi_box_bottom_left_corner_z: Distance in Z coordinate from the board origin to the bottom left bin corner in checkerboard coordinate system
113-
box_dimension_in_axis_x: Bin dimension in X axis of the checkerboard coordinate system
114-
box_dimension_in_axis_y: Bin dimension in Y axis of the checkerboard coordinate system
115-
box_dimension_in_axis_z: Bin dimension in Z axis of the checkerboard coordinate system
52+
print("Configuring ROI box based on bin size and checkerboard placement")
53+
roi_box_length = 545
54+
roi_box_width = 345
55+
roi_box_height = 150
11656

117-
Returns:
118-
masked_xyz: A masked numpy array of X, Y and Z point cloud coordinates (HxWx3 ndarray)
119-
masked_rgba: A masked masked RGB image (HxWx3 ndarray)
57+
# Coordinates are relative to the checkerboard origin which lies in the intersection between the four checkers
58+
# in the top-left corner of the checkerboard: Positive x-axis is "East", y-axis is "South" and z-axis is "Down"
59+
roi_box_lower_right_corner = np.array([240, 260, 0.5])
60+
roi_box_upper_right_corner = np.array(
61+
[
62+
roi_box_lower_right_corner[0],
63+
roi_box_lower_right_corner[1] - roi_box_width,
64+
roi_box_lower_right_corner[2],
65+
]
66+
)
67+
roi_box_lower_left_corner = np.array(
68+
[roi_box_lower_right_corner[0] - roi_box_length, roi_box_lower_right_corner[1], roi_box_lower_right_corner[2]]
69+
)
12070

121-
"""
122-
xyz = point_cloud.copy_data("xyz")
123-
rgba = point_cloud.copy_data("rgba")
71+
point_o_in_checkerboard_frame = roi_box_lower_right_corner
72+
point_a_in_checkerboard_frame = roi_box_upper_right_corner
73+
point_b_in_checkerboard_frame = roi_box_lower_left_corner
12474

125-
masked_xyz = np.copy(xyz)
126-
masked_rgba = np.copy(rgba)
75+
print("Detecting and estimating pose of the Zivid checkerboard in the camera frame")
76+
detection_result = zivid.calibration.detect_feature_points(original_point_cloud)
77+
transform_checkerboard_to_camera = detection_result.pose().to_matrix()
12778

128-
# Creating ROI box mask
129-
margin_of_box_roi = 10
130-
mask_x = np.logical_and(
131-
xyz[:, :, 0] > roi_box_bottom_left_corner_x - margin_of_box_roi,
132-
xyz[:, :, 0] < roi_box_bottom_left_corner_x + box_dimension_in_axis_x + margin_of_box_roi,
133-
)
134-
mask_y = np.logical_and(
135-
xyz[:, :, 1] < roi_box_bottom_left_corner_y + margin_of_box_roi,
136-
xyz[:, :, 1] > roi_box_bottom_left_corner_y - box_dimension_in_axis_y - margin_of_box_roi,
137-
)
138-
mask_z = np.logical_and(
139-
xyz[:, :, 2] < roi_box_bottom_left_corner_z + margin_of_box_roi,
140-
xyz[:, :, 2] > roi_box_bottom_left_corner_z - box_dimension_in_axis_z - margin_of_box_roi,
79+
print("Transforming the ROI base frame points to the camera frame")
80+
roi_points_in_camera_frame = _transform_points(
81+
[point_o_in_checkerboard_frame, point_a_in_checkerboard_frame, point_b_in_checkerboard_frame],
82+
transform_checkerboard_to_camera,
14183
)
142-
mask = np.logical_and(np.logical_and(mask_x, mask_y), mask_z)
14384

144-
# Filtering out points outside the ROI box
145-
masked_xyz[~mask] = np.nan
146-
masked_rgba[~mask] = 0
85+
print("Setting the ROI")
86+
settings.region_of_interest.box.enabled = True
87+
settings.region_of_interest.box.point_o = roi_points_in_camera_frame[0]
88+
settings.region_of_interest.box.point_a = roi_points_in_camera_frame[1]
89+
settings.region_of_interest.box.point_b = roi_points_in_camera_frame[2]
90+
settings.region_of_interest.box.extents = (-10, roi_box_height)
14791

148-
return masked_xyz, masked_rgba
92+
roi_point_cloud = camera.capture(settings).point_cloud()
14993

94+
print("Displaying the ROI-filtered point cloud")
95+
display_pointcloud(roi_point_cloud.copy_data("xyz"), roi_point_cloud.copy_data("rgba")[:, :, :3])
15096

151-
def _main() -> None:
152-
153-
with zivid.Application():
154-
155-
user_options = _options()
156-
data_file = user_options.zdf_path
157-
print(f"Reading ZDF frame from file: {data_file}")
158-
frame = zivid.Frame(data_file)
159-
point_cloud = frame.point_cloud()
160-
161-
print("Displaying the point cloud original point cloud")
162-
display_pointcloud(point_cloud.copy_data("xyz"), point_cloud.copy_data("rgba")[:, :, 0:3])
163-
164-
if user_options.downsample:
165-
point_cloud.downsample(user_options.downsample)
166-
167-
print("Detecting and estimating pose of the Zivid checkerboard in the camera frame")
168-
detection_result = zivid.calibration.detect_feature_points(point_cloud)
169-
transform_camera_to_checkerboard = detection_result.pose().to_matrix()
170-
171-
print("Camera pose in checkerboard frame:")
172-
transform_checkerboard_to_camera = np.linalg.inv(transform_camera_to_checkerboard)
173-
print(transform_checkerboard_to_camera)
174-
175-
print("Transforming point cloud from camera frame to Checkerboard frame")
176-
point_cloud.transform(transform_checkerboard_to_camera)
177-
178-
print("Bottom-Left ROI Box corner:")
179-
roi_box_bottom_left_corner_x = user_options.roi_box_bottom_left_corner_x # Positive is "East"
180-
roi_box_bottom_left_corner_y = user_options.roi_box_bottom_left_corner_y # Positive is "South"
181-
roi_box_bottom_left_corner_z = user_options.roi_box_bottom_left_corner_z # Positive is "Down"
182-
print(f"X: {roi_box_bottom_left_corner_x}")
183-
print(f"Y: {roi_box_bottom_left_corner_y}")
184-
print(f"Z: {roi_box_bottom_left_corner_z}")
185-
186-
print("ROI Box size:")
187-
roi_box_length = user_options.box_dimension_in_axis_x
188-
roi_box_width = user_options.box_dimension_in_axis_y
189-
roi_box_height = user_options.box_dimension_in_axis_z
190-
print(f"Length: {roi_box_length}")
191-
print(f"Width: {roi_box_width}")
192-
print(f"Height: {roi_box_height}")
193-
194-
print("Filtering the point cloud based on ROI Box")
195-
filtered_xyz, filtered_rgba = roi_box_point_cloud(
196-
point_cloud,
197-
roi_box_bottom_left_corner_x,
198-
roi_box_bottom_left_corner_y,
199-
roi_box_bottom_left_corner_z,
200-
roi_box_length,
201-
roi_box_width,
202-
roi_box_height,
203-
)
204-
205-
print("Displaying transformed point cloud after ROI Box filtering")
206-
display_pointcloud(filtered_xyz, filtered_rgba[:, :, 0:3])
207-
208-
print("Displaying depth map of the transformed point cloud after ROI Box filtering")
209-
display_depthmap(filtered_xyz)
97+
print("Displaying depth map of the ROI-filtered point cloud")
98+
display_depthmap(roi_point_cloud.copy_data("xyz"))
21099

211100

212101
if __name__ == "__main__":

0 commit comments

Comments
 (0)