优化速度

This commit is contained in:
i
2026-04-21 20:52:41 +08:00
parent b3e99742dd
commit 39530852dd
2 changed files with 144 additions and 63 deletions
+2 -1
View File
@@ -3,4 +3,5 @@ Log/
.vscode/
camera_params.json
**.pyc**
data/
data/
.env
+142 -62
View File
@@ -180,6 +180,8 @@ class CameraWorker(QThread):
self._has_dual_ir = False
self._ir_enabled = False
self._last_emit_ts = 0.0
self._last_frames = None # 最近一帧,供"按键即拍"使用
self._capture_frames = None # 触发拍照时快照的帧
self._consec_timeouts = 0
self._disconnect_emitted = False
@@ -189,8 +191,9 @@ class CameraWorker(QThread):
def trigger_capture(self, save_dir: str):
with self._lock:
self._capture_dir = save_dir
self._do_capture = True
self._capture_dir = save_dir
self._capture_frames = self._last_frames # 快照当前帧
self._do_capture = True
def stop(self):
self._running = False
@@ -309,11 +312,14 @@ class CameraWorker(QThread):
self._consec_timeouts = 0
with self._lock:
d2c = self._d2c
do_cap = self._do_capture
cap_dir = self._capture_dir
self._last_frames = frames # 始终保存最新帧供快照
d2c = self._d2c
do_cap = self._do_capture
cap_dir = self._capture_dir
cap_frames = self._capture_frames
if do_cap:
self._do_capture = False
self._do_capture = False
self._capture_frames = None
# 首帧提取相机参数
if self._camera_params is None:
@@ -332,7 +338,7 @@ class CameraWorker(QThread):
if do_cap and cap_dir:
try:
self._run_capture(
frames, cap_dir,
cap_frames or frames, cap_dir,
align_filter, point_cloud_filter,
frame_to_bgr_image, save_point_cloud_to_ply,
OBFrameType, OBFormat,
@@ -521,6 +527,44 @@ class BatchD2CWorker(QThread):
self.done.emit()
# ─────────────────────────────────────────────────────────────────
# Toast Overlay(不阻塞鼠标,自动消失)
# ─────────────────────────────────────────────────────────────────
class _Toast(QLabel):
def __init__(self, parent: QWidget):
super().__init__(parent)
self.setAlignment(Qt.AlignCenter)
self.setAttribute(Qt.WA_TransparentForMouseEvents, True)
self.setStyleSheet(
"background: rgba(30,140,30,210);"
"color: white;"
"border-radius: 10px;"
"font-size: 15px;"
"padding: 10px 28px;"
)
self._timer = QTimer(self)
self._timer.setSingleShot(True)
self._timer.timeout.connect(self.hide)
self.hide()
def show_msg(self, text: str, ms: int = 1000):
self.setText(text)
self.adjustSize()
p = self.parent()
self.move((p.width() - self.width()) // 2,
p.height() - self.height() - 70)
self.raise_()
self.show()
self._timer.start(ms)
def reposition(self):
if self.isVisible():
p = self.parent()
self.move((p.width() - self.width()) // 2,
p.height() - self.height() - 70)
# ─────────────────────────────────────────────────────────────────
# Main Window
# ─────────────────────────────────────────────────────────────────
@@ -542,6 +586,8 @@ class MainWindow(QMainWindow):
self._depth_profiles_data: list[dict] = []
self._build_ui()
# toast 覆盖在 central widget 上
self._toast = _Toast(self.centralWidget())
# ─────────────────────────────────
# UI Construction
@@ -572,86 +618,100 @@ class MainWindow(QMainWindow):
tabs.addTab(self._build_d2c_tab(), " Orbbec Viewer 深度图 D2C ")
root.addWidget(tabs)
@staticmethod
def _step_group(num: int, title: str) -> QGroupBox:
grp = QGroupBox(f"第 {num} 步 · {title}")
grp.setStyleSheet(
"QGroupBox { font-weight:bold; font-size:12px; color:#8ec8ff;"
" border:1px solid #444; border-radius:5px; margin-top:6px; padding-top:4px; }"
"QGroupBox::title { subcontrol-origin:margin; left:10px; padding:0 4px; }"
)
return grp
def _build_capture_tab(self) -> QWidget:
w = QWidget()
layout = QVBoxLayout(w)
layout.setContentsMargins(12, 10, 12, 10)
layout.setSpacing(8)
layout.setContentsMargins(12, 8, 12, 8)
layout.setSpacing(6)
# ── 设备刷新行 ──
dev_row = QHBoxLayout()
COMBO_CSS = "QComboBox { combobox-popup: 0; }"
# ── 第 1 步:刷新设备 ──
grp1 = self._step_group(1, "刷新设备")
g1 = QHBoxLayout(grp1)
g1.setContentsMargins(8, 4, 8, 6)
refresh_btn = QPushButton("刷新设备")
refresh_btn.setFixedHeight(30)
refresh_btn.setFixedHeight(28)
refresh_btn.clicked.connect(self._refresh_devices)
dev_row.addWidget(refresh_btn)
g1.addWidget(refresh_btn)
self.device_status = QLabel("未连接设备,请点击「刷新设备」")
self.device_status.setStyleSheet("color: #aaa; font-size: 12px;")
dev_row.addWidget(self.device_status)
dev_row.addStretch()
layout.addLayout(dev_row)
self.device_status.setStyleSheet("color:#aaa; font-size:12px;")
g1.addWidget(self.device_status)
g1.addStretch()
layout.addWidget(grp1)
# ── 流配置行 ──
stream_grp = QGroupBox("流配置")
stream_layout = QHBoxLayout(stream_grp)
stream_layout.setSpacing(12)
# ── 第 2 步:流配置 ──
grp2 = self._step_group(2, "流配置")
g2 = QHBoxLayout(grp2)
g2.setContentsMargins(8, 4, 8, 6)
g2.setSpacing(10)
stream_layout.addWidget(QLabel("RGB:"))
g2.addWidget(QLabel("RGB:"))
self.color_combo = QComboBox()
self.color_combo.setMinimumWidth(260)
self.color_combo.setMinimumWidth(250)
self.color_combo.setMaxVisibleItems(12)
self.color_combo.setStyleSheet("QComboBox { combobox-popup: 0; }")
stream_layout.addWidget(self.color_combo)
self.color_combo.setStyleSheet(COMBO_CSS)
g2.addWidget(self.color_combo)
stream_layout.addSpacing(16)
stream_layout.addWidget(QLabel("深度:"))
g2.addSpacing(12)
g2.addWidget(QLabel("深度:"))
self.depth_combo = QComboBox()
self.depth_combo.setMinimumWidth(260)
self.depth_combo.setMinimumWidth(250)
self.depth_combo.setMaxVisibleItems(12)
self.depth_combo.setStyleSheet("QComboBox { combobox-popup: 0; }")
stream_layout.addWidget(self.depth_combo)
stream_layout.addStretch()
self.depth_combo.setStyleSheet(COMBO_CSS)
g2.addWidget(self.depth_combo)
g2.addStretch()
self.stream_btn = QPushButton("开启")
self.stream_btn.setCheckable(True)
self.stream_btn.setFixedSize(88, 32)
self.stream_btn.setFixedSize(88, 30)
self.stream_btn.setStyleSheet(
"QPushButton{ border-radius:6px; border:none; font-weight:bold; }"
"QPushButton{ border-radius:5px; border:none; font-weight:bold; }"
"QPushButton:!checked{ background:#555; color:#ccc; }"
"QPushButton:checked{ background:#2a8a2a; color:white; }"
"QPushButton:disabled{ background:#444; color:#777; }"
)
self.stream_btn.toggled.connect(self._on_stream_toggle)
stream_layout.addWidget(self.stream_btn)
g2.addWidget(self.stream_btn)
layout.addWidget(grp2)
layout.addWidget(stream_grp)
# ── 第 3 步:保存目录 ──
grp3 = self._step_group(3, "保存目录")
g3 = QHBoxLayout(grp3)
g3.setContentsMargins(8, 4, 8, 6)
g3.setSpacing(8)
# ── 目录 + D2C 控制行 ──
ctrl = QHBoxLayout()
ctrl.addWidget(QLabel("保存目录:"))
today = datetime.now()
self.session_edit = QLineEdit(f"{today.year}年{today.month}月{today.day}日")
self.session_edit.setMinimumWidth(170)
ctrl.addWidget(self.session_edit)
self.session_edit.setMinimumWidth(160)
g3.addWidget(self.session_edit)
create_btn = QPushButton("创建 / 载入")
create_btn.setFixedHeight(28)
create_btn.clicked.connect(self._create_session)
ctrl.addWidget(create_btn)
g3.addWidget(create_btn)
self.session_status = QLabel("(未创建)")
self.session_status.setStyleSheet("color:gray; font-size:12px;")
ctrl.addWidget(self.session_status)
ctrl.addStretch()
g3.addWidget(self.session_status)
g3.addStretch()
self.d2c_check = QCheckBox("启用 D2C 对齐预览")
self.d2c_check.setToolTip("勾选后预览使用 D2C 对齐;拍照时始终保存全部数据")
self.d2c_check.stateChanged.connect(
lambda s: self._worker and self._worker.set_d2c(s == Qt.Checked))
ctrl.addWidget(self.d2c_check)
layout.addLayout(ctrl)
g3.addWidget(self.d2c_check)
layout.addWidget(grp3)
# ── 预览区 ──
preview = QFrame()
@@ -669,7 +729,7 @@ class MainWindow(QMainWindow):
box.addWidget(hdr)
lbl = QLabel("等待画面…")
lbl.setAlignment(Qt.AlignCenter)
lbl.setMinimumSize(540, 380)
lbl.setMinimumSize(540, 360)
lbl.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
lbl.setStyleSheet("background:#111; border:1px solid #555; color:#666;")
setattr(self, attr, lbl)
@@ -678,13 +738,22 @@ class MainWindow(QMainWindow):
layout.addWidget(preview, stretch=1)
# ── 拍照按钮 ──
btn_row = QHBoxLayout()
btn_row.addStretch()
# ── 第 4 步:拍照 ──
step4_row = QHBoxLayout()
step4_lbl = QLabel("第 4 步 · 拍照")
step4_lbl.setStyleSheet(
"color:#8ec8ff; font-weight:bold; font-size:12px;")
step4_row.addWidget(step4_lbl)
step4_row.addStretch()
hint = QLabel("快捷键 S")
hint.setStyleSheet("color:#666; font-size:11px;")
step4_row.addWidget(hint)
self.capture_btn = QPushButton("拍照")
self.capture_btn.setFixedSize(160, 48)
self.capture_btn.setFixedSize(160, 44)
self.capture_btn.setEnabled(False)
f = QFont(); f.setPointSize(14); f.setBold(True)
f = QFont(); f.setPointSize(13); f.setBold(True)
self.capture_btn.setFont(f)
self.capture_btn.setStyleSheet(
"QPushButton{ background:#2a6ebb; color:white; border-radius:8px; border:none; }"
@@ -693,9 +762,8 @@ class MainWindow(QMainWindow):
"QPushButton:disabled{ background:#444; color:#777; }"
)
self.capture_btn.clicked.connect(self._on_capture)
btn_row.addWidget(self.capture_btn)
btn_row.addStretch()
layout.addLayout(btn_row)
step4_row.addWidget(self.capture_btn)
layout.addLayout(step4_row)
return w
@@ -983,11 +1051,7 @@ class MainWindow(QMainWindow):
def _on_capture_done(self, save_dir: str):
self.capture_btn.setEnabled(True)
self.capture_btn.setText("拍照")
msg = QMessageBox(QMessageBox.Information, "拍摄完成",
f"已保存至:\n{save_dir}", QMessageBox.Ok, self)
msg.setWindowModality(Qt.NonModal)
msg.show()
QTimer.singleShot(3000, msg.accept)
self._toast.show_msg("拍摄完成!", 1000)
# ─────────────────────────────────
# Batch D2C Tab
@@ -1088,6 +1152,22 @@ class MainWindow(QMainWindow):
def _append_d2c_log(self, msg: str):
self.d2c_log.append(msg)
# ─────────────────────────────────
# Keyboard & Resize
# ─────────────────────────────────
def keyPressEvent(self, event):
if event.key() == Qt.Key_S:
focused = QApplication.focusWidget()
if not isinstance(focused, (QLineEdit, QTextEdit)) and self.capture_btn.isEnabled():
self._on_capture()
return
super().keyPressEvent(event)
def resizeEvent(self, event):
super().resizeEvent(event)
self._toast.reposition()
# ─────────────────────────────────
# Close
# ─────────────────────────────────