feat(review): 核对包改成医生读得懂;资料库超声一路只留给 agent 的参数
- ceus:灌注指标改为对病灶去暗区(roi_perf)和紫圈(roi_pan)两组算,roi_all 指标删除; D1–D4 仍要 roi_all、roi_perf 两条都过才定位(负责人 2026-10-17:医生要正常区与病灶对比看) - build/library:tic.json 只出两组 11 个指标与 7 个槽位的视频时间;医生截图挪进 ultrasound/keyframes/key.png,UltrasoundRoute 去掉 key_image、keyframes 多一个 key - review:TIC参数.csv 取代 TIC结果.csv;问题清单按原因对照表写成大白话,对照表外的原因报错; 程序原文进 snapshot/问题清单_原文.csv;说明.pdf 整份重写为合作者口吻 - 文档:结构.md、医生核对包、装配两个库、CEUS定量 任务书 04。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -160,15 +160,28 @@ library/<构建号>/
|
||||
manifest.json 构建清单:每个文件的 SHA-256、构建时的 git 提交、配置哈希、所用 CEUS 运行号(没装为 null)
|
||||
cases/<化名>/
|
||||
clinical/clinical.json 临床那一路
|
||||
ultrasound/ 超声那一路:report.txt、key.png;装了 CEUS 结果时另有
|
||||
keyframes/<槽位>.png 和 tic.json
|
||||
ultrasound/ 超声那一路:report.txt、keyframes/key.png;装了 CEUS 结果时
|
||||
keyframes/ 里另有定位到的 <槽位>.png,另有 tic.json
|
||||
mr/report.txt MR 那一路
|
||||
```
|
||||
|
||||
`build.yaml` 的 `ceus_run` 指向某次 CEUS 定量的运行目录时,build 才往超声一路装 CEUS 结果,为 null 时不装。装的时候:
|
||||
超声一路的图都放在 `keyframes/` 一个文件夹里。医生截的关键图 `key.png` 来自交付包、不来自 CEUS,所以每例都有,没装 CEUS 时 `keyframes/` 里只有它一张;去掉文本块、EXIF 等附加数据,只按像素重新编码,不能逐像素保真重编码的整例跳过(C14)。
|
||||
|
||||
- `keyframes/<槽位>.png`:下文关键帧表里定位到的那几张(槽位即 B0、D1 等),和 `key.png` 一样去掉附加数据重新编码;每例最多 8 张图(7 张关键帧加 `key.png`)。
|
||||
- `tic.json`:从这一例的 `summary.json` 里逐字段挑出,此外什么都不写:四条曲线(`roi_all` 病灶整体、`roi_perf` 病灶去暗区、`roi_pan` 紫圈即医生圈的一块正常胰腺、`background_circle` 背景圆)各自的拟合是否成功(`success`)和拟合优度 R²(`r2`);病灶两条曲线的灌注指标(`perfusion_metrics`,拟合没过质量门为 null);紫圈曲线是否可用(`pan_curve_usable`);7 个槽位各自是否定位到(`located`)、定位到的视频时间(`video_time_s`,秒)、没定位的原因(`reason`)。视频号、文件路径、配置、帧号、拟合参数都不写。挑哪些字段只在 `src/cadx/build/_ceus.py` 里列。
|
||||
`build.yaml` 的 `ceus_run` 指向某次 CEUS 定量的运行目录时,build 才往超声一路装 CEUS 结果,为 null 时不装(没有 `tic.json`)。装的时候:
|
||||
|
||||
- `keyframes/<槽位>.png`:下文关键帧表里定位到的那几张(槽位即 B0、D1 等),和 `key.png` 一样去掉附加数据重新编码、过 C14;每例最多 8 张图(7 张关键帧加 `key.png`)。
|
||||
- `tic.json`:只放「给专家的参数」,此外什么都不写:
|
||||
|
||||
```
|
||||
{
|
||||
"perfusion_metrics": {"roi_pan": {11 个指标} 或 null, "roi_perf": {11 个指标} 或 null},
|
||||
"keyframe_times_s": {"B0": 秒或 null, …, "F2": 秒或 null}
|
||||
}
|
||||
```
|
||||
|
||||
`perfusion_metrics` 是两组灌注指标:`roi_pan` 是紫圈(医生在正常胰腺实质上圈的一块),`roi_perf` 是病灶去掉暗区(不进造影剂的囊液部分)后的区域,两组放在一起,是为了让专家把病灶和正常胰腺对着看(负责人 2026-10-17)。每组是下文第 9 步的 11 个指标,键名沿用 `summary.json` 的 `values`(`PE_au`、`TTP_s` …);这一组的拟合没过质量门整组为 null,观测不够算不出的单项为 null,不外推。`keyframe_times_s` 是 7 个槽位定位到的视频时间(秒),没定位到为 null。
|
||||
|
||||
不放:拟合成败和 R²、病灶整体(`roi_all`)和背景圆的曲线、紫圈是否可用、关键帧没定位的原因、指标的信号域等口径标签和辅助时刻(TI、TO、mTT,只是算其他指标的中间量),以及视频号、文件路径、配置、帧号、拟合参数。资料库的定义是「专家能看到什么」,可见范围只在 build 一处决定:多放进去、等会诊那边再挑,就成了两处决定,改了一处忘了另一处就会悄悄漏给专家(任务书 04,负责人 2026-10-17 认可)。挑哪些字段只在 `src/cadx/build/_ceus.py` 里列。
|
||||
- 核对这次 CEUS 运行是在这份交付包上跑的:运行快照里 `ceus.yaml` 的 `paths.delivery_dir` 与 `build.yaml` 的 `delivery_dir` 规范化后不是同一路径;或逐例比,交付包里这段视频文件的 SHA-256 与 `summary.json` 的 `video_sha256` 不同,或交付包的推注时间与 `summary.json` 的 `injection_offset_s` 不同,整次停下报错。这两个字段不进 `tic.json`。
|
||||
- CEUS 在这一例上失败(在 `failed.csv` 里)或运行目录里没有这一例的结果,这一例整例跳过,记 C15。失败的病例要不要改成「超声不可评价、仍参与会诊」等 `../待定问题/03-病例排除标准.md` 定。
|
||||
|
||||
@@ -179,7 +192,7 @@ library/<构建号>/
|
||||
| 性别、年龄 | 看得见 | 看不见 | 看不见 |
|
||||
| 5 个症状、5 项既往史、5 项化验(原值与是否异常) | 看得见 | 看不见 | 看不见 |
|
||||
| 超声报告「所见」段、医生截的关键图 | 看不见 | 看得见 | 看不见 |
|
||||
| CEUS 关键帧、TIC 灌注指标 | 看不见 | 看得见(给哪些指标、几张图由会诊任务书定) | 看不见 |
|
||||
| CEUS 关键帧图与视频时间、紫圈和病灶去暗区两组灌注指标(上文 `tic.json`) | 看不见 | 看得见 | 看不见 |
|
||||
| MR 报告「所见」段 | 看不见 | 看不见 | 看得见 |
|
||||
| 病理诊断、报告「印象 / 结论」段、医生标注工作簿、真实病例号、Excel 行序、姓名 | 看不见 | 看不见 | 看不见 |
|
||||
|
||||
@@ -198,7 +211,23 @@ library/<构建号>/
|
||||
|
||||
### 医生核对包(`runs/review_pack/<运行号>/`)
|
||||
|
||||
把一次构建的两个库和它装入的那次 CEUS 运行,整理成医生不用写代码就能看的一个文件夹(表格 CSV、文字 PDF、图和视频逐字节拷贝),由负责人打包交给临床方核对我们的处理结果。病例目录用医生的病例号,问题清单只写程序观察到的现象;包里有真实病例号、报告原文和诊断,只在临床方与我们之间传递。它不是流水线的一段:不产出任何后续段要读的东西,医生每交一版数据、跑完 CEUS 定量和装配之后出一次。包内布局和每个文件的格式见 `../任务书/03-医生核对包.md` 和包里的 `说明.pdf`,怎么跑见 `../guides/医生核对包.md`。
|
||||
把一次构建的两个库和它装入的那次 CEUS 运行,整理成医生不用写代码就能看的一个文件夹(表格 CSV、文字 PDF、图和视频逐字节拷贝),由负责人打包交给临床方核对我们的处理结果。包里有真实病例号、报告原文和诊断,只在临床方与我们之间传递。它不是流水线的一段:不产出任何后续段要读的东西,医生每交一版数据、跑完 CEUS 定量和装配之后出一次。
|
||||
|
||||
```
|
||||
runs/review_pack/<运行号>/
|
||||
snapshot/ 快照,含程序原文的 问题清单_原文.csv(不给医生)
|
||||
医生核对包_<构建号>/
|
||||
说明.pdf 问题清单.csv 病例总表.csv
|
||||
标准答案/ 答案库 4 张表原样拷贝
|
||||
病例/<病例号>/ 临床信息.csv 超声报告.pdf MR报告.pdf
|
||||
关键帧/医生截图.png、<槽位>_第<秒>秒.png
|
||||
TIC曲线.png TIC参数.csv 回放视频.mp4
|
||||
```
|
||||
|
||||
- 医生看到的超声参数就是 AI 专家看到的那份:`关键帧/医生截图.png` 拷自资料库 `ultrasound/keyframes/key.png`,`TIC参数.csv` 的数值取自资料库 `tic.json`(紫圈、病灶去暗区两组 × 11 个指标)。只有某组整组为空时的「没算出的原因」取自 CEUS 运行的 `summary.json`,这一行只给医生看。
|
||||
- 问题清单是给医生的大白话:程序记录的原因经 review 里的一张对照表(检查编号、CEUS 各步的失败原因、拟合原因码、关键帧未取到的原因、紫圈不可用)换成一句医生能懂的话,同一个原因引起的几条合成一行;对照表里没有的原因直接报错停下。程序原文留在快照里给我们自己追溯。来源:任务书 04,负责人 2026-10-17「合作方是医生,感觉他们也不一定看得懂」。
|
||||
|
||||
每个文件的格式见 `../任务书/03-医生核对包.md`(04 改过的以 `../任务书/04-核对包改成医生读得懂.md` 为准)和包里的 `说明.pdf`,怎么跑见 `../guides/医生核对包.md`。
|
||||
|
||||
### CEUS 定量的产物(`runs/ceus/` 与 `work/`)
|
||||
|
||||
@@ -216,7 +245,7 @@ CEUS 定量按下面的阶段进行(旧项目的阶段划分,迁移时逐模
|
||||
| 6 TIC 采样 | 逐帧取病灶(去不去暗区两种)平均亮度,得到 TIC(时间-强度曲线) | 否 |
|
||||
| 7 拟合 | 用 Lognormal(对数正态)曲线拟合 TIC,过质量门 | 否 |
|
||||
| 8 关键帧 | 按下面的定义挑 7 张 | 否 |
|
||||
| 9 灌注指标 | 从拟合曲线算 11 个指标(峰值强度、达峰时间、洗入速率等,口径仿照商用造影定量软件 VueBOX) | 否 |
|
||||
| 9 灌注指标 | 对病灶去暗区(`roi_perf`)和紫圈(`roi_pan`)两条曲线各算一组 11 个指标(峰值强度、达峰时间、洗入速率等,口径仿照商用造影定量软件 VueBOX),只从过了质量门的拟合曲线算,没过的那组为空。两组是为了让病灶和正常胰腺对着看;病灶整体(`roi_all`)含暗区,不算(负责人 2026-10-17,医生要正常区与病灶对比看) | 否 |
|
||||
|
||||
只有阶段 3 跨运行复用,其余每次重算:阶段 3 要显卡,最贵;其余阶段在 CPU 上算。改了后段参数不必重跑显卡。
|
||||
|
||||
@@ -309,19 +338,19 @@ Python 环境用 uv;安装与检查命令见 `../guides/开发环境.md`。
|
||||
|
||||
| 模块 | 预期行数 | 实际行数 | 旧项目对应部分的行数 |
|
||||
| --- | --- | --- | --- |
|
||||
| ceus | 6000–7500(基本照搬旧算法,去掉只为产品层服务的部分) | 7103 | `ceus_roi/` 除 `service.py` 7330,`video_decoder.py` 135 |
|
||||
| ceus | 6000–7500(基本照搬旧算法,去掉只为产品层服务的部分) | 7106 | `ceus_roi/` 除 `service.py` 7330,`video_decoder.py` 135 |
|
||||
| segment | 150–300 | 300 | `medsam2_local_track.py` 240 |
|
||||
| delivery | 400–700 | 739 | `clinical.py` 266、`modalities.py` 522、`workbook.py` 99、`delivery.py` 134,共 1021,其中入库与数据库部分不迁 |
|
||||
| library | 150–300 | 377 | `input_packages.py` 104 |
|
||||
| answers | 100–200 | 227 | — |
|
||||
| verdicts | 100–200 | — | — |
|
||||
| build | 300–500 | 537(含装入 CEUS 结果的 `_ceus.py`;读 CEUS 运行目录已挪进 runs) | `input_readers.py` 329 的装配部分 |
|
||||
| build | 300–500 | 520(含装入 CEUS 结果的 `_ceus.py`;读 CEUS 运行目录已挪进 runs) | `input_readers.py` 329 的装配部分 |
|
||||
| llm | 200–450 | — | ClinDB `llm/` 415 |
|
||||
| ledger | 200–300 | — | ClinDB `ledger/` 274 |
|
||||
| runs | 100–250 | 201(快照 `_snapshot.py` 98、读 CEUS 运行的 `_ceus_run.py` 82、`__init__.py` 21) | — |
|
||||
| consult | 500–1000(会诊口径定后重估) | — | — |
|
||||
| evaluate | 300–600(评价口径定后重估) | — | 已删的 `core/eval` 622 |
|
||||
| review | 300–500 | 610(`_pack.py` 407、`_pdf.py` 129、`_config.py` 64、`__init__.py` 10;不含说明模板 `readme_template.md` 202 行) | — |
|
||||
| review | 300–500 | 1152(`_pack.py` 447、`_problems.py` 502、`_pdf.py` 129、`_config.py` 64、`__init__.py` 10;不含说明模板 `readme_template.md` 91 行)。超出一倍:任务书 04 要求的原因对照表(`_problems.py`)大半是逐条的原因与医生写法,待负责人确认是否接受 | — |
|
||||
| scripts/ 每个 | ≤ 300 | `build.py` 37、`scan_library.py` 88、`ceus_quant.py` 403(超出,含目视核对表的读取与核对、开跑即写快照)、`ceus_align_review.py` 243、`review_pack.py` 37 | `t1_local_debug.py` 762、`tic_lognormal_replay.py` 627 |
|
||||
|
||||
---
|
||||
@@ -365,7 +394,7 @@ Python 环境用 uv;安装与检查命令见 `../guides/开发环境.md`。
|
||||
- `read_build_info(build_dir)`:读构建清单的概况,交出 `BuildInfo`:构建号、编码列是否解码、装入的 CEUS 运行号(没装为 None)。
|
||||
- `read_clinical(build_dir, alias)`、`read_ultrasound(build_dir, alias)`、`read_mr(build_dir, alias)`:按路读出一例,读时核对 SHA-256,拒绝 `.partial` 目录。
|
||||
- `ClinicalRoute`:临床一路:是否已解码、22 列字段。
|
||||
- `UltrasoundRoute`:超声一路:报告「所见」原文、关键图路径、tic.json 的内容(没装 CEUS 时为 None)、槽位 → 关键帧路径(没装时为空)。
|
||||
- `UltrasoundRoute`:超声一路:报告「所见」原文、tic.json 的内容(没装 CEUS 时为 None)、`keyframes`(`keyframes/` 下的图,文件名主干 → 路径:总有医生截的关键图 `key`,即 `KEY_SLOT`;装了 CEUS 时另有定位到的槽位)。
|
||||
- `MrRoute`:MR 一路:报告「所见」原文。
|
||||
- `scan_for_leaks(build_dir, forbidden_strings, forbidden_keys)`:在构建目录的全部 `.txt`、`.json` 里找禁止的字符串(NFKC 归一、不分大小写、按子串)和禁止的 JSON 键名,返回命中列表。
|
||||
- `LeakHit`:一处命中:文件(相对构建目录)、类别(「字符串」或「键名」)、命中的词。
|
||||
@@ -399,7 +428,7 @@ Python 环境用 uv;安装与检查命令见 `../guides/开发环境.md`。
|
||||
- `register_halves(frames, left_view, right_view, cfg.registration, cfg.prompt_source, cfg.pan_source)`:第 1 步的两半配准,交出 `HalfRegistration`:左半局部坐标 → 右半局部坐标的平移,`correlation`(两半扇形区边缘图的归一化互相关,采用它)、`template`(左半扇形内多块模板逐帧匹配后取中位数,只用来核对)、各次匹配明细、两者各分量之差的最大值;`contrast_to_target(side)` 换成造影那一半 → 另一半的平移。
|
||||
- `SegmentationInput`:视频的 fps、帧数、宽高、逐帧时间戳,分屏线,`registration`(`HalfRegistration`),`offset`(造影那一半局部坐标 + `offset` = `target_view` 局部坐标),`contrast`(`ContrastSide`:哪一半是造影画面、造影视图和分割那一半视图 `target_view`、提示帧),`target_frames()`(重新解码,逐帧交出分割那一半的 BGR 图像;不存整段),`prompt_masks`(提示帧帧号 → 绿框按 `offset` 挪到 `target_view` 局部坐标的掩膜),造影那一半的第一帧。
|
||||
- `quantify_case(prepared, target_masks, injection_offset_s, cfg)`:第 4–9 步。`target_masks` 是分割在 `target_view` 局部坐标上的 `(帧数, 高, 宽)` 布尔数组,`injection_offset_s` 是推注时间 X;分割一帧有效轮廓都没有抛 `NoValidContourError`(第 4 步)。拟合没过质量门不抛错。
|
||||
- `QuantResult`:`trajectory`(`Trajectory`)、`tic`(`TicResult`)、`curves`(`TicCurves`)、推注时间、病灶两条曲线拟合是否都过质量门、`anchors`(7 个槽位的 `AnchorFrameLocation`)、`perfusion`(`roi_all`、`roi_perf` 各自的 `LognormalPerfusionMetrics`,拟合没过为 None)、紫圈检出率。
|
||||
- `QuantResult`:`trajectory`(`Trajectory`)、`tic`(`TicResult`)、`curves`(`TicCurves`)、推注时间、病灶两条曲线拟合是否都过质量门、`anchors`(7 个槽位的 `AnchorFrameLocation`)、`perfusion`(`METRIC_CURVES` 即 `roi_perf`、`roi_pan` 各自的 `LognormalPerfusionMetrics`,拟合没过为 None)、紫圈检出率。
|
||||
- `AnchorFrameLocation`:一个关键帧槽位的帧号、视频时间、推注后时刻、状态(`ok` 或未定位的类别)、未定位的原因、锚点时刻。
|
||||
- 写产物用:`pack_trajectory(trajectory)`(trajectory.npz 字节)、`pack_tic_curves(curves)`(tic_curves.npz 字节)、`render_tic_png(tic, markers=tic_plot_markers(anchors))`(tic.png,标出 D1–D4)、`render_case_overlay(prepared, result)`(overlay.mp4 字节)、`keyframe_images(prepared, anchors)`(定位到的关键帧整幅原图,槽位 → 图像)、`quant_summary(result)`(拟合、灌注指标、紫圈检出率、7 个关键帧定位,可直接写成 JSON);读回用 `unpack_trajectory`、`unpack_tic_curves`。
|
||||
- `fan_mask(std, cfg.registration)`:由一半画面的逐像素时间标准差求扇形区掩膜;`color_marks(frames, prompt_cfg, pan_cfg, dilate)`:任一帧里落在绿框或紫圈颜色范围内的像素。两者配准用,目视核对出图也用。
|
||||
|
||||
Reference in New Issue
Block a user