b
This commit is contained in:
@@ -51,7 +51,7 @@ from PyQt5.QtWidgets import (
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
|
||||
from PyQt5.QtGui import QImage, QPixmap, QFont
|
||||
|
||||
from d2c_batch import batch_convert
|
||||
from d2c_batch import batch_convert, software_d2c, software_d2c_inv
|
||||
|
||||
PARAMS_FILE = "camera_params.json"
|
||||
MIN_DEPTH_MM, MAX_DEPTH_MM = 200, 5000
|
||||
@@ -435,12 +435,17 @@ class CameraWorker(QThread):
|
||||
self._disconnect_emitted = False
|
||||
self._sync_wait_count = 0 # 等待同步帧的计数器
|
||||
self._splat_radius = 0
|
||||
self._d2c_method = "sdk"
|
||||
self._capture_opts: dict = {}
|
||||
|
||||
def set_d2c(self, enabled: bool):
|
||||
with self._lock:
|
||||
self._d2c = enabled
|
||||
|
||||
def set_d2c_method(self, method: str):
|
||||
with self._lock:
|
||||
self._d2c_method = method
|
||||
|
||||
def set_splat(self, radius: int):
|
||||
with self._lock:
|
||||
self._splat_radius = radius
|
||||
@@ -586,11 +591,12 @@ class CameraWorker(QThread):
|
||||
self._consec_timeouts = 0
|
||||
|
||||
with self._lock:
|
||||
d2c = self._d2c
|
||||
do_cap = self._do_capture
|
||||
cap_dir = self._capture_dir
|
||||
splat_r = self._splat_radius
|
||||
cap_opts = self._capture_opts
|
||||
d2c = self._d2c
|
||||
d2c_method = self._d2c_method
|
||||
do_cap = self._do_capture
|
||||
cap_dir = self._capture_dir
|
||||
splat_r = self._splat_radius
|
||||
cap_opts = self._capture_opts
|
||||
|
||||
# 首帧提取相机参数
|
||||
if self._camera_params is None:
|
||||
@@ -636,14 +642,8 @@ class CameraWorker(QThread):
|
||||
continue
|
||||
|
||||
# 预览
|
||||
view = frames
|
||||
if d2c:
|
||||
af = align_filter.process(frames)
|
||||
if af:
|
||||
view = af.as_frame_set()
|
||||
|
||||
cf = view.get_color_frame()
|
||||
df = view.get_depth_frame()
|
||||
cf = frames.get_color_frame()
|
||||
df = frames.get_depth_frame()
|
||||
if not cf or not df:
|
||||
continue
|
||||
|
||||
@@ -651,11 +651,31 @@ class CameraWorker(QThread):
|
||||
if color_bgr is None:
|
||||
continue
|
||||
|
||||
depth_data = np.frombuffer(df.get_data(), dtype=np.uint16).reshape(
|
||||
df.get_height(), df.get_width())
|
||||
if splat_r > 0:
|
||||
depth_data = _splat_depth(depth_data, splat_r)
|
||||
depth_vis = depth_to_vis(depth_data, df.get_depth_scale())
|
||||
if d2c:
|
||||
if d2c_method == "forward" and self._camera_params is not None:
|
||||
raw = np.frombuffer(df.get_data(), dtype=np.uint16).reshape(
|
||||
df.get_height(), df.get_width())
|
||||
depth_data = software_d2c(
|
||||
raw, self._camera_params, splat_radius=splat_r)
|
||||
depth_scale = df.get_depth_scale()
|
||||
else:
|
||||
af = align_filter.process(frames)
|
||||
if af:
|
||||
view = af.as_frame_set()
|
||||
df2 = view.get_depth_frame()
|
||||
if df2:
|
||||
df = df2
|
||||
depth_data = np.frombuffer(df.get_data(), dtype=np.uint16).reshape(
|
||||
df.get_height(), df.get_width())
|
||||
depth_scale = df.get_depth_scale()
|
||||
else:
|
||||
depth_data = np.frombuffer(df.get_data(), dtype=np.uint16).reshape(
|
||||
df.get_height(), df.get_width())
|
||||
if splat_r > 0:
|
||||
depth_data = _splat_depth(depth_data, splat_r)
|
||||
depth_scale = df.get_depth_scale()
|
||||
|
||||
depth_vis = depth_to_vis(depth_data, depth_scale)
|
||||
|
||||
now = time.monotonic()
|
||||
if now - self._last_emit_ts >= 0.033:
|
||||
@@ -717,40 +737,59 @@ class CameraWorker(QThread):
|
||||
imwrite_utf8(str(base / "depth_vis.png"),
|
||||
depth_to_vis(raw, df.get_depth_scale()))
|
||||
|
||||
need_aligned = (capture_opts.get("d2c", True) or
|
||||
d2c_method = capture_opts.get("d2c_method", "sdk")
|
||||
need_aligned = ((d2c_method == "sdk" and capture_opts.get("d2c", True)) or
|
||||
capture_opts.get("pc", False) or
|
||||
capture_opts.get("pc_color", False))
|
||||
aset = None
|
||||
if need_aligned:
|
||||
aligned = align_filter.process(frames)
|
||||
if aligned:
|
||||
aset = aligned.as_frame_set()
|
||||
adf = aset.get_depth_frame()
|
||||
if adf and capture_opts.get("d2c", True):
|
||||
|
||||
# D2C 深度图保存
|
||||
if capture_opts.get("d2c", True):
|
||||
if d2c_method == "sdk" and aset:
|
||||
adf = aset.get_depth_frame()
|
||||
if adf:
|
||||
ad = np.frombuffer(adf.get_data(), dtype=np.uint16).reshape(
|
||||
adf.get_height(), adf.get_width())
|
||||
imwrite_utf8(str(base / "depth_d2c.png"), ad)
|
||||
imwrite_utf8(str(base / "depth_d2c_vis.png"),
|
||||
depth_to_vis(ad, adf.get_depth_scale()))
|
||||
elif self._camera_params is not None:
|
||||
raw = np.frombuffer(df.get_data(), dtype=np.uint16).reshape(
|
||||
df.get_height(), df.get_width())
|
||||
if d2c_method == "inverse":
|
||||
aligned_img = software_d2c_inv(raw, self._camera_params)
|
||||
else: # forward
|
||||
splat_r = capture_opts.get("splat_radius", 1)
|
||||
aligned_img = software_d2c(raw, self._camera_params, splat_radius=splat_r)
|
||||
imwrite_utf8(str(base / "depth_d2c.png"), aligned_img)
|
||||
imwrite_utf8(str(base / "depth_d2c_vis.png"),
|
||||
depth_to_vis(aligned_img, df.get_depth_scale()))
|
||||
|
||||
if capture_opts.get("pc", False):
|
||||
try:
|
||||
point_cloud_filter.set_create_point_format(OBFormat.POINT)
|
||||
pc = point_cloud_filter.process(aligned)
|
||||
if pc:
|
||||
save_ply_utf8(str(base / "point_cloud.ply"), pc,
|
||||
save_point_cloud_to_ply)
|
||||
except Exception as exc:
|
||||
self.log_msg.emit(f"点云警告:{exc}")
|
||||
# 点云保存(始终使用 SDK AlignFilter 结果)
|
||||
if aset:
|
||||
if capture_opts.get("pc", False):
|
||||
try:
|
||||
point_cloud_filter.set_create_point_format(OBFormat.POINT)
|
||||
pc = point_cloud_filter.process(aligned)
|
||||
if pc:
|
||||
save_ply_utf8(str(base / "point_cloud.ply"), pc,
|
||||
save_point_cloud_to_ply)
|
||||
except Exception as exc:
|
||||
self.log_msg.emit(f"点云警告:{exc}")
|
||||
|
||||
if capture_opts.get("pc_color", False):
|
||||
try:
|
||||
point_cloud_filter.set_create_point_format(OBFormat.RGB_POINT)
|
||||
pc = point_cloud_filter.process(aligned)
|
||||
if pc:
|
||||
save_ply_utf8(str(base / "point_cloud_color.ply"), pc,
|
||||
save_point_cloud_to_ply)
|
||||
except Exception as exc:
|
||||
self.log_msg.emit(f"彩色点云警告:{exc}")
|
||||
if capture_opts.get("pc_color", False):
|
||||
try:
|
||||
point_cloud_filter.set_create_point_format(OBFormat.RGB_POINT)
|
||||
pc = point_cloud_filter.process(aligned)
|
||||
if pc:
|
||||
save_ply_utf8(str(base / "point_cloud_color.ply"), pc,
|
||||
save_point_cloud_to_ply)
|
||||
except Exception as exc:
|
||||
self.log_msg.emit(f"彩色点云警告:{exc}")
|
||||
|
||||
self.capture_done.emit(save_dir)
|
||||
|
||||
@@ -1062,6 +1101,15 @@ class MainWindow(QMainWindow):
|
||||
for key, cb in self._capture_checks.items():
|
||||
cb.setChecked(getattr(self._app_settings, f"capture_{key}", cb.isChecked()))
|
||||
|
||||
def _on_capture_d2c_method_changed(self):
|
||||
method = self.capture_d2c_method_combo.currentData()
|
||||
if self._worker:
|
||||
self._worker.set_d2c_method(method)
|
||||
is_forward = method == "forward"
|
||||
if not is_forward:
|
||||
self.capture_splat_check.setChecked(False)
|
||||
self.capture_splat_check.setEnabled(is_forward)
|
||||
|
||||
def _on_capture_splat_changed(self, state: int):
|
||||
radius = max(1, self._app_settings.splat_radius) if state == Qt.Checked else 0
|
||||
if self._worker:
|
||||
@@ -1147,7 +1195,7 @@ class MainWindow(QMainWindow):
|
||||
layout.addWidget(grp2)
|
||||
|
||||
# ── 第 3 步:保存目录 & 采集内容 ──
|
||||
grp3 = self._step_group(3, "保存目录 & 采集内容")
|
||||
grp3 = self._step_group(3, "保存目录 && 采集内容")
|
||||
vg3 = QVBoxLayout(grp3)
|
||||
vg3.setContentsMargins(8, 4, 8, 8)
|
||||
vg3.setSpacing(5)
|
||||
@@ -1223,6 +1271,25 @@ class MainWindow(QMainWindow):
|
||||
row_cap.addStretch()
|
||||
vg3.addLayout(row_cap)
|
||||
|
||||
# 行 4:D2C 转换方式
|
||||
row_d2c_method = QHBoxLayout()
|
||||
row_d2c_method.setSpacing(8)
|
||||
lbl_d2c_method = QLabel("D2C 方式:")
|
||||
lbl_d2c_method.setFixedWidth(_sz(58))
|
||||
row_d2c_method.addWidget(lbl_d2c_method)
|
||||
self.capture_d2c_method_combo = QComboBox()
|
||||
self.capture_d2c_method_combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
self.capture_d2c_method_combo.addItem("逆向投影(SDK 同等,推荐)", "sdk")
|
||||
self.capture_d2c_method_combo.addItem("正向投影 + Splat 填充", "forward")
|
||||
self.capture_d2c_method_combo.currentIndexChanged.connect(
|
||||
self._on_capture_d2c_method_changed)
|
||||
row_d2c_method.addWidget(self.capture_d2c_method_combo)
|
||||
# 默认选中 "sdk",Splat 应取消勾选并禁用
|
||||
self.capture_splat_check.setChecked(False)
|
||||
self.capture_splat_check.setEnabled(False)
|
||||
row_d2c_method.addStretch()
|
||||
vg3.addLayout(row_d2c_method)
|
||||
|
||||
layout.addWidget(grp3)
|
||||
|
||||
# ── 预览区 ──
|
||||
@@ -1611,6 +1678,8 @@ class MainWindow(QMainWindow):
|
||||
self.capture_btn.setEnabled(False)
|
||||
self.capture_btn.setText("拍摄中…")
|
||||
capture_opts = {k: cb.isChecked() for k, cb in self._capture_checks.items()}
|
||||
capture_opts["d2c_method"] = self.capture_d2c_method_combo.currentData()
|
||||
capture_opts["splat_radius"] = self._app_settings.splat_radius
|
||||
self._worker.trigger_capture(str(self._session_dir / ts), capture_opts)
|
||||
|
||||
def _on_capture_done(self, save_dir: str):
|
||||
|
||||
Reference in New Issue
Block a user