BodyBalanceEvaluation/backend/tests/testfemtobolt.py
2025-08-19 18:15:56 +08:00

117 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import numpy as np
import cv2
from matplotlib.colors import LinearSegmentedColormap
class FemtoBoltViewer:
def __init__(self, depth_min=900, depth_max=1300):
self.depth_min = depth_min
self.depth_max = depth_max
# 自定义彩虹色 colormap
colors = ['fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue']
self.cmap = LinearSegmentedColormap.from_list("custom_cmap", colors)
# SDK 设备句柄和配置
self.device_handle = None
self.pykinect = None
self.config = None
# 缓存背景+网格图像(仅生成一次)
self.background = None
# OpenCV 窗口
cv2.namedWindow("Depth CV")
def _load_sdk(self):
"""加载并初始化 FemtoBolt SDK"""
try:
import pykinect_azure as pykinect
self.pykinect = pykinect
base_dir = os.path.dirname(os.path.abspath(__file__))
dll_path = os.path.join(base_dir, "..", "dll", "femtobolt", "bin", "k4a.dll")
self.pykinect.initialize_libraries(track_body=False, module_k4a_path=dll_path)
return True
except Exception as e:
print(f"加载 SDK 失败: {e}")
return False
def _configure_device(self):
"""配置 FemtoBolt 深度相机"""
self.config = self.pykinect.default_configuration
self.config.depth_mode = self.pykinect.K4A_DEPTH_MODE_NFOV_UNBINNED
self.config.camera_fps = self.pykinect.K4A_FRAMES_PER_SECOND_15
self.config.synchronized_images_only = False
self.config.color_resolution = 0
self.device_handle = self.pykinect.start_device(config=self.config)
def _get_color_image(self, depth_image):
"""将原始深度图转换为叠加背景网格后的 RGB 彩色图像"""
h, w = depth_image.shape
# 第一次调用时生成灰色背景和白色网格
if self.background is None:
self.background = np.full((h, w, 3), 128, dtype=np.uint8) # 灰色 (0.5 -> 128)
# 绘制网格线
for x in range(w):
cv2.line(self.background, (x, 0), (x, h-1), (255, 255, 255), 1)
for y in range(h):
cv2.line(self.background, (0, y), (w-1, y), (255, 255, 255), 1)
# 生成深度掩码,仅保留指定范围内的像素
mask_valid = (depth_image >= self.depth_min) & (depth_image <= self.depth_max)
depth_clipped = np.clip(depth_image, self.depth_min, self.depth_max)
normed = (depth_clipped.astype(np.float32) - self.depth_min) / (self.depth_max - self.depth_min)
# 反转映射,保证颜色方向与之前一致
normed = 1.0 - normed
# 应用自定义 colormap将深度值映射到 RGB
rgba = self.cmap(normed)
rgb = (rgba[..., :3] * 255).astype(np.uint8)
# 叠加:在背景上覆盖彩色深度图(掩码处不覆盖,保留灰色背景+网格)
final_img = self.background.copy()
final_img[mask_valid] = rgb[mask_valid]
return final_img
def run(self):
if not self._load_sdk():
print("SDK 加载失败,程序退出")
return
self._configure_device()
print("FemtoBolt 深度相机启动成功,按 Ctrl+C 或 ESC 退出")
try:
while True:
capture = self.device_handle.update()
if capture is None:
continue
ret, depth_image = capture.get_depth_image()
if not ret or depth_image is None:
continue
# 转换并渲染当前帧
final_img = self._get_color_image(depth_image)
# OpenCV 显示
cv2.imshow("Depth CV", final_img)
# 按 ESC 键退出
if cv2.waitKey(1) & 0xFF == 27:
break
except KeyboardInterrupt:
print("检测到退出信号,结束程序")
finally:
if self.device_handle:
self.device_handle.stop()
self.device_handle.close()
cv2.destroyAllWindows()
if __name__ == "__main__":
viewer = FemtoBoltViewer(depth_min=900, depth_max=1100)
viewer.run()