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.
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/MANIFEST.in +1 -0
- {pyorbbec-1.0.1.7/src/pyorbbec.egg-info → pyorbbec-1.0.1.9}/PKG-INFO +1 -1
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/setup.py +1 -1
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9/src/pyorbbec.egg-info}/PKG-INFO +1 -1
- pyorbbec-1.0.1.9/src/pyorbbec.egg-info/SOURCES.txt +54 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/.gitkeep +0 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/README.md +26 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/callback.py +303 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/color.py +64 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/coordinate_transform.py +184 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/depth.py +107 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/depth_work_mode.py +50 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/device_firmware_update.py +155 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/device_optional_depth_presets_update.py +142 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/enumerate.py +118 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hdr.py +216 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hot_plug.py +160 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/hw_d2c_align.py +135 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/imu.py +60 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/infrared.py +115 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/logger.py +55 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/metadata.py +64 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/multi_device.py +169 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/multi_streams.py +219 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/net_device.py +158 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/playback.py +277 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/point_cloud.py +90 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/post_processing.py +119 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/preset.py +67 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/quick_start.py +90 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/recorder.py +236 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/requirements.txt +9 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/save_image_to_disk.py +106 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/sync_align.py +109 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/two_devices_sync.py +233 -0
- pyorbbec-1.0.1.9/src/pyorbbecsdk/examples/utils.py +127 -0
- pyorbbec-1.0.1.7/src/pyorbbec.egg-info/SOURCES.txt +0 -23
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/LICENSE +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/NOTICE +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/README.md +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/pyproject.toml +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/setup.cfg +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/dependency_links.txt +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/not-zip-safe +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbec.egg-info/top_level.txt +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDK.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDK.lib +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/OrbbecSDKConfig.xml +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/__init__.py +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/__version__.py +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/depthengine/depthengine.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/depthengine/depthengine.lib +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/filters/FilterProcessor.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/filters/ob_priv_filter.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/firmwareupdater/firmwareupdater.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/extensions/frameprocessor/ob_frame_processor.dll +0 -0
- {pyorbbec-1.0.1.7 → pyorbbec-1.0.1.9}/src/pyorbbecsdk/pyorbbecsdk.cp313-win_amd64.pyd +0 -0
@@ -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()
|