Rust DICOM标准字典库dicom-dictionary-std的使用,医疗影像数据元标签解析与标准化处理

Rust DICOM标准字典库dicom-dictionary-std的使用,医疗影像数据元标签解析与标准化处理

简介

dicom-dictionary-std是DICOM-rs项目的一部分,提供了标准的DICOM数据字典。该库使用dictionary_builder生成的条目来构建DICOM数据字典。

安装

在项目目录中运行以下Cargo命令:

cargo add dicom-dictionary-std

或者在Cargo.toml中添加以下行:

dicom-dictionary-std = "0.8.1"

使用示例

以下是一个完整的示例,展示如何使用dicom-dictionary-std库来解析和标准化处理DICOM医疗影像数据元标签:

use dicom_dictionary_std::tags;
use dicom_dictionary_std::uids;
use dicom_object::mem::InMemDicomObject;
use dicom_object::open_file;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 打开DICOM文件
    let obj = open_file("example.dcm")?;
    
    // 转换为内存中的DICOM对象
    let obj: InMemDicomObject = obj.into();
    
    // 获取常用标签
    let patient_name_tag = tags::PATIENT_NAME;
    let study_date_tag = tags::STUDY_DATE;
    let modality_tag = tags::MODALITY;
    
    // 从DICOM对象中获取元素值
    if let Some(patient_name) obj.element(patient_name_tag)?.to_str()? {
        println!("Patient Name: {}", patient_name);
    }
    
    if let Some(study_date) = obj.element(study_date_tag)?.to_str()? {
        println!("Study Date: {}", study_date);
    }
    
    if let Some(modality) = obj.element(modality_tag)?.to_str()? {
        println!("Modality: {}", modality);
    }
    
    // 检查SOP Class UID
    if let Some(sop_class_uid) = obj.element(tags::SOP_CLASS_UID)?.to_str()? {
        match sop_class_uid {
            uids::CT_IMAGE_STORAGE => println!("This is a CT image"),
            uids::MR_IMAGE_STORAGE => println!("This is an MR image"),
            uids::ENHANCED_CT_IMAGE_STORAGE => println!("This is an enhanced CT image"),
            _ => println!("Unknown SOP Class: {}", sop_class_uid),
        }
    }
    
    Ok(())
}

主要功能

  1. 标准DICOM标签访问:通过tags模块提供所有标准DICOM属性的快捷访问方式
  2. UID常量:通过uids模块提供标准DICOM UID的常量定义
  3. 数据字典查询:可以查询DICOM数据元素的名称、VR类型等信息

高级用法

use dicom_dictionary_std::DataDictionary;
use dicom_dictionary_std::StandardDataDictionary;

// 获取标准数据字典
let dict = StandardDataDictionary::default();

// 通过标签查询元素信息
if let Some(elem) = dict.by_tag(tags::PATIENT_NAME) {
    println!("VR for Patient Name: {:?}", elem.vr());
    println!("Name for Patient Name: {}", elem.alias());
}

// 通过关键字查询
if let Some(elem) = dict.by_name("PatientName") {
    println!("Found PatientName with tag: {:?}", elem.tag());
}

完整示例代码

以下是一个更完整的示例,展示了如何使用dicom-dictionary-std库进行DICOM文件的完整解析和处理:

use dicom_dictionary_std::tags;
use dicom_dictionary_std::uids;
use dicom_dictionary_std::StandardDataDictionary;
use dicom_object::mem::InMemDicomObject;
use dicom_object::open_file;
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 打开DICOM文件
    let path = Path::new("ct_scan.dcm");
    let obj = open_file(path)?;
    
    // 2. 转换为内存中的DICOM对象
    let obj: InMemDicomObject = obj.into();
    
    // 3. 获取标准数据字典
    let dict = StandardDataDictionary::default();
    
    // 4. 定义要查询的标签列表
    let tags_to_query = [
        tags::PATIENT_NAME,
        tags::PATIENT_ID,
        tags::STUDY_DATE,
        tags::MODALITY,
        tags::SOP_CLASS_UID,
        tags::SERIES_NUMBER,
    ];
    
    // 5. 遍历并打印所有查询的标签信息
    for tag in &tags_to_query {
        if let Some(elem) = obj.element(*tag)? {
            // 从数据字典获取元素信息
            if let Some(dict_entry) = dict.by_tag(*tag) {
                println!("\n元素: {}", dict_entry.alias());
                println!("标签: {:?}", tag);
                println!("VR类型: {:?}", dict_entry.vr());
                
                // 尝试以字符串形式打印值
                if let Ok(value) = elem.to_str() {
                    println!("值: {}", value);
                    
                    // 特殊处理SOP Class UID
                    if *tag == tags::SOP_CLASS_UID {
                        match value {
                            uids::CT_IMAGE_STORAGE => println!("图像类型: CT"),
                            uids::MR_IMAGE_STORAGE => println!("图像类型: MR"),
                            uids::ENHANCED_CT_IMAGE_STORAGE => println!("图像类型: 增强CT"),
                            _ => println!("图像类型: 未知"),
                        }
                    }
                }
            } else {
                println!("\n未知标签: {:?}", tag);
                if let Ok(value) = elem.to_str() {
                    println!("原始值: {}", value);
                }
            }
        }
    }
    
    // 6. 通过名称查询特定元素
    if let Some(elem) = dict.by_name("Modality") {
        if let Some(modality) = obj.element(elem.tag())?.to_str()? {
            println!("\n通过名称查询:");
            println!("Modality: {}", modality);
        }
    }
    
    Ok(())
}

代码说明

  1. 文件打开:使用open_file函数打开DICOM文件
  2. 对象转换:将文件对象转换为内存中的DICOM对象以便处理
  3. 数据字典:获取标准DICOM数据字典用于查询元素信息
  4. 标签查询:定义一组常用的DICOM标签进行查询
  5. 信息打印:遍历查询每个标签并打印相关信息,包括:
    • 元素名称
    • 标签值
    • VR类型
    • 元素值
    • 对SOP Class UID的特殊处理
  6. 名称查询:演示如何通过元素名称查询特定元素

元数据

  • 版本: 0.8.1
  • Rust版本要求: v1.72.0
  • 许可证: MIT OR Apache-2.0
  • 大小: 228 KiB

1 回复

以下是基于提供内容的完整示例demo,展示了如何在实际项目中使用dicom-dictionary-std库:

//! 完整DICOM字典操作示例
//! 展示dicom-dictionary-std库的核心功能

use dicom_dictionary_std::{StandardDataDictionary, tags, uids};
use dicom_core::{Tag, VR};
use std::str::FromStr;

fn main() {
    // 示例1: 基本标签查询
    basic_tag_operations();
    
    // 示例2: 高级字典操作
    advanced_dictionary_operations();
    
    // 示例3: 实际应用 - DICOM元数据解析器
    dicom_metadata_parser();
}

/// 基本标签操作示例
fn basic_tag_operations() {
    println!("=== 基本标签操作 ===");
    
    // 1.1 使用预定义标签常量
    let patient_id_tag = tags::PATIENT_ID;
    println!("[预定义常量] Patient ID 标签: {:?}", patient_id_tag);
    
    // 1.2 手动创建标签
    let study_date_tag = Tag(0x0008, 0x0020);
    println!("[手动创建] Study Date 标签: {:?}", study_date_tag);
    
    // 1.3 获取标签详细信息
    let dict = StandardDataDictionary::default();
    if let Some(entry) = dict.by_tag(study_date_tag) {
        println!("Study Date 详细信息:");
        println!("  名称: {}", entry.alias());
        println!("  VR: {:?}", entry.vr());
        println!("  VM: {}", entry.vm());
    }
    
    // 1.4 通过名称查找标签
    if let Some(entry) = dict.by_name("Modality") {
        println!("通过名称查找 'Modality': {:?}", entry.tag());
    }
}

/// 高级字典操作示例
fn advanced_dictionary_operations() {
    println!("\n=== 高级字典操作 ===");
    
    let dict = StandardDataDictionary::default();
    
    // 2.1 遍历前10个标签(避免输出过多)
    println!("前10个标准DICOM标签:");
    for entry in dict.entries().take(10) {
        println!("  {:?}: {} ({:?})", entry.tag(), entry.alias(), entry.vr());
    }
    
    // 2.2 检查特定VR类型
    let pixel_data_tag = Tag(0x7FE0, 0x0010);
    if let Some(entry) = dict.by_tag(pixel_data_tag) {
        assert_eq!(entry.vr(), VR::OB);
        println!("Pixel Data 的VR类型是 OB (Other Byte)");
    }
    
    // 2.3 比较不同DICOM版本的字典
    let dict_2008 = StandardDataDictionary::new(uids::DICOM_2008_DICTIONARY);
    let dict_2021 = StandardDataDictionary::new(uids::DICOM_2021_DICTIONARY);
    
    let functional_groups_tag = Tag(0x0018, 0x9074);
    println!("功能性组序列标签在不同版本中的存在情况:");
    println!("  2008版: {}", dict_2008.by_tag(functional_groups_tag).is_some());
    println!("  2021版: {}", dict_2021.by_tag(functional_groups_tag).is_some());
}

/// DICOM元数据解析器示例
fn dicom_metadata_parser() {
    println!("\n=== DICOM元数据解析器 ===");
    
    let test_cases = [
        "PatientName",
        "(0010,0010)",  // 与上面等效
        "StudyInstanceUID",
        "(0008,1030)",   // StudyDescription
        "PrivateTag123", // 不存在的标签
        "Rows",
        "(7FE0,0010)",   // PixelData
    ];
    
    for input in test_cases {
        match parse_dicom_element(input) {
            Ok((tag, vr, name)) => {
                println!("解析成功: '{}' -> {:?} (VR: {:?}, 名称: {})", 
                    input, tag, vr, name);
            }
            Err(err) => {
                println!("解析失败: '{}' -> {}", input, err);
            }
        }
    }
}

/// 增强版DICOM元素解析器
fn parse_dicom_element(input: &str) -> Result<(Tag, VR, String), String> {
    let dict = StandardDataDictionary::default();
    
    // 尝试按名称查找
    if let Some(entry) = dict.by_name(input) {
        return Ok((entry.tag(), entry.vr(), entry.alias().to_string()));
    }
    
    // 尝试按"(gggg,eeee)"格式解析
    if let Ok(tag) = Tag::from_str(input) {
        return match dict.by_tag(tag) {
            Some(entry) => Ok((tag, entry.vr(), entry.alias().to_string())),
            None => {
                // 检查是否是私有标签(组号为奇数)
                if tag.0 % 2 == 1 {
                    Ok((tag, VR::UN, "私有标签".to_string()))
                } else {
                    Err("标准字典中未找到此标签".to_string())
                }
            }
        };
    }
    
    Err("无法识别的DICOM标签格式".to_string())
}

这个完整示例整合了内容中提供的所有功能,并做了以下增强:

  1. 将各个功能模块组织成独立函数,便于理解和使用
  2. 添加了更完善的错误处理
  3. 实现了私有标签的自动识别
  4. 提供了更丰富的测试用例
  5. 为所有代码添加了详细注释
  6. 输出格式更清晰,带有标题分隔

要运行此示例,确保Cargo.toml中包含以下依赖:

[dependencies]
dicom-dictionary-std = "0.4"
dicom-core = "0.5"  # 需要手动添加,因为Tag类型来自此crate

输出结果将展示:

  1. 基本标签操作
  2. 高级字典功能
  3. 完整的DICOM标签解析过程,包括标准标签和私有标签处理
回到顶部