pyorbbec 1.0.1.33__cp312-cp312-win_amd64.whl
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.
- OrbbecSDK.dll +0 -0
- OrbbecSDK.lib +0 -0
- OrbbecSDKConfig.xml +2332 -0
- extensions/depthengine/depthengine.dll +0 -0
- extensions/depthengine/depthengine.lib +0 -0
- extensions/filters/FilterProcessor.dll +0 -0
- extensions/filters/ob_priv_filter.dll +0 -0
- extensions/firmwareupdater/firmwareupdater.dll +0 -0
- extensions/frameprocessor/ob_frame_processor.dll +0 -0
- pyorbbec-1.0.1.33.dist-info/METADATA +11 -0
- pyorbbec-1.0.1.33.dist-info/RECORD +49 -0
- pyorbbec-1.0.1.33.dist-info/WHEEL +5 -0
- pyorbbec-1.0.1.33.dist-info/licenses/LICENSE +202 -0
- pyorbbec-1.0.1.33.dist-info/top_level.txt +1 -0
- pyorbbecsdk/config/OrbbecSDKConfig.md +222 -0
- pyorbbecsdk/config/OrbbecSDKConfig.xml +2332 -0
- pyorbbecsdk/config/multi_device_sync_config.json +28 -0
- pyorbbecsdk/examples/.gitkeep +0 -0
- pyorbbecsdk/examples/README.md +26 -0
- pyorbbecsdk/examples/callback.py +303 -0
- pyorbbecsdk/examples/color.py +64 -0
- pyorbbecsdk/examples/coordinate_transform.py +184 -0
- pyorbbecsdk/examples/depth.py +107 -0
- pyorbbecsdk/examples/depth_work_mode.py +59 -0
- pyorbbecsdk/examples/device_firmware_update.py +155 -0
- pyorbbecsdk/examples/device_optional_depth_presets_update.py +142 -0
- pyorbbecsdk/examples/enumerate.py +118 -0
- pyorbbecsdk/examples/hdr.py +216 -0
- pyorbbecsdk/examples/hot_plug.py +160 -0
- pyorbbecsdk/examples/hw_d2c_align.py +135 -0
- pyorbbecsdk/examples/imu.py +60 -0
- pyorbbecsdk/examples/infrared.py +148 -0
- pyorbbecsdk/examples/logger.py +55 -0
- pyorbbecsdk/examples/metadata.py +64 -0
- pyorbbecsdk/examples/multi_device.py +169 -0
- pyorbbecsdk/examples/multi_streams.py +219 -0
- pyorbbecsdk/examples/net_device.py +177 -0
- pyorbbecsdk/examples/playback.py +277 -0
- pyorbbecsdk/examples/point_cloud.py +90 -0
- pyorbbecsdk/examples/post_processing.py +119 -0
- pyorbbecsdk/examples/preset.py +67 -0
- pyorbbecsdk/examples/quick_start.py +90 -0
- pyorbbecsdk/examples/recorder.py +238 -0
- pyorbbecsdk/examples/requirements.txt +8 -0
- pyorbbecsdk/examples/save_image_to_disk.py +106 -0
- pyorbbecsdk/examples/sync_align.py +109 -0
- pyorbbecsdk/examples/two_devices_sync.py +233 -0
- pyorbbecsdk/examples/utils.py +127 -0
- pyorbbecsdk.cp312-win_amd64.pyd +0 -0
@@ -0,0 +1,67 @@
|
|
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 pyorbbecsdk as ob
|
18
|
+
|
19
|
+
def main():
|
20
|
+
# Create a pipeline with default device
|
21
|
+
pipe = ob.Pipeline()
|
22
|
+
|
23
|
+
# Get the device from the pipeline
|
24
|
+
device = pipe.get_device()
|
25
|
+
|
26
|
+
try:
|
27
|
+
while True:
|
28
|
+
# Get preset list from device
|
29
|
+
preset_list = device.get_available_preset_list()
|
30
|
+
if len(preset_list) == 0:
|
31
|
+
print("The current device does not support preset mode")
|
32
|
+
break
|
33
|
+
|
34
|
+
print("\nAvailable Presets:")
|
35
|
+
for index in range(len(preset_list)):
|
36
|
+
print(f" - {index}. {preset_list[index]}")
|
37
|
+
|
38
|
+
# Print current preset name
|
39
|
+
print(f"\nCurrent PresetName: {device.get_current_preset_name()}")
|
40
|
+
|
41
|
+
# Select preset to load
|
42
|
+
try:
|
43
|
+
input_option = int(input("\nEnter index of preset to load (or -1 to exit): "))
|
44
|
+
if input_option == -1:
|
45
|
+
break
|
46
|
+
if input_option < 0 or input_option >= len(preset_list):
|
47
|
+
raise ValueError("Invalid index")
|
48
|
+
except ValueError:
|
49
|
+
print("Invalid input. Please enter a valid index.")
|
50
|
+
continue
|
51
|
+
|
52
|
+
preset_name = preset_list[input_option]
|
53
|
+
|
54
|
+
# Load preset
|
55
|
+
device.load_preset(preset_name)
|
56
|
+
|
57
|
+
# Print current preset name
|
58
|
+
print(f"\nPreset loaded. Current PresetName: {device.get_current_preset_name()}")
|
59
|
+
|
60
|
+
except ob.OBError as e:
|
61
|
+
print(f"Error: {str(e)}")
|
62
|
+
finally:
|
63
|
+
# Stop Pipeline
|
64
|
+
pipe.stop()
|
65
|
+
|
66
|
+
if __name__ == "__main__":
|
67
|
+
main()
|
@@ -0,0 +1,90 @@
|
|
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 cv2
|
18
|
+
import numpy as np
|
19
|
+
import time
|
20
|
+
|
21
|
+
from pyorbbecsdk import *
|
22
|
+
from utils import frame_to_bgr_image
|
23
|
+
|
24
|
+
ESC_KEY = 27
|
25
|
+
MIN_DEPTH = 20 # 20mm
|
26
|
+
MAX_DEPTH = 10000 # 10000mm
|
27
|
+
|
28
|
+
def main():
|
29
|
+
pipeline = Pipeline()
|
30
|
+
|
31
|
+
pipeline.start()
|
32
|
+
print("Pipeline started successfully. Press 'q' or ESC to exit.")
|
33
|
+
|
34
|
+
# Set window size
|
35
|
+
window_width = 1280
|
36
|
+
window_height = 720
|
37
|
+
cv2.namedWindow("QuickStart Viewer", cv2.WINDOW_NORMAL)
|
38
|
+
cv2.resizeWindow("QuickStart Viewer", window_width, window_height)
|
39
|
+
|
40
|
+
while True:
|
41
|
+
try:
|
42
|
+
frames = pipeline.wait_for_frames(100)
|
43
|
+
if frames is None:
|
44
|
+
continue
|
45
|
+
|
46
|
+
# Get color frame
|
47
|
+
color_frame = frames.get_color_frame()
|
48
|
+
if color_frame is None:
|
49
|
+
continue
|
50
|
+
color_image = frame_to_bgr_image(color_frame)
|
51
|
+
|
52
|
+
# Get depth frame
|
53
|
+
depth_frame = frames.get_depth_frame()
|
54
|
+
if depth_frame is None:
|
55
|
+
continue
|
56
|
+
if depth_frame.get_format() != OBFormat.Y16:
|
57
|
+
print("Depth format is not Y16")
|
58
|
+
continue
|
59
|
+
|
60
|
+
# Process depth data
|
61
|
+
width = depth_frame.get_width()
|
62
|
+
height = depth_frame.get_height()
|
63
|
+
scale = depth_frame.get_depth_scale()
|
64
|
+
|
65
|
+
depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16).reshape((height, width))
|
66
|
+
depth_data = depth_data.astype(np.float32) * scale
|
67
|
+
depth_data = np.where((depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH), depth_data, 0).astype(np.uint16)
|
68
|
+
|
69
|
+
# Create depth visualization
|
70
|
+
depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
71
|
+
depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
|
72
|
+
|
73
|
+
# Resize and combine images
|
74
|
+
color_image_resized = cv2.resize(color_image, (window_width // 2, window_height))
|
75
|
+
depth_image_resized = cv2.resize(depth_image, (window_width // 2, window_height))
|
76
|
+
combined_image = np.hstack((color_image_resized, depth_image_resized))
|
77
|
+
|
78
|
+
cv2.imshow("QuickStart Viewer", combined_image)
|
79
|
+
|
80
|
+
if cv2.waitKey(1) in [ord('q'), ESC_KEY]:
|
81
|
+
break
|
82
|
+
except KeyboardInterrupt:
|
83
|
+
break
|
84
|
+
|
85
|
+
cv2.destroyAllWindows()
|
86
|
+
pipeline.stop()
|
87
|
+
print("Pipeline stopped and all windows closed.")
|
88
|
+
|
89
|
+
if __name__ == "__main__":
|
90
|
+
main()
|
@@ -0,0 +1,238 @@
|
|
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 cv2
|
18
|
+
import numpy as np
|
19
|
+
from pyorbbecsdk import *
|
20
|
+
from utils import frame_to_bgr_image
|
21
|
+
|
22
|
+
is_paused = False
|
23
|
+
# cached frames for better visualization
|
24
|
+
cached_frames = {
|
25
|
+
'color': None,
|
26
|
+
'depth': None,
|
27
|
+
'left_ir': None,
|
28
|
+
'right_ir': None,
|
29
|
+
'ir': None
|
30
|
+
}
|
31
|
+
|
32
|
+
def setup_camera():
|
33
|
+
"""Setup camera and stream configuration"""
|
34
|
+
pipeline = Pipeline()
|
35
|
+
config = Config()
|
36
|
+
device = pipeline.get_device()
|
37
|
+
|
38
|
+
# Try to enable all possible sensors
|
39
|
+
video_sensors = [
|
40
|
+
OBSensorType.COLOR_SENSOR,
|
41
|
+
OBSensorType.DEPTH_SENSOR,
|
42
|
+
OBSensorType.IR_SENSOR,
|
43
|
+
OBSensorType.LEFT_IR_SENSOR,
|
44
|
+
OBSensorType.RIGHT_IR_SENSOR
|
45
|
+
]
|
46
|
+
sensor_list = device.get_sensor_list()
|
47
|
+
for sensor in range(len(sensor_list)):
|
48
|
+
try:
|
49
|
+
sensor_type = sensor_list[sensor].get_type()
|
50
|
+
if sensor_type in video_sensors:
|
51
|
+
config.enable_stream(sensor_type)
|
52
|
+
except:
|
53
|
+
continue
|
54
|
+
|
55
|
+
pipeline.start(config)
|
56
|
+
return pipeline
|
57
|
+
|
58
|
+
def setup_imu():
|
59
|
+
"""Setup IMU configuration"""
|
60
|
+
pipeline = Pipeline()
|
61
|
+
config = Config()
|
62
|
+
config.enable_accel_stream()
|
63
|
+
config.enable_gyro_stream()
|
64
|
+
pipeline.start(config)
|
65
|
+
return pipeline
|
66
|
+
|
67
|
+
def process_color(frame):
|
68
|
+
"""Process color image"""
|
69
|
+
frame = frame if frame else cached_frames['color']
|
70
|
+
cached_frames['color'] = frame
|
71
|
+
return frame_to_bgr_image(frame) if frame else None
|
72
|
+
|
73
|
+
|
74
|
+
def process_depth(frame):
|
75
|
+
"""Process depth image"""
|
76
|
+
frame = frame if frame else cached_frames['depth']
|
77
|
+
cached_frames['depth'] = frame
|
78
|
+
if not frame:
|
79
|
+
return None
|
80
|
+
try:
|
81
|
+
depth_data = np.frombuffer(frame.get_data(), dtype=np.uint16)
|
82
|
+
depth_data = depth_data.reshape(frame.get_height(), frame.get_width())
|
83
|
+
depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
84
|
+
return cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
|
85
|
+
except ValueError:
|
86
|
+
return None
|
87
|
+
|
88
|
+
|
89
|
+
def process_ir(ir_frame):
|
90
|
+
"""Process IR frame (left or right) to RGB image"""
|
91
|
+
if ir_frame is None:
|
92
|
+
return None
|
93
|
+
ir_frame = ir_frame.as_video_frame()
|
94
|
+
ir_data = np.asanyarray(ir_frame.get_data())
|
95
|
+
width = ir_frame.get_width()
|
96
|
+
height = ir_frame.get_height()
|
97
|
+
ir_format = ir_frame.get_format()
|
98
|
+
|
99
|
+
if ir_format == OBFormat.Y8:
|
100
|
+
ir_data = np.resize(ir_data, (height, width, 1))
|
101
|
+
data_type = np.uint8
|
102
|
+
image_dtype = cv2.CV_8UC1
|
103
|
+
max_data = 255
|
104
|
+
elif ir_format == OBFormat.MJPG:
|
105
|
+
ir_data = cv2.imdecode(ir_data, cv2.IMREAD_UNCHANGED)
|
106
|
+
data_type = np.uint8
|
107
|
+
image_dtype = cv2.CV_8UC1
|
108
|
+
max_data = 255
|
109
|
+
if ir_data is None:
|
110
|
+
print("decode mjpeg failed")
|
111
|
+
return None
|
112
|
+
ir_data = np.resize(ir_data, (height, width, 1))
|
113
|
+
else:
|
114
|
+
ir_data = np.frombuffer(ir_data, dtype=np.uint16)
|
115
|
+
data_type = np.uint16
|
116
|
+
image_dtype = cv2.CV_16UC1
|
117
|
+
max_data = 255
|
118
|
+
ir_data = np.resize(ir_data, (height, width, 1))
|
119
|
+
|
120
|
+
cv2.normalize(ir_data, ir_data, 0, max_data, cv2.NORM_MINMAX, dtype=image_dtype)
|
121
|
+
ir_data = ir_data.astype(data_type)
|
122
|
+
return cv2.cvtColor(ir_data, cv2.COLOR_GRAY2RGB)
|
123
|
+
|
124
|
+
def get_imu_text(frame, name):
|
125
|
+
"""Format IMU data"""
|
126
|
+
if not frame:
|
127
|
+
return []
|
128
|
+
return [
|
129
|
+
f"{name} x: {frame.get_x():.2f}",
|
130
|
+
f"{name} y: {frame.get_y():.2f}",
|
131
|
+
f"{name} z: {frame.get_z():.2f}"
|
132
|
+
]
|
133
|
+
|
134
|
+
|
135
|
+
def create_display(frames, width=1280, height=720):
|
136
|
+
"""Create display window"""
|
137
|
+
display = np.zeros((height, width, 3), dtype=np.uint8)
|
138
|
+
h, w = height // 2, width // 2
|
139
|
+
|
140
|
+
# Process video frames
|
141
|
+
if 'color' in frames and frames['color'] is not None:
|
142
|
+
display[0:h, 0:w] = cv2.resize(frames['color'], (w, h))
|
143
|
+
|
144
|
+
if 'depth' in frames and frames['depth'] is not None:
|
145
|
+
display[0:h, w:] = cv2.resize(frames['depth'], (w, h))
|
146
|
+
|
147
|
+
if 'ir' in frames and frames['ir'] is not None:
|
148
|
+
display[h:, 0:w] = cv2.resize(frames['ir'], (w, h))
|
149
|
+
|
150
|
+
# Display IMU data
|
151
|
+
if 'imu' in frames:
|
152
|
+
y_offset = h + 20
|
153
|
+
for data_type in ['accel', 'gyro']:
|
154
|
+
text_lines = get_imu_text(frames['imu'].get(data_type), data_type.title())
|
155
|
+
for i, line in enumerate(text_lines):
|
156
|
+
cv2.putText(display, line, (w + 10, y_offset + i * 20),
|
157
|
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
158
|
+
y_offset += 80
|
159
|
+
|
160
|
+
return display
|
161
|
+
|
162
|
+
|
163
|
+
def main():
|
164
|
+
# Window settings
|
165
|
+
WINDOW_NAME = "MultiStream Record Viewer"
|
166
|
+
file_path = input("Enter output filename (.bag) and press Enter to start recording: ")
|
167
|
+
|
168
|
+
DISPLAY_WIDTH = 1280
|
169
|
+
DISPLAY_HEIGHT = 720
|
170
|
+
|
171
|
+
# Initialize camera
|
172
|
+
pipeline = setup_camera()
|
173
|
+
device = pipeline.get_device()
|
174
|
+
#synchronize the timer of the device with the host
|
175
|
+
device.timer_sync_with_host();
|
176
|
+
# initialize recording
|
177
|
+
recorder = RecordDevice(device, file_path)
|
178
|
+
imu_pipeline = setup_imu()
|
179
|
+
cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL)
|
180
|
+
cv2.resizeWindow(WINDOW_NAME, DISPLAY_WIDTH, DISPLAY_HEIGHT)
|
181
|
+
while True:
|
182
|
+
# Get all frames
|
183
|
+
frames = pipeline.wait_for_frames(100)
|
184
|
+
if not frames:
|
185
|
+
continue
|
186
|
+
# Process different frame types
|
187
|
+
processed_frames = {'color': process_color(frames.get_color_frame()),
|
188
|
+
'depth': process_depth(frames.get_depth_frame())}
|
189
|
+
|
190
|
+
# Process IR image: try stereo IR first, fallback to mono if unavailable
|
191
|
+
try:
|
192
|
+
left = process_ir(frames.get_frame(OBFrameType.LEFT_IR_FRAME).as_video_frame())
|
193
|
+
right = process_ir(frames.get_frame(OBFrameType.RIGHT_IR_FRAME).as_video_frame())
|
194
|
+
if left is not None and right is not None:
|
195
|
+
processed_frames['ir'] = np.hstack((left, right))
|
196
|
+
except:
|
197
|
+
ir_frame = frames.get_ir_frame()
|
198
|
+
if ir_frame:
|
199
|
+
processed_frames['ir'] = process_ir(ir_frame.as_video_frame())
|
200
|
+
|
201
|
+
# Process IMU data
|
202
|
+
imu_frames = imu_pipeline.wait_for_frames(100)
|
203
|
+
if not imu_frames:
|
204
|
+
continue
|
205
|
+
accel = imu_frames.get_frame(OBFrameType.ACCEL_FRAME)
|
206
|
+
gyro = imu_frames.get_frame(OBFrameType.GYRO_FRAME)
|
207
|
+
if accel and gyro:
|
208
|
+
processed_frames['imu'] = {
|
209
|
+
'accel': accel.as_accel_frame(),
|
210
|
+
'gyro': gyro.as_gyro_frame()
|
211
|
+
}
|
212
|
+
|
213
|
+
# create display
|
214
|
+
display = create_display(processed_frames, DISPLAY_WIDTH, DISPLAY_HEIGHT)
|
215
|
+
cv2.imshow(WINDOW_NAME, display)
|
216
|
+
|
217
|
+
# check exit key
|
218
|
+
key = cv2.waitKey(1) & 0xFF
|
219
|
+
if key == ord('s'):
|
220
|
+
global is_paused
|
221
|
+
if not is_paused:
|
222
|
+
recorder.pause()
|
223
|
+
is_paused = True
|
224
|
+
print("[PAUSED] Recording paused")
|
225
|
+
else:
|
226
|
+
recorder.resume()
|
227
|
+
is_paused = False
|
228
|
+
print("[RESUMED] Recording resumed")
|
229
|
+
if key in (ord('q'), 27):
|
230
|
+
break
|
231
|
+
|
232
|
+
pipeline.stop()
|
233
|
+
recorder = None
|
234
|
+
cv2.destroyAllWindows()
|
235
|
+
|
236
|
+
|
237
|
+
if __name__ == "__main__":
|
238
|
+
main()
|
@@ -0,0 +1,106 @@
|
|
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 os
|
17
|
+
|
18
|
+
import cv2
|
19
|
+
import numpy as np
|
20
|
+
|
21
|
+
from pyorbbecsdk import *
|
22
|
+
from utils import frame_to_bgr_image
|
23
|
+
|
24
|
+
|
25
|
+
def save_depth_frame(frame: DepthFrame, index):
|
26
|
+
if frame is None:
|
27
|
+
return
|
28
|
+
width = frame.get_width()
|
29
|
+
height = frame.get_height()
|
30
|
+
timestamp = frame.get_timestamp()
|
31
|
+
scale = frame.get_depth_scale()
|
32
|
+
depth_format = frame.get_format()
|
33
|
+
if depth_format != OBFormat.Y16:
|
34
|
+
print("depth format is not Y16")
|
35
|
+
return
|
36
|
+
data = np.frombuffer(frame.get_data(), dtype=np.uint16)
|
37
|
+
data = data.reshape((height, width))
|
38
|
+
data = data.astype(np.float32) * scale
|
39
|
+
data = data.astype(np.uint16)
|
40
|
+
save_image_dir = os.path.join(os.getcwd(), "depth_images")
|
41
|
+
if not os.path.exists(save_image_dir):
|
42
|
+
os.mkdir(save_image_dir)
|
43
|
+
raw_filename = save_image_dir + "/depth_{}x{}_{}_{}.raw".format(width, height, index, timestamp)
|
44
|
+
data.tofile(raw_filename)
|
45
|
+
|
46
|
+
|
47
|
+
def save_color_frame(frame: ColorFrame, index):
|
48
|
+
if frame is None:
|
49
|
+
return
|
50
|
+
width = frame.get_width()
|
51
|
+
height = frame.get_height()
|
52
|
+
timestamp = frame.get_timestamp()
|
53
|
+
save_image_dir = os.path.join(os.getcwd(), "color_images")
|
54
|
+
if not os.path.exists(save_image_dir):
|
55
|
+
os.mkdir(save_image_dir)
|
56
|
+
filename = save_image_dir + "/color_{}x{}_{}_{}.png".format(width, height, index, timestamp)
|
57
|
+
image = frame_to_bgr_image(frame)
|
58
|
+
if image is None:
|
59
|
+
print("failed to convert frame to image")
|
60
|
+
return
|
61
|
+
cv2.imwrite(filename, image)
|
62
|
+
|
63
|
+
|
64
|
+
def main():
|
65
|
+
pipeline = Pipeline()
|
66
|
+
config = Config()
|
67
|
+
saved_color_cnt: int = 0
|
68
|
+
saved_depth_cnt: int = 0
|
69
|
+
has_color_sensor = False
|
70
|
+
try:
|
71
|
+
profile_list = pipeline.get_stream_profile_list(OBSensorType.COLOR_SENSOR)
|
72
|
+
if profile_list is not None:
|
73
|
+
color_profile: VideoStreamProfile = profile_list.get_default_video_stream_profile()
|
74
|
+
config.enable_stream(color_profile)
|
75
|
+
has_color_sensor = True
|
76
|
+
except OBError as e:
|
77
|
+
print(e)
|
78
|
+
depth_profile_list = pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
|
79
|
+
if depth_profile_list is not None:
|
80
|
+
depth_profile = depth_profile_list.get_default_video_stream_profile()
|
81
|
+
config.enable_stream(depth_profile)
|
82
|
+
pipeline.start(config)
|
83
|
+
while True:
|
84
|
+
try:
|
85
|
+
frames = pipeline.wait_for_frames(100)
|
86
|
+
if frames is None:
|
87
|
+
continue
|
88
|
+
if has_color_sensor:
|
89
|
+
if saved_color_cnt >= 5 and saved_depth_cnt >= 5:
|
90
|
+
break
|
91
|
+
elif saved_depth_cnt >= 5:
|
92
|
+
break
|
93
|
+
color_frame = frames.get_color_frame()
|
94
|
+
if color_frame is not None and saved_color_cnt < 5:
|
95
|
+
save_color_frame(color_frame, saved_color_cnt)
|
96
|
+
saved_color_cnt += 1
|
97
|
+
depth_frame = frames.get_depth_frame()
|
98
|
+
if depth_frame is not None and saved_depth_cnt < 5:
|
99
|
+
save_depth_frame(depth_frame, saved_depth_cnt)
|
100
|
+
saved_depth_cnt += 1
|
101
|
+
except KeyboardInterrupt:
|
102
|
+
break
|
103
|
+
|
104
|
+
|
105
|
+
if __name__ == "__main__":
|
106
|
+
main()
|
@@ -0,0 +1,109 @@
|
|
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 argparse
|
17
|
+
import sys
|
18
|
+
|
19
|
+
import cv2
|
20
|
+
import numpy as np
|
21
|
+
|
22
|
+
from pyorbbecsdk import *
|
23
|
+
from utils import frame_to_bgr_image
|
24
|
+
|
25
|
+
ESC_KEY = 27
|
26
|
+
|
27
|
+
MIN_DEPTH = 20 # 20mm
|
28
|
+
MAX_DEPTH = 10000 # 10000mm
|
29
|
+
# Temporal filter for smoothing depth data over time
|
30
|
+
|
31
|
+
def main(argv):
|
32
|
+
pipeline = Pipeline()
|
33
|
+
config = Config()
|
34
|
+
parser = argparse.ArgumentParser()
|
35
|
+
parser.add_argument("-s", "--enable_sync", help="enable sync", type=bool, default=True)
|
36
|
+
args = parser.parse_args(argv)
|
37
|
+
|
38
|
+
enable_sync = args.enable_sync
|
39
|
+
try:
|
40
|
+
profile_list = pipeline.get_stream_profile_list(OBSensorType.COLOR_SENSOR)
|
41
|
+
color_profile = profile_list.get_default_video_stream_profile()
|
42
|
+
config.enable_stream(color_profile)
|
43
|
+
profile_list = pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
|
44
|
+
depth_profile = profile_list.get_default_video_stream_profile()
|
45
|
+
config.enable_stream(depth_profile)
|
46
|
+
except Exception as e:
|
47
|
+
print(e)
|
48
|
+
return
|
49
|
+
|
50
|
+
if enable_sync:
|
51
|
+
try:
|
52
|
+
pipeline.enable_frame_sync()
|
53
|
+
except Exception as e:
|
54
|
+
print(e)
|
55
|
+
|
56
|
+
try:
|
57
|
+
pipeline.start(config)
|
58
|
+
except Exception as e:
|
59
|
+
print(e)
|
60
|
+
return
|
61
|
+
|
62
|
+
align_filter = AlignFilter(align_to_stream=OBStreamType.COLOR_STREAM)
|
63
|
+
|
64
|
+
while True:
|
65
|
+
try:
|
66
|
+
frames = pipeline.wait_for_frames(100)
|
67
|
+
if not frames:
|
68
|
+
continue
|
69
|
+
color_frame = frames.get_color_frame()
|
70
|
+
depth_frame = frames.get_depth_frame()
|
71
|
+
if not color_frame or not depth_frame:
|
72
|
+
continue
|
73
|
+
frames = align_filter.process(frames)
|
74
|
+
if not frames:
|
75
|
+
continue
|
76
|
+
frames = frames.as_frame_set()
|
77
|
+
color_frame = frames.get_color_frame()
|
78
|
+
depth_frame = frames.get_depth_frame()
|
79
|
+
if not color_frame or not depth_frame:
|
80
|
+
continue
|
81
|
+
|
82
|
+
color_image = frame_to_bgr_image(color_frame)
|
83
|
+
if color_image is None:
|
84
|
+
print("Failed to convert frame to image")
|
85
|
+
continue
|
86
|
+
try:
|
87
|
+
depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16).reshape(
|
88
|
+
(depth_frame.get_height(), depth_frame.get_width()))
|
89
|
+
except ValueError:
|
90
|
+
print("Failed to reshape depth data")
|
91
|
+
continue
|
92
|
+
depth_data = depth_data.astype(np.float32) * depth_frame.get_depth_scale()
|
93
|
+
depth_data = np.where((depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH), depth_data, 0)
|
94
|
+
depth_data = depth_data.astype(np.uint16)
|
95
|
+
depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX)
|
96
|
+
depth_image = cv2.applyColorMap(depth_image.astype(np.uint8), cv2.COLORMAP_JET)
|
97
|
+
depth_image = cv2.addWeighted(color_image, 0.5, depth_image, 0.5, 0)
|
98
|
+
|
99
|
+
cv2.imshow("SyncAlignViewer", depth_image)
|
100
|
+
if cv2.waitKey(1) in [ord('q'), ESC_KEY]:
|
101
|
+
break
|
102
|
+
except KeyboardInterrupt:
|
103
|
+
break
|
104
|
+
cv2.destroyAllWindows()
|
105
|
+
pipeline.stop()
|
106
|
+
|
107
|
+
|
108
|
+
if __name__ == "__main__":
|
109
|
+
main(sys.argv[1:])
|