Files
operating-room-monitor-server/backend/algorithm_subprocesses/5.15
Kevin c5716cf0af 恢复 algorithm_subprocesses 权重文件的 git 追踪。
权重目录与 doctor_info.pth 纳入版本库;样本视频、Excel、构建缓存仍保持 ignore。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 16:12:00 +08:00
..
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00
2026-05-21 15:48:03 +08:00

手术室耗材监控系统

基于 手术室主视角录像MP4术中商品 Excel,对术中耗材可能出现的时段进行端到端推断:先做 Phase 1 — 全局时序切分VideoSwin 视频特征 + ActionFormer再对每个时段做 Phase 2 — 细粒度段内推断Ultralytics YOLO手部 ROI、好坏帧、耗材 Top-K、撕膜模型门控可选地在全部段落跑完后执行 撕膜相邻段合并tear_merge),最终将每个 ActionFormer 段对应的主结果写成 TSV

本项目定位为 离线推理包:配置集中在 YAMLPython 源码中不写死业务路径;src/ 负责解析配置与编排,code/ 为算法脚本与第三方子树的导出目录。


目录


能力与适用场景

  • 输入单路术中主视角视频Excel 中含商品名称等与视频画面中文案/条码对应的字段,流程会用它构建「名称 → 商品编码」映射;可选 JSON 白名单限制耗材分类的输出类别集合。
  • 输出:对每个 ActionFormer 时段一行,给出耗材 Top 1/2/3 名称与置信度,以及映射后的 product_id;默认不写出撕膜类名列(见下文)。
  • 典型用途:手术视频质检、耗材使用回溯、与院内物资系统对接前的中间结果导出。

不在本 README 范围内的内容:模型训练脚本、数据采集规范、院内部署与鉴权——这些通常在全量开发仓库中维护。


流水线概览

Phase 1时段提案ActionSegmenter

  1. 在工作目录 work/input/ 下放一份视频的副本文件名与stem一致
  2. 调用 run_feature_extraction:用 torchvision Swin3D-T 预训练 backbone 抽取视频特征,写出 features/*.npymeta.json
  3. 生成单视频推理所需的 JSON/YAMLinfer_single.json / infer_single.yaml)。
  4. 子进程调用 ActionFormereval.py,载入 weights.actionformer 的检查点,得到 eval_results.pkl
  5. 从 pkl 解析时段列表,依次应用:
    • 分数阈值 phase1.af_min_score
    • 互斥贪心合并(与同仓库逻辑一致)
    • 最短时长过滤 phase1.af_min_seg_seconds

Phase 2段内细粒度推断

对每个存活时段 (start_sec, end_sec)

  • 用 OpenCV VideoCapture 在区间内按 phase2.frame_stride 抽样帧。
  • 手部检测weights.hand,置信度 phase2.det_conf,检测框经 phase2.pad_ratio 等与 HandRoiGrouper 合并规则处理。
  • FineGrainedClassifier:在同一 ROI 链路中依次调用好坏帧、耗材分类、撕膜模型;阈值由 classification.* 与重试逻辑控制;耗材输出会按 Excel/JSON 白名单 过滤允许的类别索引。

若某段推断失败(如无法得到有效手部/分类结果),仍会输出一行,top1_name 等字段会填入 可读原因字符串(见「输出文件」)。

可选:撕膜相邻段合并(tear_merge

tear_merge.merge_adjacent_tear: true 时,在全部段初步写表后:

  • 用撕膜模型对相邻段是否在「撕膜」行为上达成一致做门控;可用 tear_merge_weights 指定与推理阶段不同的权重。
  • 合并后的段落可能 复用已缓存的细胞格(同起止时间与 key若不存在缓存则会对合并窗 全量再推理一次(日志会有 [tear_merge] 合并窗段全量重推理)。

简要数据流(概念图)

flowchart LR
  V[MP4 + Excel] --> P1[VideoSwin 特征]
  P1 --> AF[ActionFormer 提案时段]
  AF --> P2[YOLO 手/好坏帧/耗材/撕膜]
  P2 --> TM{撕膜合并?}
  TM -->|是| OUT[TSV]
  TM -->|否| OUT

环境与依赖

组件 说明
操作系统 Linux 为主(开发验证环境);若在 Windows/macOS 上跑,需注意路径与子进程脚本兼容性。
Python 建议 3.10+(与 PyTorch 2.x、第三方库的常见组合一致
CUDA / PyTorch 与你的显卡驱动匹配的 PyTorch / torchvision。务必先PyTorch 官方指引 安装 torchtorchvision,再 pip install -r requirements.txt,避免 pip 拉上不匹配的 cu 版本。
磁盘 工作目录中会暂存特征 .npy、中间 json/yaml、pkl长视频与工作目录设置在固定路径时注意预留空间。

requirements.txt 中的 Python 包(节选含义):

  • torch / torchvision:特征与后端(版本行仅作下限,实际应与你的 CUDA 环境一致)。
  • ultralyticsYOLOv8 系 API加载 .pt 手部与分类权重。
  • opencv-python:读视频、seek/抽帧。
  • pandasopenpyxl:读取 Excel。
  • PyYAML:解析 configs/*.yaml

此外还有 editable 安装的本地包

  • code/actionformer_release/libs/utils:含 NMS 等 C++/CPU 扩展ActionFormer eval.py 依赖;必须在仓库根目录执行 pip install -e ...(见下文)。

安装

git clone <你的仓库 URL>
cd <仓库目录>

# 推荐使用 venv / conda以下为 venv 示例
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

# 1先安装与 CUDA 匹配的 torch / torchvision见官网
# 2再安装本仓库列出的其余依赖
pip install -r requirements.txt

# 3编译安装 ActionFormer 侧 NMS 扩展(在仓库根目录执行)
pip install -e code/actionformer_release/libs/utils

要点:

  • pip install -e 的安装目录必须是 code/actionformer_release/libs/utils(该目录下有 setup.py),且在 已从仓库根 import torch 无报错 的前提下执行。
  • 若升级了 PyTorch有时需要对该扩展 重新安装

准备权重与输入

权重(放入 weights/,或由 YAML 指到任意绝对路径)

本流程需要 5 个 Ultralytics/YOLO 或 ActionFormer 检查点文件:

YAML 配置键 建议文件名 作用
weights.actionformer actionformer_epoch_045.pth.tar Phase 1 ActionFormer 推理
weights.hand hand_detect.pt 手部检测
weights.goodbad goodbad_frame.pt 好坏帧二分类
weights.haocai haocai_classify.pt 耗材多类分类
weights.tear tear_classify.pt 撕膜相关(段内门控 + 可选合并阶段)

VideoSwin 使用 torchvision 自带的 Swin3D-T ImageNet/Kinetics 侧预训练权重,要求用户再提供单独权重文件。

若你仍能从完整开发仓库拷贝文件,可参考以下 相对路径(来自内部交接文档,仅供找回文件时对照;完整仓库不一定随本 pack 分发):

配置键 建议文件名 开发仓库中参考路径(若存在)
weights.actionformer actionformer_epoch_045.pth.tar code/video_clip_cls/runs/actionformer_ckpt/haocai_main_perspective_videoswin_haocai_main_perspective_videoswin/epoch_045.pth.tar
weights.hand hand_detect.pt code/hand_detection/runs/hand_det_y11s_multiframe-better/weights/best.pt
weights.goodbad goodbad_frame.pt code/goodORbad_frame/runs/goodbad_frame_y11m_e50/weights/best.pt
weights.haocai haocai_classify.pt code/haocai_classify/runs/haocai_cls_41cls_goodframe_721_e50_p8-0.96/weights/best.pt
weights.tear tear_classify.pt code/tear_classify/runs/tear_cls_bicls_y11m_e50_ds0511/weights/best.pt

Excel 与白名单

  • io.excel:用于 e2e.load_product_code_map 等逻辑构建 耗材名称 ↔ 编码;表格结构需与你的训练/线上约定一致。
  • io.whitelist_json: null:启用 从 Excel 第一张工作表的 C 列读取一串「允许出现的商品名称」,再映射到分类 head 的允许类别索引(与线上一致)。
  • io.whitelist_json 若为路径JSON 形如 {"allowed_names":["名称A","名称B",...]}

视频路径建议

配置里 io.video / io.excel / io.out 既可写 相对路径(相对 仓库根,即包含 main.py 的那一层),也可写绝对路径。

上传至 GitHub 的仓库中建议 不要将个人机上的绝对路径 提交进 configs/default_config.yaml;可使用 input/xxx.mp4 占位,每台机器本地化修改或使用独立 configs/local.yaml(并加入 .gitignore)。


运行方式

# 默认读取 configs/default_config.yaml
python main.py

# 指定配置文件
python main.py --config configs/my_run.yaml

命令行接口main.py

参数 含义
--config YAML 配置文件路径;默认 configs/default_config.yaml

运行前,config.py 会将 YAML 中相对路径一律 -resolve 为基于仓库根的绝对路径runtime.pythonnull 时使用 sys.executable 调用子进程(特征提取与 ActionFormer eval从而在 venv 内保持一致解释器。

环境变量(入口已设默认):

  • OPENCV_FFMPEG_LOGLEVEL:降低 OpenCV FFmpeg 后端日志冗长度;可按需在外层 shell 覆盖。

配置文件逐项说明

主模板见 configs/default_config.yaml。以下与 src/config.py 的映射一致。

io

类型 说明
video 路径 输入 MP4
excel 路径 输入 Excel
out 路径 输出 TSV父目录会自动创建
whitelist_json null 或路径 null 表示从 Excel 第一表 C 列读白名单;否则为 JSON 文件路径

weights

五个模型文件路径,缺失时进程会在校验阶段报错并打印「缺少 xxx」。

runtime

说明
work_dir null:使用系统临时目录(进程结束默认删除);非 null:固定中间结果目录
keep_work_dir true 且无 work_dir 时,使用 tempfile.mkdtemp保留 目录(日志会打印路径)
python null/"":子进程使用当前解释器;否则填绝对路径可用于多环境隔离

device

说明
type cudacpuCPU 仅能验证逻辑,速度慢)
half true 时向 Ultralytics predict 传入半精度以降低显存(依 GPU 支持情况而定)

phase1ActionFormer + 特征)

说明
af_min_score 保留提案段的分数下限
af_min_seg_seconds 段长(秒)下限;<=0 可关闭最短段过滤
feat_batch_size VideoSwin 特征批大小;显存紧张时可设为 1

phase2(解码与检测)

说明
seek_margin_sec 打开段落时在起止两侧的 seek 留白,减轻关键帧不齐带来的边界效应
frame_stride 抽帧步长,>=1
det_conf 手部检测置信度阈值
pad_ratio 手部框缩放/填充比例(与 _pad_box 等一致)
imgsz_det YOLO 检测输入分辨率
merge_iou_gt ROI 合并IoU 相关阈值
merge_center_dist_max_px 合并:中心距离像素上限,null 表示不用该项
merge_center_dist_max_frac_diag 合并:中心距离相对对角线比例上限,null 表示不用

classification

说明
imgsz_cls 分类支路输入尺寸
good_top1_conf_threshold 「好帧」Top1 置信度门槛
good_top1_retry_threshold 重试时使用的好帧阈值(与段内 retry 逻辑配合)
haocai_min_conf 耗材 Top1 主阈值
haocai_min_conf_retry 第二次尝试的耗材阈值;<=0 关闭二段重试;若 haocai_min_conf 则配置会被视为等价于关闭重试
empty_cache_every 每隔若干步 torch.cuda.empty_cache()0 表示不调用

tear_merge

说明
merge_adjacent_tear 是否在写表前做相邻撕膜导向的合并
tear_merge_weights null 则用 weights.tear;否则指定合并专用权重路径
tear_merge_class 撕膜类别名(与 tear 模型 names 对齐),默认 "tearing"
tear_merge_head_sec 合并判定时观察的段首秒数
tear_merge_prob 撕膜概率阈值
tear_merge_min_frames 最少帧数要求
tear_merge_verbose 是否打印冗余日志
tear_merge_full_frame true 时合并路径用全帧而非手部分支(按需实验)

output

说明
legacy_12_col_only true(默认):12 列 TSV不含 tear_top1_nametear_top2_namefalse14 列,保留撕膜 Top2 名称列

doctor_identity

说明
enabled 是否启用医生身份识别后处理;true 时会在结果文件末尾追加 医生信息:...
checkpoint 医生识别模型权重路径,默认 doctor_identity_package/doctor_info.pth
labels_csv person_id -> 医生姓名 映射表,默认 doctor_identity_package/labels.csv
middle_seconds 取视频中间窗口长度(秒),默认 10.0
sample_fps 中间窗口采样帧率,默认 3.0
pad_frac 人体框外扩比例,默认 0.15

输出文件与列含义

  • 分隔符:制表符 Tab
  • 编码UTF-8。
  • 表头:与 legacy_12_col_only 一致。

12 列(默认)rankstart_secend_secproduct_id_top1top1_nametop1_confproduct_id_top2top2_nametop2_confproduct_id_top3top3_nametop3_conf

14 列:在末尾增加 tear_top1_nametear_top2_name

说明:

  • product_id_* 由 Excel商品表映射若耗材名存在但表中无映射仍会输出名称编码为空_stderr 可能出现 「商品表无名称…」 警告。
  • 推断失败行仍会占用一行:top1_name(及对应 conf 为空)常为 可读失败原因,便于离线筛查。
  • 文件末尾会额外追加一行医生识别结果,格式固定为:医生信息XXX。例如:医生信息:付玉峰 (id=24503, conf=0.9969)

目录结构

.
├── main.py                     # CLI读 YAML调用编排
├── requirements.txt
├── README.md                   # 本文件
├── README_handoff.md           # 简短交接备忘(可与本 README 互为补充)
├── configs/
│   └── default_config.yaml     # 默认配置模板
├── src/
│   ├── __init__.py
│   ├── paths.py               # 将 code/video_clip_cls/scripts 等加入 sys.path
│   ├── config.py               # YAML -> argparse.NamespaceSimpleNamespace
│   ├── pack_utils.py          # Excel 白名单加载等共用工具
│   ├── orchestrator.py         # PipelineManager主流程
│   └── actionformer_utils.py    # Phase1 ActionSegmenter
├── weights/                    # 用户提供 .pth.tar / .pt勿提交大文件时用 .gitignore
├── input/
├── output/
├── data/
└── code/                       # 算法导出树(一般不改)
    ├── repo_root.py
    ├── dataset.py
    ├── video_clip_cls/          # VideoSwin 提特征、e2e、pipeline 脚本…
    │   └── ...
    └── actionformer_release/   # ActionFormer 上游 + 本项目 yaml / train / eval
        ├── README.md
        ├── INSTALL.md
        └── LICENSE

src/paths.py 会校验 code/repo_root.py 存在,并依次 prependvideo_clip_cls/infer_single_0506video_clip_cls/scriptscode 根,以便 import run_haocai_actionformer_consumables_e2eimport pipeline.segment_processor 等板块与原版脚本一致。


与上游开发仓库的关系

  • code/ 目录常为从更大研发仓库 剪出的子树编排入口已从散落的 argparse 收口为:YAML → src/config.pysrc/orchestrator.py
  • 若在段内推断或合并逻辑上与历史行为不一致,可对照 code/video_clip_cls/scripts/main_pipeline.py(同一 PipelineManager 思想)。
  • 更偏「给谁解压就能跑」的清单式说明可见 README_handoff.md

ActionFormer 子项目

code/actionformer_release/ 基于 ActionFormer 公开代码演进而来:

本 README 不重述上游论文公式与训练指令;仅强调 推理路径依赖 nms_1d_cpu 的可编辑安装。


常见问题与排错

现象 可能原因与处理
Import / nms 相关错误eval 阶段) 未安装扩展:在仓库根执行 pip install -e code/actionformer_release/libs/utils;确认先能 python -c "import torch"
找不到视频 / 找不到 Excel 检查 YAML 路径;相对路径是相对 仓库根,不是当前 shell 工作目录层级错误。
缺少手部检测 weights/ 下文件名与 YAML 不一致,或拷贝不完整。
CUDA OOM 减小 feat_batch_size;设 device.half: true;或缩短试运行视频长度。
CPU 太慢 Phase1 特征 + AF 在长视频上单核/单进程极慢属预期;仅建议短 clip 冒烟。
OpenCV 无法打开 MP4 检查文件是否损坏、编码是否罕见;必要时用 ffmpeg 重封装为 H.264 MP4。
商品编码总为空 检查 Excel 表结构是否与 load_product_code_map 假设一致;名称字符串是否与模型输出完全一致(空格、别名)。

许可证

  • ActionFormer 相关代码:以 code/actionformer_release/LICENSE 为准。
  • 本仓库其余部分:若在 GitHub 公开,建议在仓库根 自行添加 LICENSE(公司内部可保留专有许可),并与 PyTorch / Ultralytics / OpenCV 等依赖的开源许可证要求自行核对后再分发模型权重。

若需英文版 README、Dockerfile 或示例 configs/ci_smoke.yaml,可以单独提出要求再补。