-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch '51-o3d3xx-o3x1xx-add-python-based-examples' into 'main'
Release for O3D and O3X examples Closes #51 See merge request syntron/support/csr/ifm3d/ifm3d-examples!50
- Loading branch information
Showing
52 changed files
with
1,079 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
ifm3dpy | ||
numpy | ||
numpy | ||
open3d | ||
opencv_python |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
#!/usr/bin/env python3 | ||
############################################# | ||
# Copyright 2024-present ifm electronic, gmbh | ||
# SPDX-License-Identifier: Apache-2.0 | ||
############################################# | ||
"""This program is a small viewer that can | ||
be used to display amplitude, distance, xyz or JPEG | ||
images from any of the supported devices (O3X, O3D and O3R). | ||
The JPEG image is only supported for the O3R platform. | ||
""" | ||
|
||
import argparse | ||
import collections | ||
from functools import partial | ||
import logging | ||
import time | ||
from typing import Callable | ||
import cv2 | ||
from ifm3dpy.device import Device, O3R | ||
from ifm3dpy.framegrabber import FrameGrabber, buffer_id | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
logging.basicConfig(level=logging.INFO, format="%(message)s") | ||
|
||
try: | ||
import open3d | ||
|
||
OPEN3D_AVAILABLE = True | ||
except ModuleNotFoundError: | ||
OPEN3D_AVAILABLE = False | ||
|
||
|
||
def get_jpeg(self, img_queue: collections.deque): | ||
"""Get the JPEG image from the frame | ||
and decodes it so it can be displayed. | ||
""" | ||
rgb = cv2.imdecode(self.get_buffer(buffer_id.JPEG_IMAGE), cv2.IMREAD_UNCHANGED) | ||
img_queue.append(rgb) | ||
|
||
|
||
def get_distance(self, img_queue: collections.deque): | ||
"""Get the distance image from the frame | ||
and normalizes it for display. | ||
""" | ||
img = cv2.normalize( | ||
self.get_buffer(buffer_id.RADIAL_DISTANCE_IMAGE), | ||
None, | ||
0, | ||
255, | ||
cv2.NORM_MINMAX, | ||
cv2.CV_8U, | ||
) | ||
img = cv2.applyColorMap(img, cv2.COLORMAP_JET) | ||
img_queue.append(img) | ||
|
||
|
||
def get_amplitude(self, img_queue: collections.deque): | ||
"""Returns the amplitude data extracted | ||
from the frame. | ||
""" | ||
img_queue.append(self.get_buffer(buffer_id.NORM_AMPLITUDE_IMAGE)) | ||
|
||
|
||
def get_xyz(self, img_queue: collections.deque): | ||
"""Returns the xyz data extracted | ||
from the frame. | ||
""" | ||
img_queue.append(self.get_buffer(buffer_id.XYZ)) | ||
|
||
|
||
def display_2d(fg: FrameGrabber, getter: Callable, title: str): | ||
"""Display the requested 2D data (distance, amplitude or JPEG)""" | ||
if getter.__name__ == "get_jpeg": | ||
fg.start([buffer_id.JPEG_IMAGE]) | ||
else: | ||
fg.start( | ||
[ | ||
buffer_id.NORM_AMPLITUDE_IMAGE, | ||
buffer_id.RADIAL_DISTANCE_IMAGE, | ||
] | ||
) | ||
img_queue = collections.deque(maxlen=10) | ||
fg.on_new_frame(partial(getter, img_queue=img_queue)) | ||
time.sleep(3) | ||
|
||
cv2.startWindowThread() | ||
cv2.namedWindow(title, cv2.WINDOW_NORMAL) | ||
while True: | ||
if img_queue: | ||
cv2.imshow(title, img_queue.pop()) | ||
cv2.waitKey(15) | ||
|
||
if cv2.getWindowProperty(title, cv2.WND_PROP_VISIBLE) < 1: | ||
break | ||
|
||
cv2.destroyAllWindows() | ||
|
||
|
||
def display_3d(fg: FrameGrabber, getter: Callable, title: str): | ||
"""Stream and display the point cloud. | ||
""" | ||
fg.start( | ||
[buffer_id.XYZ] | ||
) | ||
img_queue = collections.deque(maxlen=10) | ||
fg.on_new_frame(partial(getter, img_queue=img_queue)) | ||
time.sleep(3) | ||
vis = open3d.visualization.Visualizer() | ||
vis.create_window(title) | ||
|
||
first = True | ||
while True: | ||
if img_queue: | ||
img = img_queue.pop() | ||
|
||
img = img.reshape(img.shape[0] * img.shape[1], 3) | ||
pcd = open3d.geometry.PointCloud() | ||
pcd.points = open3d.utility.Vector3dVector(img) | ||
|
||
vis.clear_geometries() | ||
vis.add_geometry(pcd, first) | ||
if not vis.poll_events(): | ||
break | ||
|
||
vis.update_renderer() | ||
|
||
first = False | ||
|
||
vis.destroy_window() | ||
|
||
|
||
def main(): | ||
image_choices = ["distance", "amplitude", "jpeg"] | ||
if OPEN3D_AVAILABLE: | ||
image_choices += ["xyz"] | ||
|
||
parser = argparse.ArgumentParser() | ||
|
||
parser.add_argument( | ||
"--image", | ||
help="The image to received (default: distance). The jpeg image is only available for the O3R.", | ||
type=str, | ||
choices=image_choices, | ||
required=True, | ||
) | ||
parser.add_argument( | ||
"--ip", | ||
help="IP address of the sensor (default: 192.168.0.69)", | ||
type=str, | ||
required=False, | ||
default="192.168.0.69", | ||
) | ||
parser.add_argument( | ||
"--xmlrpc-port", | ||
help="XMLRPC port of the sensor (default: 80)", | ||
type=int, | ||
required=False, | ||
default=80, | ||
) | ||
parser.add_argument( | ||
"--port", | ||
help="The port from which images should be received (for the O3R only)", | ||
type=str, | ||
required=False, | ||
) | ||
args = parser.parse_args() | ||
|
||
getter = globals()["get_" + args.image] | ||
|
||
device = Device(args.ip, args.xmlrpc_port) | ||
device_type = device.who_am_i() | ||
logging.info(f"Device type is: {device_type}") | ||
if device_type == device.device_family.O3R: | ||
if args.port is None: | ||
raise ValueError("A port should be provided.") | ||
o3r = O3R(args.ip) | ||
fg = FrameGrabber(device, pcic_port=o3r.port(args.port).pcic_port) | ||
logging.info(f"Port: {args.port}") | ||
else: | ||
fg = FrameGrabber(device) | ||
if args.image == "jpeg": | ||
raise ValueError("JPEG images are only supported on the O3R platform.") | ||
|
||
title = f"{device_type} viewer" | ||
|
||
if args.image == "xyz": | ||
display_3d(fg, getter, title) | ||
else: | ||
display_2d(fg, getter, title) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,3 @@ | ||
# O3D3xx and O3X1xx examples | ||
|
||
# ifm3d Examples | ||
|
||
This project is formerly the `examples` sub-module of the | ||
[ifm3d](https://github.com/ifm/ifm3d) project. It has been moved to a | ||
standalone project to increase its efficacy as a teaching tool. Specifically, | ||
beyond providing concrete code examples for interfacing to `ifm3d` it also | ||
shows how to integrate `ifm3d` into an external project via `cmake`. This | ||
project relies upon `ifm3d` version 1.4.3 or better. The remainder of the old | ||
`README` now follows -- with minor edits. | ||
|
||
This directory contains example programs that utilize `ifm3d`. The | ||
intention is to create standalone programs that illustrate one very specific | ||
concept in order to serve the purpose of letting developers ramp up quickly | ||
with using the library. The build infrastructure in this directory is minimal | ||
and the programs are intended to be run in place. Additionally, unless | ||
specifically stated otherwise, things like performance and robust error | ||
handling are not demonstrated. The purpose is to clearly illustrate the task | ||
without clouding it with the details of real-world software engineering -- | ||
unless, of course, that was the point of the example. | ||
|
||
It is expected that this library of examples will grow over time in response to | ||
common themes we see on the issue tracker. | ||
|
||
## Prerequisites | ||
- [fmt](https://github.com/fmtlib/fmt.git) | ||
- [openCV](https://opencv.org/releases/) | ||
|
||
|
||
## Building the examples | ||
|
||
Assuming you are starting from the top-level directory of this source | ||
distribution: | ||
|
||
$ mkdir build | ||
$ cd build | ||
$ cmake .. | ||
$ cmake --build . | ||
|
||
### Windows examples | ||
For Windows-based target, with Visual Studio 2017, assuming you are starting from the top-level directory of this source | ||
distribution: | ||
|
||
$ set IFM3D_CMAKE_GENERATOR="Visual Studio 17 2022" | ||
$ cd ifm3d-examples/o3d3xx-o3x1xx | ||
$ mkdir build | ||
$ cd build | ||
# Note: To show images Opencv is used,hence build path to opencv is added into -DCMAKE_PREFIX_PATH | ||
$ cmake -G %IFM3D_CMAKE_GENERATOR% -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON -DCMAKE_PREFIX_PATH=F:\windows\ifm3d_deps\install;F:\opencv-4.9.0-windows\opencv\build .. | ||
$ cmake --build . --config Release --target ALL_BUILD | ||
|
||
At this stage, projects are built and you will find *IFM3D_EXAMPLES.sln* in build folder. | ||
Use Release / RelWithDebInfo configuration to run and investigate application examples. | ||
Please add PATH variable to projects : | ||
|
||
PATH=%IFM3D_BUILD_DIR%\install\bin;%IFM3D_BUILD_DIR%\install\x64\vc%MSVC_MAJOR_VERSION%.%MSVC_MINOR_VERSION%\bin;%PATH% | ||
|
||
For instance, you can fill directly in VS *Project Properties* / *Debugging* / *Environment* with `PATH=C:\ifm3d\install\bin;C:\ifm3d\install\x64\vc14.1\bin;%PATH%` | ||
|
||
## What is included? | ||
|
||
|
||
* [ex-file_io](file_io/ex-file_io.cpp) Shows how to capture data from the camera and | ||
write the images to disk. In this example, the amplitude image is written out as PNG files. | ||
* [ex-getmac](getmac/ex-getmac.cpp) | ||
Request the MAC address from the camera. The MAC address can be used as | ||
a unique identifier. | ||
* [ex-timestamp](timestamp/ex-timestamp.cpp) | ||
Request some frames from the camera and write the timestamps to stdout | ||
* [ex-exposure_times](exposure_time/ex-exposure_times.cpp) Shows how to change imager | ||
exposure times on the fly while streaming in pixel data and validating the | ||
setting of the exposure times registered to the frame data. | ||
* [ex-fast_app_switch](fast_app_switch/ex-fast_app_switch.cpp) Shows how to switch between two | ||
applications on the camera using PCIC | ||
* [ex-pcicclient_async_messages](pcicclient_async_messages/ex-pcicclient_async_messages.cpp) Shows how to | ||
use the PCICClient module to receive asynchronous notification (and error) | ||
messages from the camera. | ||
* [ex-pcicclient_set_io](pcicclient_set_io/ex-pcicclient_set_io.cpp) Shows how to mutate the digial IO pins | ||
on the O3D camera by the PCIC interface. | ||
* [ex-simpleImage_ppm_io](simpleimage/example/ex-simpleImage_ppm_io.cpp) Shows how to write your own | ||
image container which does not depend on PCL nor OpenCV. | ||
* [ex-multi_camera_grabber](multi_camera_grabber/ex-multi_camera_grabber.cpp) demonstrate's how to acquire frames from multiple ifm 3D camera's, | ||
see the example [documentation](doc/ex-multi_camera_grabber.md) for more details. | ||
|
||
### Note: Use of `Device` and `LegacyDevice` class | ||
|
||
Please note `Device` is the base class and `LegacyDevice` inherits from the `Device` class. Object from `ifm3d::Device` can be created while accessing the device functionalities and `ifm3d::LegacyDevice` object can be created while using the application specific methods of legacy devices like `O3D/O3X`. | ||
|
||
## LICENSE | ||
Please see the file called [LICENSE](LICENSE). | ||
This folders container Python and C++ examples for the O3D3xx and O3X1xx series of devices. Head to the `cpp` or to the `python` folder for more details on the individual examples in these languages. |
Oops, something went wrong.