4. 数据清洗与质量检查
在医学影像AI训练流水线中,数据清洗与质量检查是决定模型上限的关键环节。原始数据往往来自多家医院、多台设备、多个扫描协议,甚至包含人工整理时的误操作。如果直接把这些数据送入训练,模型学到的可能是伪影、重复样本或损坏文件带来的噪声,而不是真正的解剖与病理特征。本节围绕四类核心任务展开:异常值检测、重复数据剔除、图像完整性校验,以及自动化QC报告的生成。
一、异常值检测:从元数据到像素分布
异常值检测需要同时关注“元数据异常”和“图像内容异常”。元数据层面,常见异常包括:层厚为0或负值、像素间距缺失、患者年龄超出合理范围(如0~120岁)、扫描时间与检查类型不匹配等。图像内容层面,则包括灰度分布异常、信噪比过低、存在大面积金属伪影或截断等。
实际操作中,可以先对DICOM标签做规则过滤。例如,对CT数据检查 SliceThickness 是否在0.5~10 mm之间,对MRI检查 RepetitionTime 是否为正数。对于像素级异常,常用Z-score或IQR方法。以某批胸部CT为例,假设统计得到全数据集像素均值为-200 HU、标准差为300 HU,则可将像素均值超过+3σ(即700 HU)的切片标记为疑似异常,因为正常胸部CT中极少出现如此高的整体均值。更稳健的做法是计算每个体积的灰度直方图,提取均值、方差、偏度、峰度四个特征,再用孤立森林(Isolation Forest)做无监督检测。示例参数可设为:n_estimators=100, contamination=0.02,即假设约2%的样本为异常。被标记的样本不应直接删除,而应进入人工复核队列。
二、重复数据剔除:精确匹配与近似匹配
重复数据在医学影像中非常普遍,常见来源包括:同一患者多次导出、不同标注版本重复入库、数据增强后误存回原始目录。重复样本会导致训练集与验证集泄漏,使评估指标虚高。
精确重复可以通过文件哈希(如SHA-256)快速识别。对DICOM文件,还可以结合 PatientID + StudyInstanceUID + SeriesInstanceUID + SOPInstanceUID 四元组判断。近似重复则更复杂,因为同一扫描可能因重新保存而改变文件头,但像素内容几乎一致。此时可对图像降采样到64×64,计算感知哈希(pHash),再设定汉明距离阈值。示例中,若两个体积的pHash汉明距离≤5,则判定为高度相似,进入人工确认。对于分割掩膜,还可以计算Dice系数,若Dice>0.98且图像pHash距离≤5,则几乎可以确定为重复。
三、图像完整性校验:文件、几何与内容三层检查
图像完整性校验应覆盖三个层次。第一层是文件层:检查DICOM文件能否被pydicom正常读取,PixelData是否存在,传输语法是否支持。第二层是几何层:检查层间距是否均匀、方向矩阵是否正交、图像尺寸是否与元数据一致。第三层是内容层:检查是否存在全黑切片、全白切片、严重截断或明显错层。
一个实用的完整性校验流程如下:
- 读取DICOM,捕获异常并记录文件路径与错误类型。
- 检查
Rows、Columns、PixelSpacing、SliceThickness是否齐全且为正数。 - 将像素值转换为HU(CT)或归一化强度(MRI),统计非零像素占比。若非零像素占比低于5%,标记为“疑似空片”。
- 计算相邻切片间的互相关,若某切片与上下层相关性均低于0.3,标记为“错层或伪影”。
- 输出校验结果表,包含文件路径、检查项、状态和备注。
以下是一个可直接参考的校验结果示例表:
| 文件路径 | 检查项 | 状态 | 备注 |
|---|---|---|---|
| /data/ct/patient_001/ser_01/IMG_0032.dcm | PixelData存在 | 通过 | — |
| /data/ct/patient_001/ser_01/IMG_0033.dcm | 非零像素占比 | 失败 | 非零像素占比2.1%,疑似空片 |
| /data/mri/patient_014/ser_02/IMG_0010.dcm | 层间距均匀性 | 警告 | 相邻层间距偏差>15% |
| /data/ct/patient_022/ser_03/IMG_0007.dcm | 方向矩阵正交性 | 失败 | 方向余弦不满足正交,需重新导出 |
四、自动化QC报告生成
当数据量达到数千甚至数万例时,人工逐例检查不现实。自动化QC报告的目标是:把上述检测结果汇总为可读、可筛选、可追溯的文档。报告通常包含总体统计、异常分布、失败样本清单和可视化图表。
实现上,可以用Python脚本串联各检查模块,将结果写入Pandas DataFrame,再导出为HTML或PDF。报告首页给出关键指标:总样本数、通过数、警告数、失败数、重复样本数、异常值比例。第二页按检查项分组,列出失败样本路径和原因。第三页可嵌入直方图,展示像素均值分布、层厚分布和信噪比分布,帮助快速定位系统性问题。
以下是一个QC报告生成的核心代码片段,展示如何组织检查结果:
import pandas as pd
from qc_checks import check_dicom_integrity, detect_outliers, find_duplicates
records = []
for file_path in dicom_files:
integrity = check_dicom_integrity(file_path)
outlier = detect_outliers(file_path)
records.append({
"file_path": file_path,
"integrity_status": integrity["status"],
"integrity_note": integrity["note"],
"outlier_flag": outlier["flag"],
"outlier_score": outlier["score"]
})
df = pd.DataFrame(records)
dup_groups = find_duplicates(dicom_files)
summary = {
"total": len(df),
"pass": (df["integrity_status"] == "pass").sum(),
"fail": (df["integrity_status"] == "fail").sum(),
"outlier_count": df["outlier_flag"].sum(),
"duplicate_groups": len(dup_groups)
}
df.to_csv("qc_detail.csv", index=False)
print(summary)
运行后,qc_detail.csv 可作为逐例追溯的依据,而 summary 字典则用于生成报告首页的统计卡片。若某检查项失败率超过预设阈值(例如空片比例>1%),报告应自动标红并提示“建议检查扫描协议或导出流程”。
五、把清洗与QC嵌入流水线
数据清洗不是一次性任务,而应嵌入每次数据入库的入口。推荐的做法是:在数据注册阶段就执行完整性校验和哈希去重,在数据预处理阶段执行异常值检测,在训练前生成最终QC报告并冻结数据版本。这样,任何一次训练都能追溯到具体的数据快照和QC结论。
把上述四个环节串联起来,数据清洗与QC就不再是训练前的“杂活”,而是可度量、可追溯、可自动化的工程步骤。下一阶段的数据增强与划分,将直接建立在本节产出的干净数据快照之上。