Skip to content

Commit

Permalink
Samples: Update to SDK 2.11
Browse files Browse the repository at this point in the history
This commit
* Adds projection samples project_image_start_and_stop.py and
read_and_project_image.py. The samples respectively,
    * Show how to start and stop image projection with the projector.
    * Show how to create a projector image from a 2d image from file and
    project it.
See support.zivid.com/en/latest/academy/camera/2d-image-projection.html
for details.
* Adds verify_camera_in_field_from_zdf.py to check dimension trueness of
a Zivid camera from a ZDF file. This allows the camera to be verified
while it is running in production.
* Modifies capture_2d_and_3d.py to use a new API function call;
zivid.Pixelmapping. The API function simplifies mapping from a full
resolution 2d image to a subsampled point cloud since 2.11 adds
4x4subsampling. See
support.zivid.com/en/latest/academy/applications/piece-picking/
2d3d-strategy.html and support.zivid.com/en/latest/academy/
camera/monochrome-capture.html for details.
* Modifies samples that output camera info to also output the camera
state. SDK 2.11 adds camera status to camera state. The camera status
shows if a camera is available, inaccessible, busy, requires firmware
update, etc. This is a result of improved network discovery.

See the SDK Changelog
support.zivid.com/en/latest/api-reference/changelog.html#sdk-changelog
for further details.
  • Loading branch information
annfrid committed Dec 19, 2023
1 parent bd91ba3 commit 51ce1cd
Show file tree
Hide file tree
Showing 14 changed files with 304 additions and 75 deletions.
109 changes: 57 additions & 52 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions continuous-integration/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ function install_www_deb {
rm -r $TMP_DIR || exit
}

install_www_deb "https://downloads.zivid.com/sdk/releases/2.10.1+50b274e8-7/u${VERSION_ID:0:2}/zivid-telicam-driver_3.0.1.1-3_amd64.deb" || exit
install_www_deb "https://downloads.zivid.com/sdk/releases/2.10.1+50b274e8-7/u${VERSION_ID:0:2}/zivid_2.10.1+50b274e8-7_amd64.deb" || exit
install_www_deb "https://downloads.zivid.com/sdk/releases/2.11.0+95829246-1/u${VERSION_ID:0:2}/zivid-telicam-driver_3.0.1.1-3_amd64.deb" || exit
install_www_deb "https://downloads.zivid.com/sdk/releases/2.11.0+95829246-1/u${VERSION_ID:0:2}/zivid_2.11.0+95829246-1_amd64.deb" || exit

python3 -m pip install --upgrade pip || exit
python3 -m pip install --requirement "$ROOT_DIR/requirements.txt" || exit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
Start the Image Projection and Stop it.
How to stop the image projection is demonstrated in three different ways:
- calling stop() function on the projected image handle
- projected image handle going out of scope
- triggering a 3D capture
"""

from typing import Tuple

import numpy as np
import zivid
import zivid.experimental.calibration
import zivid.experimental.projection


def create_projector_image(resolution: Tuple, color: Tuple) -> np.ndarray:
"""Create projector image (numpy array) of given color.
Args:
resolution: projector resolution
color: bgra
Returns:
An image (numpy array) of color given by the bgra value
"""
projector_image = np.full((resolution[0], resolution[1], len(color)), color, dtype=np.uint8)
return projector_image


def _main() -> None:
with zivid.Application() as app:
print("Connecting to camera")
with app.connect_camera() as camera:
print("Retrieving the projector resolution that the camera supports")
projector_resolution = zivid.experimental.projection.projector_resolution(camera)

red_color = (0, 0, 255, 255)

projector_image = create_projector_image(projector_resolution, red_color)

project_image_handle = zivid.experimental.projection.show_image_bgra(camera, projector_image)

input('Press enter to stop projecting using the ".stop()" function')
project_image_handle.stop()

green_color = (0, 255, 0, 255)
projector_image = create_projector_image(projector_resolution, green_color)
with zivid.experimental.projection.show_image_bgra(camera, projector_image):
input("Press enter to stop projecting with context manager")

pink_color = (114, 52, 237, 255)
projector_image = create_projector_image(projector_resolution, pink_color)
project_image_handle = zivid.experimental.projection.show_image_bgra(camera, projector_image)

input("Press enter to stop projecting by performing a 3D capture")
settings = zivid.Settings()
settings.acquisitions.append(zivid.Settings.Acquisition())
camera.capture(settings)

input("Press enter to exit")


if __name__ == "__main__":
_main()
83 changes: 83 additions & 0 deletions source/applications/basic/visualization/read_and_project_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
Read a 2D image from file and project it using the camera projector.
The image for this sample can be found under the main instructions for Zivid samples.
"""

from datetime import timedelta
from typing import Tuple

import cv2
import numpy as np
import zivid
import zivid.experimental.calibration
import zivid.experimental.projection
from sample_utils.paths import get_sample_data_path


def _resize_and_create_projector_image(image_to_resize: np.ndarray, final_resolution: Tuple) -> np.ndarray:
"""Resizes an image to a given resolution.
Args:
image_to_resize: openCV image that needs to be resized
final_resolution: resolution after resizing
Returns:
An image with a resolution that matches the projector resolution
"""
resized_image = cv2.resize(
image_to_resize, (final_resolution[1], final_resolution[0]), interpolation=cv2.INTER_LINEAR
)
projector_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2BGRA)

return projector_image


def _main() -> None:
with zivid.Application() as app:
print("Connecting to camera")
with app.connect_camera() as camera:
image_file = get_sample_data_path() / "ZividLogo.png"
print("Reading 2D image from file: ")
input_image = cv2.imread(str(image_file))
if input_image is None:
raise RuntimeError(f"File {image_file} not found or couldn't be read.")

print(f"Input image size: {input_image.shape[:2]}")

print("Retrieving the projector resolution that the camera supports")
projector_resolution = zivid.experimental.projection.projector_resolution(camera)

print(f"Resizing input image to fit projector resolution:{projector_resolution}")
projector_image = _resize_and_create_projector_image(
image_to_resize=input_image, final_resolution=projector_resolution
)

projector_image_file = "ProjectorImage.png"
print(f"Saving the projector image to file: {projector_image_file}")
cv2.imwrite(projector_image_file, projector_image)

print("Displaying the projector image")

with zivid.experimental.projection.show_image_bgra(camera, projector_image) as projected_image:
settings_2d = zivid.Settings2D()
settings_2d.acquisitions.append(
zivid.Settings2D.Acquisition(
brightness=0.0, exposure_time=timedelta(microseconds=20000), aperture=2.83
)
)

print("Capturing a 2D image with the projected image")
frame_2d = projected_image.capture(settings_2d)

captured_image_file = "CapturedImage.png"
print(f"Saving the captured image: {captured_image_file}")
frame_2d.image_bgra().save(captured_image_file)

input("Press enter to stop projecting ...")


if __name__ == "__main__":
_main()
2 changes: 2 additions & 0 deletions source/applications/point_cloud_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ complete list of output data formats and how to copy them from the GPU.
| `numpy.ndarray([height,width,3], dtype=float32)` | `PointCloud.copy_data("xyzw")` | 16 bytes | 37 MB |
| `numpy.ndarray([height,width], dtype=float32)` | `PointCloud.copy_data("z")` | 4 bytes | 9 MB |
| `numpy.ndarray([height,width,4], dtype=uint8)` | `PointCloud.copy_data("rgba")` | 4 bytes | 9 MB |
| `numpy.ndarray([height,width,4], dtype=uint8)` | `PointCloud.copy_data("bgra")` | 4 bytes | 9 MB |
| `numpy.ndarray([height,width,4], dtype=uint8)` | `PointCloud.copy_data("srgb")` | 4 bytes | 9 MB |
| `numpy.ndarray([height,width], dtype=float32)` | `PointCloud.copy_data("snr")` | 4 bytes | 9 MB |
| `numpy.ndarray([height,width], dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4'), ('r', 'u1'), ('g', 'u1'), ('b', 'u1'), ('a', 'u1')])` | `PointCloud.copy_data("xyzrgba")` | 16 bytes | 37 MB |

Expand Down
22 changes: 9 additions & 13 deletions source/camera/advanced/capture_2d_and_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import numpy as np
import zivid
from sample_utils.display import display_pointcloud, display_rgbs
from zivid.experimental import calibration


def _options() -> argparse.Namespace:
Expand All @@ -36,27 +37,20 @@ def _options() -> argparse.Namespace:
return parser.parse_args()


def _map_rgb(pixels_to_sample: zivid.Settings.Sampling.Pixel, rgba: np.ndarray) -> np.ndarray:
def _map_rgb(pixel_mapping: zivid.PixelMapping, rgba: np.ndarray) -> np.ndarray:
"""Function to map the full RGB image to a subsampled one.
Args:
pixels_to_sample: zivid.Settings.Sampling.Pixel option to use for subsampling
pixel_mapping: zivid.PixelMapping to use for pixel mapping
rgba: RGBA image (HxWx4)
Raises:
RuntimeError: If chosen zivid.Settings.Sampling.Pixel is unsupported
Returns:
Subsampled RGB image
"""
if pixels_to_sample == zivid.Settings.Sampling.Pixel.blueSubsample2x2:
return rgba[::2, ::2, 0:3]
if pixels_to_sample == zivid.Settings.Sampling.Pixel.redSubsample2x2:
return rgba[1::2, 1::2, 0:3]
if pixels_to_sample == zivid.Settings.Sampling.Pixel.all:
return rgba[:, :, 0:3]
raise RuntimeError(f"Invalid pixels to sample: {pixels_to_sample}")
return rgba[
pixel_mapping.row_offset :: pixel_mapping.row_stride, pixel_mapping.col_offset :: pixel_mapping.col_stride, 0:3
]


def _main() -> None:
Expand Down Expand Up @@ -89,13 +83,15 @@ def _main() -> None:
for acquisition in settings.acquisitions:
acquisition.brightness = 2.2

pixel_mapping = calibration.pixel_mapping(camera, settings)

print("Capturing 2D frame")
with camera.capture(settings_2d) as frame_2d:
print("Getting RGBA image")
image = frame_2d.image_rgba()
rgba = image.copy_data()

rgb_mapped = _map_rgb(user_input.pixels_to_sample, rgba)
rgb_mapped = _map_rgb(pixel_mapping, rgba)
display_rgbs(
rgbs=[rgba[:, :, :3], rgb_mapped],
titles=["Full resolution RGB from 2D capture", f"{user_input.pixels_to_sample} RGB from 2D capture"],
Expand Down
3 changes: 3 additions & 0 deletions source/camera/advanced/capture_hdr_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def _settings_folder(camera: zivid.Camera) -> str:
Args:
camera: Zivid camera
Raises:
RuntimeError: If camera is not supported
Returns:
Folder name
Expand Down
5 changes: 3 additions & 2 deletions source/camera/basic/capture_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,13 @@ You may also list all cameras connected to the computer, and view their
serial numbers through

([go to
source](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/print_version_info.py#L16-L18))
source](https://github.com/zivid/zivid-python-samples/tree/master//source/camera/info_util_other/camera_info.py#L16-L19))

``` sourceCode python
cameras = app.cameras()
for camera in cameras:
print(f"Camera Info: {camera}")
print(f"Camera Info: {camera.info}")
print(f"Camera State: {camera.state}")
```

### File Camera
Expand Down
3 changes: 3 additions & 0 deletions source/camera/basic/capture_with_settings_from_yml.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def _settings_folder(camera: zivid.Camera) -> str:
Args:
camera: Zivid camera
Raises:
RuntimeError: If camera is not supported
Returns:
Folder name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Print version information for Python, zivid-python and Zivid SDK, then list cameras and print camera info for each connected camera.
Print version information for Python, zivid-python and Zivid SDK, then list cameras and print camera info and state for each connected camera.
"""

Expand All @@ -15,7 +15,8 @@ def _main() -> None:
print(f"Zivid SDK: {zivid.SDKVersion.full}")
cameras = app.cameras()
for camera in cameras:
print(f"Camera Info: {camera}")
print(f"Camera Info: {camera.info}")
print(f"Camera State: {camera.state}")


if __name__ == "__main__":
Expand Down
3 changes: 3 additions & 0 deletions source/camera/info_util_other/capture_with_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def _settings_folder(camera: zivid.Camera) -> str:
Args:
camera: Zivid camera
Raises:
RuntimeError: If camera is not supported
Returns:
Folder name
Expand Down
2 changes: 1 addition & 1 deletion source/camera/maintenance/correct_camera_in_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def _main() -> None:
accuracy_estimate = correction.accuracy_estimate()

print(
"If written to the camera, this correction can be expected to yield a dimension accuracy of ",
"If written to the camera, this correction can be expected to yield a dimension accuracy error of ",
f"{accuracy_estimate.dimension_accuracy()*100:.3f} or better in the range of z=[{accuracy_estimate.z_min():.3f}, {accuracy_estimate.z_max():.3f}] across the full FOV.",
"Accuracy close to where the correction data was collected is likely better.",
)
Expand Down
7 changes: 4 additions & 3 deletions source/camera/maintenance/verify_camera_in_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
This example shows how to verify the local dimension trueness of a camera.
If the trueness is much worse than expected, the camera may have been damaged by
shock in shipping in handling. If so, look at the correct_camera_in_field sample sample.
shock in shipping or handling. If so, look at the correct_camera_in_field sample sample.
Note: This example uses experimental SDK features, which may be modified, moved, or deleted in the future without notice.
Note: This example uses experimental SDK features, which may be modified, moved, or deleted
in the future without notice.
"""

Expand Down Expand Up @@ -41,7 +42,7 @@ def _main() -> None:
print(f"Successful measurement at {detection_result.centroid()}")
camera_verification = calibration.verify_camera(infield_input)
print(
f"Estimated dimension trueness at measured position: {camera_verification.local_dimension_trueness()*100:.3f}%"
f"Estimated dimension trueness error at measured position: {camera_verification.local_dimension_trueness()*100:.3f}%"
)


Expand Down
63 changes: 63 additions & 0 deletions source/camera/maintenance/verify_camera_in_field_from_zdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Check the dimension trueness of a Zivid camera from a ZDF file.
This example shows how to verify the local dimension trueness of a camera from a ZDF file. If the trueness is much worse
than expected, the camera may have been damaged by shock in shipping or handling. If so, look at the
correct_camera_in_field sample sample.
Why is verifying camera accuracy from a ZDF file useful?
Let us assume that your system is in production. You want to verify the accuracy of the camera while the system is running.
At the same time, you want to minimize the time the robot and the camera are used for anything else than their main task,
e.g., bin picking. Instead of running a full infield verification live, which consists of capturing, detecting, and
estimating accuracy, you can instead only capture and save results to ZDF files on disk. As the robot and the camera go
back to their main tasks, you can load the ZDF files and verify the accuracy offline, using a different PC than the one
used in production. In addition, you can send these ZDF files to Zivid Customer Success for investigation.
Note: This example uses experimental SDK features, which may be modified, moved, or deleted in the future without notice.
"""

import zivid
from sample_utils.paths import get_sample_data_path
from zivid.experimental import calibration


def _main() -> None:
app = zivid.Application()

file_camera = get_sample_data_path() / "BinWithCalibrationBoard.zfc"
print(f"Creating virtual camera using file: {file_camera}")
with app.create_file_camera(file_camera) as camera:
# Calibration board can be captured live, while the system is in production, and saved to ZDF file, for later use in
# offline infield verification

print("Capturing calibration board")
with calibration.capture_calibration_board(camera) as frame:
data_file = "FrameWithCalibrationBoard.zdf"
print(f"Saving frame to file: {data_file}, for later use in offline infield verification")
frame.save(data_file)

# The ZDF captured with captureCalibrationBoard(camera) that contains the calibration board can be loaded for
# offline infield verification

print(f"Reading frame from file: {data_file}, for offline infield verification")
with zivid.Frame(data_file) as frame:
print("Detecting calibration board")
detection_result = calibration.detect_feature_points(frame)

infield_input = calibration.InfieldCorrectionInput(detection_result)
if not infield_input.valid():
raise RuntimeError(
f"Capture not valid for infield verification! Feedback: {infield_input.status_description()}"
)

print(f"Successful measurement at {detection_result.centroid()}")
camera_verification = calibration.verify_camera(infield_input)
print(
f"Estimated dimension trueness error at measured position: {camera_verification.local_dimension_trueness()*100:.3f}%"
)


if __name__ == "__main__":
_main()

0 comments on commit 51ce1cd

Please sign in to comment.