import dicube
from dicube import get_dicom_status, DicomStatus
from dicube.dicom import CommonTags
# 读取示例数据
dirname = 'dicube-testdata/dicom/sample_200'
img = dicube.load_from_dicom_folder(dirname)
meta = img.dicom_meta
status = get_dicom_status(meta)
print(f"当前数据状态: {status.value}")
# 1. 像素间距检查
spacing_consistent = meta.is_shared(CommonTags.PixelSpacing)
print(f"像素间距统一: {spacing_consistent}")
if spacing_consistent:
spacing = meta.get_shared_value(CommonTags.PixelSpacing)
print(f" 统一间距: {spacing}mm")
# 2. 图像尺寸检查
shape_consistent = (meta.is_shared(CommonTags.Rows) and
meta.is_shared(CommonTags.Columns))
print(f"图像尺寸统一: {shape_consistent}")
if shape_consistent:
rows = meta.get_shared_value(CommonTags.Rows)
cols = meta.get_shared_value(CommonTags.Columns)
print(f" 统一尺寸: {cols}×{rows}")
# 3. 图像方向检查
orientation_consistent = meta.is_shared(CommonTags.ImageOrientationPatient)
print(f"图像方向统一: {orientation_consistent}")DICOM序列状态
什么是 CONSISTENT 状态:规范的三维采样网格
DiCube主要为静态三维医学图像服务,其核心假设是整个3D图像在空间中对应着一个规范的采样网格(regular meshgrid)。当DICOM序列处于CONSISTENT状态时,它满足以下条件:
- 统一的像素间距:所有切片的
PixelSpacing相同 - 一致的图像尺寸:所有切片的
Rows与Columns相同
- 规律的切片间距:Z 轴方向上切片位置等间距
- 统一的图像方向:所有切片的
ImageOrientationPatient相同 - 连续的实例编号:
InstanceNumber从 1 开始连续递增 - 完整的元数据:所有必需的 DICOM 标签存在且有效
只有当序列满足所有这些条件时,DiCube才能为其计算准确的空间信息(Space),构建完整的三维采样网格。
非 Location 相关的状态问题
DiCube使用四种模式来分类非Location相关的字段问题:missing、non_uniform、gap、duplicate。
1. Missing:关键字段缺失
# 演示missing问题的检测
import copy
from dicube.dicom.dicom_tags import get_tag_key
def demo_missing_problems():
print("=== Missing 问题演示 ===")
# 缺失像素间距
test_meta1 = copy.deepcopy(meta)
test_meta1._merged_data.pop(get_tag_key(CommonTags.PixelSpacing), None)
status1 = get_dicom_status(test_meta1)
print(f"删除PixelSpacing后: {status1.value}")
# 缺失图像尺寸
test_meta2 = copy.deepcopy(meta)
test_meta2._merged_data.pop(get_tag_key(CommonTags.Columns), None)
status2 = get_dicom_status(test_meta2)
print(f"删除Columns后: {status2.value}")
# 缺失数据类型信息
test_meta3 = copy.deepcopy(meta)
test_meta3._merged_data.pop(get_tag_key(CommonTags.BitsStored), None)
status3 = get_dicom_status(test_meta3)
print(f"删除BitsStored后: {status3.value}")
demo_missing_problems()2. Non_uniform:字段值不一致
def demo_non_uniform_problems():
print("\n=== Non_uniform 问题演示 ===")
# 像素间距不一致
test_meta1 = copy.deepcopy(meta)
num_slices = test_meta1.slice_count
spacing_values = []
for i in range(num_slices):
if i < num_slices // 2:
spacing_values.append([0.5, 0.5]) # 前半段用0.5mm
else:
spacing_values.append([1.0, 1.0]) # 后半段用1.0mm
test_meta1.set_nonshared_item(CommonTags.PixelSpacing, spacing_values)
status1 = get_dicom_status(test_meta1)
print(f"设置不一致PixelSpacing后: {status1.value}")
# 图像尺寸不一致
test_meta2 = copy.deepcopy(meta)
cols_values = []
for i in range(num_slices):
if i < num_slices // 2:
cols_values.append(512) # 前半段512列
else:
cols_values.append(256) # 后半段256列
test_meta2.set_nonshared_item(CommonTags.Columns, cols_values)
status2 = get_dicom_status(test_meta2)
print(f"设置不一致Columns后: {status2.value}")
demo_non_uniform_problems()3. Duplicate:重复值
def demo_duplicate_problems():
print("\n=== Duplicate 问题演示 ===")
# 实例编号重复
test_meta = copy.deepcopy(meta)
num_slices = test_meta.slice_count
# 所有切片都使用相同的实例编号
duplicate_numbers = [1] * num_slices
test_meta.set_nonshared_item(CommonTags.InstanceNumber, duplicate_numbers)
status = get_dicom_status(test_meta)
print(f"设置重复InstanceNumber后: {status.value}")
# 展示重复检测逻辑
instance_numbers = test_meta.get_values(CommonTags.InstanceNumber)
unique_count = len(set(instance_numbers))
total_count = len(instance_numbers)
print(f" 实例编号: {instance_numbers[:5]}... (总共{total_count}个)")
print(f" 唯一值数量: {unique_count}")
print(f" 检测逻辑: unique_count({unique_count}) < total_count({total_count}) = {unique_count < total_count}")
demo_duplicate_problems()4. Gap:数值跳跃
def demo_gap_problems():
print("\n=== Gap 问题演示 ===")
# 实例编号跳跃
test_meta = copy.deepcopy(meta)
num_slices = test_meta.slice_count
# 创建有跳跃的实例编号序列:1,2,3,5,6,7,8...
gap_numbers = list(range(1, num_slices + 1))
for i in range(3, len(gap_numbers)): # 从第4个开始,所有编号+1
gap_numbers[i] += 1
test_meta.set_nonshared_item(CommonTags.InstanceNumber, gap_numbers)
status = get_dicom_status(test_meta)
print(f"设置跳跃InstanceNumber后: {status.value}")
# 展示跳跃检测逻辑
instance_numbers = test_meta.get_values(CommonTags.InstanceNumber)
sorted_numbers = sorted([int(x) for x in instance_numbers])
print(f" 排序后的实例编号: {sorted_numbers[:8]}...")
# 检查连续性
diffs = [sorted_numbers[i+1] - sorted_numbers[i] for i in range(len(sorted_numbers)-1)]
print(f" 相邻差值: {diffs[:7]}...")
gap_detected = not all(d == 1 for d in diffs)
print(f" 检测逻辑: 存在非1的差值 = {gap_detected}")
demo_gap_problems()Location 相关的状态问题
Location相关的问题主要涉及切片在三维空间中的位置排列,这些问题会破坏规范采样网格的连续性。
1. Missing Location:位置信息缺失
当DICOM序列中既缺少ImagePositionPatient又缺少SliceLocation字段时,DiCube无法确定切片的空间位置。
检测逻辑:需要ImagePositionPatient OR SliceLocation,当两者都缺失时 → MISSING_LOCATION
2. Dwelling Location:位置停滞
这是位置序列中出现重复值的情况,表示多个切片具有相同的空间位置。
数值示例:
- 正常序列:
[1.0, 2.0, 3.0, 4.0, 5.0](间距为1.0) - 停滞序列:
[1.0, 2.0, 2.0, 3.0, 4.0](第2和第3个位置相同) - 位置差值:
[1.0, 0.0, 1.0, 1.0]
检测逻辑:当位置差值中存在零值时 → DWELLING_LOCATION
3. Reversed Location:位置方向混乱
Z轴位置序列中同时存在正向和反向移动,表示扫描方向不一致或序列被打乱。
数值示例:
- 正常序列:
[1.0, 2.0, 3.0, 4.0, 5.0](单调递增) - 混乱序列:
[1.0, 2.0, 3.0, 4.0, 2.0, 5.0, 6.0](第5个位置倒退) - 位置差值:
[1.0, 1.0, 1.0, -2.0, 3.0, 1.0]
检测逻辑:当位置差值中同时存在正值和负值时 → REVERSED_LOCATION
4. Gap Location:位置跳跃
Z轴位置序列中出现不规律的大间隙,破坏了等间距采样的假设。
数值示例:
- 正常序列:
[10.0, 15.0, 20.0, 25.0, 30.0](间距为5.0) - 跳跃序列:
[10.0, 15.0, 20.0, 35.0, 40.0](第4个位置跳跃) - 位置差值:
[5.0, 5.0, 15.0, 5.0] - 平均间距:5.0
- 相对偏差:
[0%, 0%, 200%, 0%]
检测逻辑:当某个间距偏离平均值超过50%时 → GAP_LOCATION
DiCube的兼容性处理策略
DiCube尽力在各种异常情况下保持兼容性,采用”尽力而为”的原则来处理有问题的DICOM数据。当检测到数据质量问题时,DiCube仍然能够加载和处理数据,但会相应地限制某些功能。
处理策略细节
无法计算Space信息的状态:
MISSING_SPACING、NON_UNIFORM_SPACING:像素间距问题MISSING_ORIENTATION、NON_UNIFORM_ORIENTATION:图像方向问题
MISSING_LOCATION、REVERSED_LOCATION、DWELLING_LOCATION、GAP_LOCATION:位置信息问题
处理方式:
- 像素数据:正常加载和处理,应用必要的rescale变换
- 元数据:完整保留所有DICOM标签信息,确保往返转换的完整性
- 空间信息:当检测到空间相关问题时,将Space设置为None并警告用户
- 功能限制:无法进行需要精确空间信息的操作,如空间变换、重采样、配准等
这种设计确保了DiCube在面对现实世界中不完美的DICOM数据时,仍能提供基本的图像处理功能,同时明确告知用户哪些高级功能不可用。
错误优先级:只报告最严重的问题
DiCube的状态检查遵循严格的优先级原则:按照严重程度从高到低依次检查,只报告发现的第一个(最严重的)问题。这种设计避免了信息过载,有助于用户专注于解决最关键的问题。
检查优先级顺序
- Series UID问题(最高优先级)
MISSING_SERIES_UID:缺失序列标识符NON_UNIFORM_SERIES_UID:序列标识符不统一
- Instance Number问题
MISSING_INSTANCE_NUMBER:缺失实例编号DUPLICATE_INSTANCE_NUMBERS:实例编号重复GAP_INSTANCE_NUMBER:实例编号跳跃
- 数据类型问题
MISSING_DTYPE:缺失数据类型信息NON_UNIFORM_DTYPE:数据类型不一致
- 空间参数问题
MISSING_SPACING:缺失像素间距NON_UNIFORM_SPACING:像素间距不一致MISSING_SHAPE:缺失图像尺寸NON_UNIFORM_SHAPE:图像尺寸不一致MISSING_ORIENTATION:缺失图像方向NON_UNIFORM_ORIENTATION:图像方向不一致
- 位置问题
MISSING_LOCATION:缺失位置信息REVERSED_LOCATION:位置方向混乱DWELLING_LOCATION:位置停滞GAP_LOCATION:位置跳跃
- 其他问题
NON_UNIFORM_RESCALE_FACTOR:校正参数不一致
- 理想状态
CONSISTENT:所有检查通过
总结
DicomStatus系统通过系统化的状态检查,确保DiCube能够:
- 识别理想状态:CONSISTENT状态代表规范的三维采样网格
- 分类问题类型:用missing、non_uniform、gap、duplicate四种模式描述非Location问题
- 检测空间异常:专门处理dwelling、reversed、gap等Location相关问题
- 智能兼容处理:在数据有问题时仍能部分工作,但合理限制功能
- 优先级管理:按严重程度报告问题,指导用户逐步修复
这个系统为DiCube的可靠性和鲁棒性提供了重要保障,确保在各种真实世界的数据质量情况下都能给出合理的处理方案。