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(())
}
主要功能
- 标准DICOM标签访问:通过
tags
模块提供所有标准DICOM属性的快捷访问方式 - UID常量:通过
uids
模块提供标准DICOM UID的常量定义 - 数据字典查询:可以查询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(())
}
代码说明
- 文件打开:使用
open_file
函数打开DICOM文件 - 对象转换:将文件对象转换为内存中的DICOM对象以便处理
- 数据字典:获取标准DICOM数据字典用于查询元素信息
- 标签查询:定义一组常用的DICOM标签进行查询
- 信息打印:遍历查询每个标签并打印相关信息,包括:
- 元素名称
- 标签值
- VR类型
- 元素值
- 对SOP Class UID的特殊处理
- 名称查询:演示如何通过元素名称查询特定元素
元数据
- 版本: 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())
}
这个完整示例整合了内容中提供的所有功能,并做了以下增强:
- 将各个功能模块组织成独立函数,便于理解和使用
- 添加了更完善的错误处理
- 实现了私有标签的自动识别
- 提供了更丰富的测试用例
- 为所有代码添加了详细注释
- 输出格式更清晰,带有标题分隔
要运行此示例,确保Cargo.toml中包含以下依赖:
[dependencies]
dicom-dictionary-std = "0.4"
dicom-core = "0.5" # 需要手动添加,因为Tag类型来自此crate
输出结果将展示:
- 基本标签操作
- 高级字典功能
- 完整的DICOM标签解析过程,包括标准标签和私有标签处理