Rebuild DICOM UPP registration workspace
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
# DICOM_and_UPP 配准工作台
|
# DICOM / UPP 配准工作台
|
||||||
|
|
||||||
用于在浏览器中人工核对 DICOM 序列与 UPP STL 模型的配准关系。页面会读取 PACS DICOM、UPP STL 资产和 DICOM 阅片分类结果,配准位姿单独写入 `dicom_upp_registrations` 表。
|
面向 `DICOM / UPP 数据库关联可视化` 中的完整关联 CT,维护 STL 模型与 DICOM 序列的搭配关系及位姿参数。
|
||||||
|
|
||||||
配准维护表按 `ct_number + algorithm_model` 建唯一约束:同一个 CT、同一个算法模型只保留一条 STL 配准记录;再次保存会更新原记录。
|
此工作台不内置示例项目;进入后直接从数据库完整关联 CT 列表读取 DICOM 和 STL。旧版“锁定”概念已改为 `未配准 / 已配准` 状态。
|
||||||
|
|
||||||
默认端口:
|
默认地址:
|
||||||
|
|
||||||
- 本机:`http://127.0.0.1:8109/`
|
- 本机:`http://127.0.0.1:8109/`
|
||||||
- 局域网:`http://192.168.3.11:8109/`
|
- 局域网:`http://192.168.3.11:8109/`
|
||||||
@@ -14,10 +14,14 @@
|
|||||||
- 账号:`admin`
|
- 账号:`admin`
|
||||||
- 密码:`123456`
|
- 密码:`123456`
|
||||||
|
|
||||||
|
保存表:
|
||||||
|
|
||||||
|
- `public.dicom_upp_registrations`
|
||||||
|
- 唯一键:`ct_number + algorithm_model`
|
||||||
|
- 主要字段:`registration_status`、`series_instance_uid`、`selected_stl_files`、`transform`、`model_reference`、`dicom_reference`
|
||||||
|
|
||||||
启动:
|
启动:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
当前保存内容包括 CT 号、DICOM 序列 UID、重建算法模型、STL family/文件选择、位姿 transform、可选分割/备注、锁定状态和更新人。
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,167 +14,138 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="loginOverlay" class="login-overlay">
|
||||||
|
<form id="loginForm" class="login-panel">
|
||||||
|
<span class="brand-mark"></span>
|
||||||
|
<h1>DICOM / UPP 配准工作台</h1>
|
||||||
|
<p>登录后从完整关联 CT 中选择 DICOM 与 STL 配准关系</p>
|
||||||
|
<input id="username" autocomplete="username" placeholder="账号" />
|
||||||
|
<input id="password" type="password" autocomplete="current-password" placeholder="密码" />
|
||||||
|
<button type="submit">登录</button>
|
||||||
|
<span id="loginError"></span>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
<span class="brand-mark"></span>
|
<span class="brand-mark"></span>
|
||||||
<div>
|
<div>
|
||||||
<h1>DICOM / UPP 配准工作台</h1>
|
<h1>DICOM / UPP 配准工作台</h1>
|
||||||
<p id="brandSubtitle">DICOM 序列、STL family 与人工位姿锁定</p>
|
<p id="subtitle">完整关联 CT · STL 搭配 · 位姿参数</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-actions">
|
<div class="top-actions">
|
||||||
<button id="relationBtn" class="dark-btn accent" type="button">数据库关联</button>
|
<button id="relationBtn" class="ghost-btn accent" type="button">数据库关联可视化</button>
|
||||||
<button id="viewerBtn" class="dark-btn" type="button">阅片系统</button>
|
<button id="viewerBtn" class="ghost-btn" type="button">DICOM 阅片系统</button>
|
||||||
<span id="dbStatus" class="status-pill">数据库</span>
|
<span id="dbStatus" class="status-pill">数据库</span>
|
||||||
<button id="refreshBtn" class="dark-btn" type="button">刷新</button>
|
<button id="refreshBtn" class="ghost-btn" type="button">刷新</button>
|
||||||
<span id="userBadge" class="user-badge">未登录</span>
|
<span id="userBadge" class="user-badge">未登录</span>
|
||||||
<button id="logoutBtn" class="dark-btn" type="button">退出</button>
|
<button id="logoutBtn" class="ghost-btn" type="button">退出</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div id="topLoading" class="top-loading hidden"><span></span></div>
|
<div id="topLoading" class="top-loading hidden"><span></span></div>
|
||||||
|
|
||||||
<main class="workspace">
|
<main class="workspace">
|
||||||
<aside class="left-rail">
|
<aside class="case-panel panel">
|
||||||
<section class="panel search-panel">
|
<div class="panel-head">
|
||||||
<div class="panel-head">
|
<div>
|
||||||
<h2>匹配检查</h2>
|
<h2>完整关联 CT</h2>
|
||||||
<span id="caseCount">0</span>
|
<p>DICOM + STL</p>
|
||||||
</div>
|
</div>
|
||||||
<input id="caseSearch" class="search-input" placeholder="搜索 CT号 / 姓名 / 模型" />
|
<span id="caseCount">0</span>
|
||||||
<div id="caseList" class="case-list"></div>
|
</div>
|
||||||
</section>
|
<input id="caseSearch" class="search-input" placeholder="搜索 CT号 / 姓名 / 模型" />
|
||||||
|
<div class="filter-row">
|
||||||
<section class="panel stacked-panel">
|
<button class="filter active" data-status="">全部</button>
|
||||||
<div class="panel-head">
|
<button class="filter" data-status="unregistered">未配准</button>
|
||||||
<h2>DICOM序列</h2>
|
<button class="filter" data-status="registered">已配准</button>
|
||||||
<span id="seriesCount">0</span>
|
</div>
|
||||||
</div>
|
<div class="part-filter">
|
||||||
<div id="seriesList" class="series-list"></div>
|
<button class="filter active" data-part="">全部部位</button>
|
||||||
</section>
|
<button class="filter" data-part="head_neck">头颈部</button>
|
||||||
|
<button class="filter" data-part="chest">胸部</button>
|
||||||
<section class="panel stacked-panel">
|
<button class="filter" data-part="upper_abdomen">上腹部</button>
|
||||||
<div class="panel-head">
|
<button class="filter" data-part="lower_abdomen">下腹部</button>
|
||||||
<h2>STL模型</h2>
|
<button class="filter" data-part="pelvis">盆腔</button>
|
||||||
<span id="stlCount">0</span>
|
</div>
|
||||||
</div>
|
<div id="caseList" class="case-list"></div>
|
||||||
<div class="segmented small">
|
|
||||||
<button id="modeFile" class="active" type="button">单独</button>
|
|
||||||
<button id="modeFamily" type="button">Family</button>
|
|
||||||
</div>
|
|
||||||
<div id="modelRail" class="chip-rail"></div>
|
|
||||||
<div id="familyRail" class="chip-rail"></div>
|
|
||||||
<div id="stlList" class="stl-list"></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel registration-panel">
|
|
||||||
<div class="panel-head">
|
|
||||||
<h2>交互配准</h2>
|
|
||||||
<span id="saveState">未保存</span>
|
|
||||||
</div>
|
|
||||||
<div class="pose-grid" id="poseGrid"></div>
|
|
||||||
<textarea id="registrationNotes" class="notes" rows="2" placeholder="配准备注"></textarea>
|
|
||||||
<div class="action-grid">
|
|
||||||
<button id="resetPoseBtn" class="dark-btn" type="button">重置位姿</button>
|
|
||||||
<button id="saveRegistrationBtn" class="primary-btn" type="button">保存配准</button>
|
|
||||||
<button id="lockRegistrationBtn" class="warn-btn" type="button">保存并上锁</button>
|
|
||||||
<button id="unlockRegistrationBtn" class="dark-btn" type="button">解锁</button>
|
|
||||||
<button id="exportStlBtn" class="dark-btn" type="button">导出STL</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<section class="viewer-shell">
|
<section class="main-panel">
|
||||||
<section class="panel hero-strip">
|
<section class="case-strip panel">
|
||||||
<div>
|
<div>
|
||||||
<h2 id="activeTitle">未选择 CT</h2>
|
<h2 id="activeTitle">未选择 CT</h2>
|
||||||
<p id="activeMeta">从左侧选择一个 DICOM + STL 匹配检查</p>
|
<p id="activeMeta">从左侧选择一个完整关联检查</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-tags" id="activeTags"></div>
|
<div id="activeTags" class="tag-line"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="viewer-grid">
|
<section class="work-grid">
|
||||||
<article class="viewport-card dicom-card">
|
<aside class="series-panel panel">
|
||||||
<div class="viewport-head">
|
<div class="panel-head compact">
|
||||||
<div>
|
<h2>DICOM 序列</h2>
|
||||||
<h3>DICOM</h3>
|
<span id="seriesCount">0</span>
|
||||||
<span id="dicomMeta">未选择序列</span>
|
</div>
|
||||||
|
<div id="seriesList" class="series-list"></div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<section class="viewer-panel panel">
|
||||||
|
<div class="viewer-head">
|
||||||
|
<div class="segmented">
|
||||||
|
<button data-window="default" class="active">默认</button>
|
||||||
|
<button data-window="bone">骨窗</button>
|
||||||
|
<button data-window="soft">软组织</button>
|
||||||
|
<button data-window="contrast">高对比</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tool-row">
|
<div class="viewer-tools">
|
||||||
<select id="planeSelect">
|
<button id="fitBtn" class="ghost-btn">视角复位</button>
|
||||||
<option value="axial">轴位</option>
|
<button id="saveBtn" class="primary-btn">保存配准</button>
|
||||||
<option value="sagittal">矢状位</option>
|
<button id="statusBtn" class="state-btn">标为已配准</button>
|
||||||
<option value="coronal">冠状位</option>
|
|
||||||
</select>
|
|
||||||
<select id="windowSelect">
|
|
||||||
<option value="default">默认</option>
|
|
||||||
<option value="soft">软组织</option>
|
|
||||||
<option value="bone">骨窗</option>
|
|
||||||
<option value="contrast">高对比</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-stage" id="dicomStage">
|
<div class="fusion-stage">
|
||||||
<img id="dicomImage" alt="DICOM切片" />
|
<div id="fusionViewport"></div>
|
||||||
<div id="dicomEmpty" class="empty-state">等待选择 DICOM 序列</div>
|
<div class="fusion-hud left" id="fusionStatus">等待选择 DICOM 与 STL</div>
|
||||||
|
<div class="fusion-hud right" id="fusionMeta">DICOM - · STL -</div>
|
||||||
|
<div id="fusionLoading" class="fusion-loading hidden">
|
||||||
|
<span>正在构建融合视图</span>
|
||||||
|
<div><i></i></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="slice-row">
|
<div class="slice-row">
|
||||||
|
<span id="sliceLabel">切片 0 / 0</span>
|
||||||
<input id="sliceSlider" type="range" min="0" max="0" value="0" />
|
<input id="sliceSlider" type="range" min="0" max="0" value="0" />
|
||||||
<span id="sliceLabel">0 / 0</span>
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</section>
|
||||||
|
|
||||||
<article class="viewport-card">
|
<aside class="right-panel">
|
||||||
<div class="viewport-head">
|
<section class="panel stl-panel">
|
||||||
<div>
|
<div class="panel-head compact">
|
||||||
<h3>STL拼接后</h3>
|
<h2>STL 模型</h2>
|
||||||
<span id="stlMeta">未加载模型</span>
|
<span id="stlCount">0</span>
|
||||||
</div>
|
</div>
|
||||||
<button id="fitStlBtn" class="icon-btn" title="重置三维视角" type="button">复位</button>
|
<div id="modelRail" class="chip-rail"></div>
|
||||||
</div>
|
<div id="stlList" class="stl-list"></div>
|
||||||
<div id="stlViewport" class="three-stage"></div>
|
</section>
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="viewport-card fusion-card">
|
<section class="panel pose-panel">
|
||||||
<div class="viewport-head">
|
<div class="panel-head compact">
|
||||||
<div>
|
<h2>位姿参数</h2>
|
||||||
<h3>STL和DICOM融合</h3>
|
<span id="saveState">未保存</span>
|
||||||
<span id="fusionMeta">位姿未保存</span>
|
|
||||||
</div>
|
</div>
|
||||||
<button id="fitFusionBtn" class="icon-btn" title="重置融合视角" type="button">复位</button>
|
<div id="poseGrid" class="pose-grid"></div>
|
||||||
</div>
|
<div class="flip-row">
|
||||||
<div id="fusionViewport" class="three-stage"></div>
|
<button data-flip="flipX">镜像 X</button>
|
||||||
</article>
|
<button data-flip="flipY">镜像 Y</button>
|
||||||
|
<button data-flip="flipZ">镜像 Z</button>
|
||||||
<article class="viewport-card segmentation-card">
|
|
||||||
<div class="viewport-head">
|
|
||||||
<div>
|
|
||||||
<h3>DICOM分割</h3>
|
|
||||||
<span id="segmentationMeta">基于当前可见 STL 的预览</span>
|
|
||||||
</div>
|
</div>
|
||||||
<button id="toggleMaskBtn" class="icon-btn" title="显示或隐藏分割预览" type="button">显示</button>
|
<textarea id="notes" class="notes" rows="2" placeholder="配准备注"></textarea>
|
||||||
</div>
|
</section>
|
||||||
<div class="segmentation-stage">
|
</aside>
|
||||||
<img id="segmentationImage" alt="DICOM分割预览" />
|
|
||||||
<canvas id="maskCanvas"></canvas>
|
|
||||||
<div id="segmentationEmpty" class="empty-state">选择序列和 STL 后显示叠加预览</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div id="loginOverlay" class="login-overlay">
|
|
||||||
<form id="loginForm" class="login-panel">
|
|
||||||
<span class="brand-mark"></span>
|
|
||||||
<h2>DICOM / UPP 配准工作台</h2>
|
|
||||||
<p>登录后进行 DICOM 与 STL 配准</p>
|
|
||||||
<input id="username" class="search-input" autocomplete="username" placeholder="账号" />
|
|
||||||
<input id="password" class="search-input" type="password" autocomplete="current-password" placeholder="密码" />
|
|
||||||
<button class="primary-btn" type="submit">登录</button>
|
|
||||||
<span id="loginError" class="error-line"></span>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/static/app.js"></script>
|
<script type="module" src="/static/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user