pyorbbec 1.0.1.7__tar.gz → 1.0.1.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/MANIFEST.in +1 -0
  2. {pyorbbec-1.0.1.7/src/pyorbbec.egg-info → pyorbbec-1.0.1.9}/PKG-INFO +1 -1
  3. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/setup.py +1 -1
  4. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9/src/pyorbbec.egg-info}/PKG-INFO +1 -1
  5. pyorbbec-1.0.1.9/src/pyorbbec.egg-info/SOURCES.txt +54 -0
  6. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/.gitkeep +0 -0
  7. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/README.md +26 -0
  8. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/callback.py +303 -0
  9. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/color.py +64 -0
  10. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/coordinate_transform.py +184 -0
  11. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/depth.py +107 -0
  12. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/depth_work_mode.py +50 -0
  13. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/device_firmware_update.py +155 -0
  14. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/device_optional_depth_presets_update.py +142 -0
  15. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/enumerate.py +118 -0
  16. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hdr.py +216 -0
  17. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hot_plug.py +160 -0
  18. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hw_d2c_align.py +135 -0
  19. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/imu.py +60 -0
  20. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/infrared.py +115 -0
  21. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/logger.py +55 -0
  22. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/metadata.py +64 -0
  23. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/multi_device.py +169 -0
  24. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/multi_streams.py +219 -0
  25. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/net_device.py +158 -0
  26. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/playback.py +277 -0
  27. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/point_cloud.py +90 -0
  28. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/post_processing.py +119 -0
  29. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/preset.py +67 -0
  30. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/quick_start.py +90 -0
  31. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/recorder.py +236 -0
  32. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/requirements.txt +9 -0
  33. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/save_image_to_disk.py +106 -0
  34. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/sync_align.py +109 -0
  35. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/two_devices_sync.py +233 -0
  36. pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/utils.py +127 -0
  37. pyorbbec-1.0.1.7/src/pyorbbec.egg-info/SOURCES.txt +0 -23
  38. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/LICENSE +0 -0
  39. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/NOTICE +0 -0
  40. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/README.md +0 -0
  41. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/pyproject.toml +0 -0
  42. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/setup.cfg +0 -0
  43. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/dependency_links.txt +0 -0
  44. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/not-zip-safe +0 -0
  45. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/top_level.txt +0 -0
  46. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDK.dll +0 -0
  47. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDK.lib +0 -0
  48. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDKConfig.xml +0 -0
  49. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/__init__.py +0 -0
  50. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/__version__.py +0 -0
  51. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/depthengine/depthengine.dll +0 -0
  52. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/depthengine/depthengine.lib +0 -0
  53. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/filters/FilterProcessor.dll +0 -0
  54. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/filters/ob_priv_filter.dll +0 -0
  55. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/firmwareupdater/firmwareupdater.dll +0 -0
  56. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/frameprocessor/ob_frame_processor.dll +0 -0
  57. {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/pyorbbecsdk.cp313-win_amd64.pyd +0 -0
@@ -1,2 +1,3 @@
1
1
  include README.md LICENSE NOTICE HISTORY.md requirements-dev.txt
2
2
  recursive-include src/pyorbbecsdk/extensions *
3
+ recursive-include src/pyorbbecsdk/examples *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyorbbec
3
- Version: 1.0.1.7
3
+ Version: 1.0.1.9
4
4
  Summary: Python interface to the Orbbec SDK.
5
5
  Home-page: https://orbbec.com.cn/
6
6
  Author: orbbec
@@ -21,7 +21,7 @@ from setuptools import setup, find_packages
21
21
 
22
22
  setup(
23
23
  name="pyorbbec",
24
- version="1.0.1.7",
24
+ version="1.0.1.9",
25
25
  description="Python interface to the Orbbec SDK.",
26
26
  long_description_content_type="text/markdown",
27
27
  author="orbbec",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyorbbec
3
- Version: 1.0.1.7
3
+ Version: 1.0.1.9
4
4
  Summary: Python interface to the Orbbec SDK.
5
5
  Home-page: https://orbbec.com.cn/
6
6
  Author: orbbec
@@ -0,0 +1,54 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ NOTICE
4
+ README.md
5
+ pyproject.toml
6
+ setup.py
7
+ src/pyorbbec.egg-info/PKG-INFO
8
+ src/pyorbbec.egg-info/SOURCES.txt
9
+ src/pyorbbec.egg-info/dependency_links.txt
10
+ src/pyorbbec.egg-info/not-zip-safe
11
+ src/pyorbbec.egg-info/top_level.txt
12
+ src/pyorbbecsdk/OrbbecSDK.dll
13
+ src/pyorbbecsdk/OrbbecSDK.lib
14
+ src/pyorbbecsdk/OrbbecSDKConfig.xml
15
+ src/pyorbbecsdk/__init__.py
16
+ src/pyorbbecsdk/__version__.py
17
+ src/pyorbbecsdk/pyorbbecsdk.cp313-win_amd64.pyd
18
+ src/pyorbbecsdk/examples/.gitkeep
19
+ src/pyorbbecsdk/examples/README.md
20
+ src/pyorbbecsdk/examples/callback.py
21
+ src/pyorbbecsdk/examples/color.py
22
+ src/pyorbbecsdk/examples/coordinate_transform.py
23
+ src/pyorbbecsdk/examples/depth.py
24
+ src/pyorbbecsdk/examples/depth_work_mode.py
25
+ src/pyorbbecsdk/examples/device_firmware_update.py
26
+ src/pyorbbecsdk/examples/device_optional_depth_presets_update.py
27
+ src/pyorbbecsdk/examples/enumerate.py
28
+ src/pyorbbecsdk/examples/hdr.py
29
+ src/pyorbbecsdk/examples/hot_plug.py
30
+ src/pyorbbecsdk/examples/hw_d2c_align.py
31
+ src/pyorbbecsdk/examples/imu.py
32
+ src/pyorbbecsdk/examples/infrared.py
33
+ src/pyorbbecsdk/examples/logger.py
34
+ src/pyorbbecsdk/examples/metadata.py
35
+ src/pyorbbecsdk/examples/multi_device.py
36
+ src/pyorbbecsdk/examples/multi_streams.py
37
+ src/pyorbbecsdk/examples/net_device.py
38
+ src/pyorbbecsdk/examples/playback.py
39
+ src/pyorbbecsdk/examples/point_cloud.py
40
+ src/pyorbbecsdk/examples/post_processing.py
41
+ src/pyorbbecsdk/examples/preset.py
42
+ src/pyorbbecsdk/examples/quick_start.py
43
+ src/pyorbbecsdk/examples/recorder.py
44
+ src/pyorbbecsdk/examples/requirements.txt
45
+ src/pyorbbecsdk/examples/save_image_to_disk.py
46
+ src/pyorbbecsdk/examples/sync_align.py
47
+ src/pyorbbecsdk/examples/two_devices_sync.py
48
+ src/pyorbbecsdk/examples/utils.py
49
+ src/pyorbbecsdk/extensions/depthengine/depthengine.dll
50
+ src/pyorbbecsdk/extensions/depthengine/depthengine.lib
51
+ src/pyorbbecsdk/extensions/filters/FilterProcessor.dll
52
+ src/pyorbbecsdk/extensions/filters/ob_priv_filter.dll
53
+ src/pyorbbecsdk/extensions/firmwareupdater/firmwareupdater.dll
54
+ src/pyorbbecsdk/extensions/frameprocessor/ob_frame_processor.dll
File without changes
@@ -0,0 +1,26 @@
1
+ Install the requirements to run the sample after install the .whl
2
+ pip3 install -r requirements.txt
3
+
4
+ | Example | Description | Notes | Level |
5
+ |---------------------------|-----------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|-------|
6
+ | enumerate.py | Use the SDK interface to obtain camera-related information, including model, various sensors, and sensor-related configurations . | | ⭐ |
7
+ | hot_plug.py | Demonstrates how to detect hot plug events. | | ⭐ |
8
+ | logger.py | Use the SDK interface to set the log output level and customize the output path. | | ⭐ |
9
+ | quick_start.py | Demonstrates how to use the SDK. | | ⭐ |
10
+ | callback.py | Displays the video stream from the camera using a callback. | | ⭐⭐ |
11
+ | color.py | Displays the color stream from the camera. | | ⭐⭐ |
12
+ | depth.py | Displays the depth stream from the camera. | | ⭐⭐ |
13
+ | imu.py | Demonstrates how to read IMU data. | | ⭐⭐ |
14
+ | infrared.py | Displays the infrared stream from the camera. | | ⭐⭐ |
15
+ | multi_device.py | Demonstrates how to use multiple devices. | | ⭐⭐ |
16
+ | net_device.py | Demonstrates how to use network functions. | Supported by Femto Mega and Gemini 2 XL. | ⭐⭐ |
17
+ | coordinate_transform.py | Use the SDK interface to transform different coordinate systems. | | ⭐⭐⭐ |
18
+ | device_firmware_update.py | This sample demonstrates how to read a firmware file to perform firmware upgrades on the device. | | ⭐⭐⭐ |
19
+ | depth_work_mode.py | Demonstrates how to set the depth work mode. | Supported by Gemini2、Gemini2L、Astra2、Gemini 2 XL | ⭐⭐⭐ |
20
+ | hdr.py | In this sample, user can get the HDR merge image. Also supports user to toggle HDR merge and toggle alternate show origin frame. | Supported by the Gemini 330 series. | ⭐⭐⭐ |
21
+ | hw_d2c_align.py | Demonstrates how to use hardware D2C. | | ⭐⭐⭐ |
22
+ | point_cloud.py | Demonstrates how to save the point cloud to disk using a point cloud filter. | | ⭐⭐⭐ |
23
+ | post_processing.py | Demonstrates how to use post-processing filters. | Supported by the Gemini 330 series. | ⭐⭐⭐ |
24
+ | preset.py | Use the SDK interface to set and get the preset value. | Supported by the Gemini 330 series. | ⭐⭐⭐ |
25
+ | sync_align.py | Demonstrates how to use the align filter. | | ⭐⭐⭐ |
26
+ | two_devices_sync.py | Demonstrates how to synchronize two devices. | | ⭐⭐⭐ |
@@ -0,0 +1,303 @@
1
+ # ******************************************************************************
2
+ # Copyright (c) 2024 Orbbec 3D Technology, Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ******************************************************************************
16
+
17
+ from queue import Queue
18
+ import cv2
19
+ import numpy as np
20
+ from pyorbbecsdk import *
21
+ from utils import frame_to_bgr_image
22
+
23
+ # Global variables
24
+ frames_queue = Queue()
25
+ MAX_QUEUE_SIZE = 1
26
+ ESC_KEY = 27
27
+ stop_rendering = False
28
+
29
+ # Define sensor types we want to enable
30
+ video_sensor_types = [
31
+ OBSensorType.DEPTH_SENSOR,
32
+ OBSensorType.LEFT_IR_SENSOR,
33
+ OBSensorType.RIGHT_IR_SENSOR,
34
+ OBSensorType.IR_SENSOR,
35
+ OBSensorType.COLOR_SENSOR
36
+ ]
37
+ # cached frames for better visualization
38
+ cached_frames = {
39
+ 'color': None,
40
+ 'depth': None,
41
+ 'left_ir': None,
42
+ 'right_ir': None,
43
+ 'ir': None
44
+ }
45
+
46
+ def on_new_frame_callback(frame: FrameSet):
47
+ """Callback function to handle new frames"""
48
+ if frame is None:
49
+ return
50
+ if frames_queue.qsize() >= MAX_QUEUE_SIZE:
51
+ frames_queue.get()
52
+ frames_queue.put(frame)
53
+
54
+
55
+ def process_color(frame):
56
+ """Process color frame to BGR image"""
57
+ if not frame:
58
+ return None
59
+ color_frame = frame.get_color_frame()
60
+ color_frame = color_frame if color_frame else cached_frames['color']
61
+ if not color_frame:
62
+ return None
63
+ try:
64
+ cached_frames['color'] = color_frame
65
+ return frame_to_bgr_image(color_frame)
66
+ except ValueError:
67
+ print("Error processing color frame")
68
+ return None
69
+
70
+
71
+ def process_depth(frame):
72
+ """Process depth frame to colorized depth image"""
73
+ if not frame:
74
+ return None
75
+ depth_frame = frame.get_depth_frame()
76
+ depth_frame = depth_frame if depth_frame else cached_frames['depth']
77
+ if not depth_frame:
78
+ return None
79
+ try:
80
+ depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
81
+ depth_data = depth_data.reshape(depth_frame.get_height(), depth_frame.get_width())
82
+ depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
83
+ cached_frames['depth'] = depth_frame
84
+ return cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
85
+ except ValueError:
86
+ print("Error processing depth frame")
87
+ return None
88
+
89
+
90
+ def process_ir(frame, frame_type):
91
+ if frame is None:
92
+ return None
93
+ ir_frame = frame.get_frame(frame_type)
94
+ frame_name = 'ir' if frame_type == OBFrameType.IR_FRAME else 'left_ir' if frame_type == OBFrameType.LEFT_IR_FRAME else 'right_ir'
95
+ ir_frame = ir_frame if ir_frame else cached_frames[frame_name]
96
+ if not ir_frame:
97
+ return None
98
+ ir_frame = ir_frame.as_video_frame()
99
+ cached_frames[frame_name] = ir_frame
100
+ ir_data = np.asanyarray(ir_frame.get_data())
101
+ width = ir_frame.get_width()
102
+ height = ir_frame.get_height()
103
+ ir_format = ir_frame.get_format()
104
+
105
+ if ir_format == OBFormat.Y8:
106
+ ir_data = np.resize(ir_data, (height, width, 1))
107
+ data_type = np.uint8
108
+ image_dtype = cv2.CV_8UC1
109
+ max_data = 255
110
+ elif ir_format == OBFormat.MJPG:
111
+ ir_data = cv2.imdecode(ir_data, cv2.IMREAD_UNCHANGED)
112
+ data_type = np.uint8
113
+ image_dtype = cv2.CV_8UC1
114
+ max_data = 255
115
+ if ir_data is None:
116
+ print("decode mjpeg failed")
117
+ return None
118
+ ir_data = np.resize(ir_data, (height, width, 1))
119
+ else:
120
+ ir_data = np.frombuffer(ir_data, dtype=np.uint16)
121
+ data_type = np.uint16
122
+ image_dtype = cv2.CV_16UC1
123
+ max_data = 255
124
+ ir_data = np.resize(ir_data, (height, width, 1))
125
+
126
+ cv2.normalize(ir_data, ir_data, 0, max_data, cv2.NORM_MINMAX, dtype=image_dtype)
127
+ ir_data = ir_data.astype(data_type)
128
+ return cv2.cvtColor(ir_data, cv2.COLOR_GRAY2RGB)
129
+
130
+
131
+
132
+ def create_display(processed_frames, width=1280, height=720):
133
+ """Create display window with all processed frames
134
+ Layout:
135
+ 2x2 grid when both left and right IR are present:
136
+ [Color] [Depth]
137
+ [L-IR] [R-IR]
138
+
139
+ 2x2 grid with single IR:
140
+ [Color] [Depth]
141
+ [ IR ][ ]
142
+ """
143
+ display = np.zeros((height, width, 3), dtype=np.uint8)
144
+ h, w = height // 2, width // 2
145
+
146
+ # Helper function for safe image resizing
147
+ def safe_resize(img, target_size):
148
+ if img is None:
149
+ return None
150
+ try:
151
+ return cv2.resize(img, target_size)
152
+ except:
153
+ return None
154
+
155
+ # Process frames with consistent error handling
156
+ def place_frame(img, x1, y1, x2, y2):
157
+ if img is not None:
158
+ try:
159
+ h_section = y2 - y1
160
+ w_section = x2 - x1
161
+ resized = safe_resize(img, (w_section, h_section))
162
+ if resized is not None:
163
+ display[y1:y2, x1:x2] = resized
164
+ except:
165
+ pass
166
+
167
+ # Always show color and depth in top row if available
168
+ place_frame(processed_frames.get('color'), 0, 0, w, h)
169
+ place_frame(processed_frames.get('depth'), w, 0, width, h)
170
+
171
+ # Handle IR display in bottom row
172
+ has_left_ir = processed_frames.get('left_ir') is not None
173
+ has_right_ir = processed_frames.get('right_ir') is not None
174
+ has_single_ir = processed_frames.get('ir') is not None
175
+
176
+ if has_left_ir and has_right_ir:
177
+ # Show stereo IR in bottom row
178
+ place_frame(processed_frames['left_ir'], 0, h, w, height)
179
+ place_frame(processed_frames['right_ir'], w, h, width, height)
180
+ elif has_single_ir:
181
+ # Show single IR in bottom-left quadrant
182
+ place_frame(processed_frames['ir'], 0, h, w, height)
183
+
184
+ # Add labels to identify each stream
185
+ font = cv2.FONT_HERSHEY_SIMPLEX
186
+ font_scale = 0.8
187
+ font_color = (255, 255, 255)
188
+ font_thickness = 2
189
+
190
+ # Helper function for adding labels
191
+ def add_label(text, x, y):
192
+ cv2.putText(display, text, (x + 10, y + 30), font, font_scale,
193
+ font_color, font_thickness)
194
+
195
+ # Add labels for each quadrant
196
+ add_label("Color", 0, 0)
197
+ add_label("Depth", w, 0)
198
+
199
+ if has_left_ir and has_right_ir:
200
+ add_label("Left IR", 0, h)
201
+ add_label("Right IR", w, h)
202
+ elif has_single_ir:
203
+ add_label("IR", 0, h)
204
+
205
+ return display
206
+
207
+ def rendering_frames():
208
+ """Main rendering loop for processing and displaying frames"""
209
+ global frames_queue, stop_rendering
210
+
211
+ # Create and configure display window
212
+ cv2.namedWindow("Orbbec Camera Viewer", cv2.WINDOW_NORMAL)
213
+ cv2.resizeWindow("Orbbec Camera Viewer", 1280, 720)
214
+
215
+ while not stop_rendering:
216
+ if frames_queue.empty():
217
+ continue
218
+
219
+ frame_set = frames_queue.get()
220
+ if frame_set is None:
221
+ continue
222
+
223
+ # Process all available frames
224
+ processed_frames = {
225
+ 'color': process_color(frame_set),
226
+ 'depth': process_depth(frame_set),
227
+ }
228
+
229
+ # Process IR frames with better error handling
230
+ try:
231
+ left_ir = process_ir(frame_set, OBFrameType.LEFT_IR_FRAME)
232
+ right_ir = process_ir(frame_set, OBFrameType.RIGHT_IR_FRAME)
233
+ if left_ir is not None and right_ir is not None:
234
+ processed_frames['left_ir'] = left_ir
235
+ processed_frames['right_ir'] = right_ir
236
+ else:
237
+ # Try single IR if stereo IR is not available
238
+ ir = process_ir(frame_set, OBFrameType.IR_FRAME)
239
+ if ir is not None:
240
+ processed_frames['ir'] = ir
241
+ except:
242
+ # Fallback to single IR in case of any error
243
+ try:
244
+ ir = process_ir(frame_set, OBFrameType.IR_FRAME)
245
+ if ir is not None:
246
+ processed_frames['ir'] = ir
247
+ except:
248
+ pass
249
+
250
+ # Create and display the combined view
251
+ display = create_display(processed_frames)
252
+ cv2.imshow("Orbbec Camera Viewer", display)
253
+
254
+ # Check for exit key
255
+ key = cv2.waitKey(1)
256
+ if key in [ord('q'), ESC_KEY]:
257
+ return
258
+
259
+ def main():
260
+ """Main function to initialize and run the camera viewer"""
261
+ global stop_rendering
262
+ config = Config()
263
+ pipeline = Pipeline()
264
+
265
+ try:
266
+ # Initialize pipeline and config
267
+
268
+
269
+ # Get device and sensor information
270
+ device = pipeline.get_device()
271
+ sensor_list = device.get_sensor_list()
272
+
273
+ # Enable all available video streams
274
+ for sensor in range(len(sensor_list)):
275
+ sensor_type = sensor_list[sensor].get_type()
276
+ if sensor_type in video_sensor_types:
277
+ try:
278
+ print(f"Enabling sensor type: {sensor_type}")
279
+ config.enable_stream(sensor_type)
280
+ except:
281
+ print(f"Failed to enable sensor type: {sensor_type}")
282
+ continue
283
+
284
+ # Start pipeline with callback
285
+ pipeline.start(config, lambda frames: on_new_frame_callback(frames))
286
+
287
+ # Start rendering frames
288
+ try:
289
+ rendering_frames()
290
+ except KeyboardInterrupt:
291
+ stop_rendering = True
292
+
293
+ except Exception as e:
294
+ print(f"Error: {str(e)}")
295
+
296
+ # Cleanup
297
+ stop_rendering = True
298
+ pipeline.stop()
299
+ cv2.destroyAllWindows()
300
+
301
+
302
+ if __name__ == "__main__":
303
+ main()
@@ -0,0 +1,64 @@
1
+ # ******************************************************************************
2
+ # Copyright (c) 2024 Orbbec 3D Technology, Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http:# www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ******************************************************************************
16
+ import cv2
17
+
18
+ from pyorbbecsdk import *
19
+ from utils import frame_to_bgr_image
20
+
21
+ ESC_KEY = 27
22
+
23
+
24
+ def main():
25
+ config = Config()
26
+ pipeline = Pipeline()
27
+ try:
28
+ profile_list = pipeline.get_stream_profile_list(OBSensorType.COLOR_SENSOR)
29
+ try:
30
+ color_profile: VideoStreamProfile = profile_list.get_video_stream_profile(640, 0, OBFormat.RGB, 30)
31
+ except OBError as e:
32
+ print(e)
33
+ color_profile = profile_list.get_default_video_stream_profile()
34
+ print("color profile: ", color_profile)
35
+ config.enable_stream(color_profile)
36
+ except Exception as e:
37
+ print(e)
38
+ return
39
+ pipeline.start(config)
40
+ while True:
41
+ try:
42
+ frames: FrameSet = pipeline.wait_for_frames(100)
43
+ if frames is None:
44
+ continue
45
+ color_frame = frames.get_color_frame()
46
+ if color_frame is None:
47
+ continue
48
+ # covert to RGB format
49
+ color_image = frame_to_bgr_image(color_frame)
50
+ if color_image is None:
51
+ print("failed to convert frame to image")
52
+ continue
53
+ cv2.imshow("Color Viewer", color_image)
54
+ key = cv2.waitKey(1)
55
+ if key == ord('q') or key == ESC_KEY:
56
+ break
57
+ except KeyboardInterrupt:
58
+ break
59
+ cv2.destroyAllWindows()
60
+ pipeline.stop()
61
+
62
+
63
+ if __name__ == "__main__":
64
+ main()
@@ -0,0 +1,184 @@
1
+ # ******************************************************************************
2
+ # Copyright (c) 2024 Orbbec 3D Technology, Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http:# www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ******************************************************************************
16
+
17
+ import numpy as np
18
+
19
+ import pyorbbecsdk as ob
20
+
21
+ ESC_KEY = 27
22
+
23
+
24
+ def print_help():
25
+ print("Supported commands:")
26
+ print("Press '1' to transform 2D point to 2D point")
27
+ print("Press '2' to transform 2D point to 3D point")
28
+ print("Press '3' to transform 3D point to 3D point")
29
+ print("Press '4' to transform 3D point to 2D point")
30
+ print("--------------------------------------------")
31
+ print("Press Ctrl+C to exit the program")
32
+
33
+
34
+ def get_frame_data(color_frame, depth_frame):
35
+ color_frame = color_frame.as_video_frame()
36
+ depth_frame = depth_frame.as_video_frame()
37
+
38
+ depth_width = depth_frame.get_width()
39
+ depth_height = depth_frame.get_height()
40
+
41
+ color_profile = color_frame.get_stream_profile()
42
+ depth_profile = depth_frame.get_stream_profile()
43
+ print("video profile:", color_profile.as_video_stream_profile())
44
+ color_intrinsics = color_profile.as_video_stream_profile().get_intrinsic()
45
+ color_distortion = color_profile.as_video_stream_profile().get_distortion()
46
+ depth_intrinsics = depth_profile.as_video_stream_profile().get_intrinsic()
47
+ depth_distortion = depth_profile.as_video_stream_profile().get_distortion()
48
+
49
+ extrinsic = depth_profile.get_extrinsic_to(color_profile)
50
+
51
+ depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16).reshape(depth_height, depth_width)
52
+
53
+ return (color_intrinsics, color_distortion, depth_intrinsics, depth_distortion,
54
+ extrinsic, depth_data, depth_width, depth_height)
55
+
56
+
57
+ def transform_points(transform_func, color_frame, depth_frame, dimension):
58
+ (color_intrinsics, color_distortion, depth_intrinsics, depth_distortion,
59
+ extrinsic, depth_data, depth_width, depth_height) = get_frame_data(color_frame, depth_frame)
60
+
61
+ convert_width, convert_height = 3, 3
62
+ for i in range(depth_width // 2, depth_width // 2 + convert_width):
63
+ for j in range(depth_height // 2, depth_height // 2 + convert_height):
64
+ depth = depth_data[j, i]
65
+ x, y = float(i), float(j)
66
+ original_point = (x, y, depth)
67
+ if depth > 0:
68
+ if dimension == "2d_to_2d":
69
+ res = transform_func(ob.OBPoint2f(x, y), depth, depth_intrinsics, depth_distortion,
70
+ color_intrinsics, color_distortion, extrinsic)
71
+ elif dimension == "2d_to_3d":
72
+ res = transform_func(ob.OBPoint2f(x, y), depth, depth_intrinsics, extrinsic)
73
+ elif dimension == "3d_to_3d":
74
+ res = transform_func(ob.OBPoint3f(x, y, depth), extrinsic)
75
+ elif dimension == "3d_to_2d":
76
+ res = transform_func(ob.OBPoint3f(x, y, depth), color_intrinsics, color_distortion, extrinsic)
77
+ print(f"\n--- {dimension.replace('_', ' to ')} Point Transformation ---")
78
+ print(f"Original point: {original_point}")
79
+ print(f"Transformed point: {res}")
80
+ print(f"--------------------------------------------")
81
+ else:
82
+ print("Depth is 0")
83
+
84
+
85
+ from pynput import keyboard
86
+
87
+ # Global variable to track the key that was pressed
88
+ key_pressed = None
89
+
90
+
91
+ def on_press(key):
92
+ global key_pressed
93
+ try:
94
+ # Try to get the character key that was pressed
95
+ key_pressed = key.char
96
+ except AttributeError:
97
+ # Handle special keys like 'ESC'
98
+ if key == keyboard.Key.esc:
99
+ key_pressed = 'esc'
100
+
101
+
102
+ def main():
103
+ print_help() # Display help menu
104
+ config = ob.Config() # Initialize the config for the pipeline
105
+ pipeline = ob.Pipeline() # Create the pipeline object
106
+
107
+ try:
108
+ # Enable depth and color sensors
109
+ for sensor_type in [ob.OBSensorType.DEPTH_SENSOR, ob.OBSensorType.COLOR_SENSOR]:
110
+ profile_list = pipeline.get_stream_profile_list(sensor_type)
111
+ assert profile_list is not None
112
+ profile = profile_list.get_default_video_stream_profile()
113
+ assert profile is not None
114
+ print(f"{sensor_type} profile:", profile)
115
+ config.enable_stream(profile) # Enable the stream for the sensor
116
+ except Exception as e:
117
+ print(e)
118
+ return
119
+
120
+ print("start pipeline")
121
+ pipeline.start(config) # Start the pipeline with the config
122
+
123
+ # Dictionary mapping key input to transformation functions and dimension types
124
+ transform_functions = {
125
+ '1': (ob.transformation2dto2d, "2d_to_2d"),
126
+ '2': (ob.transformation2dto3d, "2d_to_3d"),
127
+ '3': (ob.transformation3dto3d, "3d_to_3d"),
128
+ '4': (ob.transformation3dto2d, "3d_to_2d")
129
+ }
130
+
131
+ # Start the keyboard listener to capture key presses
132
+ listener = keyboard.Listener(on_press=on_press)
133
+ listener.start()
134
+
135
+ while True:
136
+ try:
137
+ # Wait for frames from the pipeline (with a timeout of 100 ms)
138
+ frames = pipeline.wait_for_frames(100)
139
+ if frames is None:
140
+ continue
141
+
142
+ # Get depth and color frames from the captured frames
143
+ depth_frame = frames.get_depth_frame()
144
+ color_frame = frames.get_color_frame()
145
+
146
+ # Skip iteration if depth or color frame is not available
147
+ if depth_frame is None or color_frame is None:
148
+ continue
149
+
150
+ # check depth frame data size, if not match, print error
151
+ depth_width = depth_frame.get_width()
152
+ depth_height = depth_frame.get_height()
153
+ depth_data_size = depth_frame.get_data_size()
154
+ if depth_data_size != depth_width * depth_height * 2:
155
+ print("Error: depth frame data size does not match")
156
+ continue
157
+
158
+ # Check if a key was pressed
159
+ global key_pressed
160
+ if key_pressed:
161
+ # Convert the pressed key to lowercase
162
+ key = key_pressed.lower()
163
+ key_pressed = None # Reset key_pressed after handling it
164
+
165
+ # Check if the key corresponds to a transformation function
166
+ if key in transform_functions:
167
+ print("Transforming points...")
168
+ transform_func, dimension = transform_functions[key]
169
+ transform_points(transform_func, color_frame, depth_frame, dimension)
170
+ elif key in ['q', 'esc']: # Exit if 'q' or 'esc' is pressed
171
+ break
172
+ elif key == 'h': # Display help if 'h' is pressed
173
+ print_help()
174
+
175
+ except KeyboardInterrupt:
176
+ break
177
+
178
+ # Stop the pipeline and keyboard listener
179
+ pipeline.stop()
180
+ listener.stop()
181
+
182
+
183
+ if __name__ == "__main__":
184
+ main()