Rust医学影像处理库dicom-encoding的使用,支持DICOM标准数据的高效编解码与解析

Rust医学影像处理库dicom-encoding的使用,支持DICOM标准数据的高效编解码与解析

概述

dicom-encoding是DICOM-rs项目的一部分,提供DICOM数据编码和解码的基础功能。这个库支持DICOM标准数据的高效编解码与解析。

安装

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

cargo add dicom-encoding

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

dicom-encoding = "0.8.2"

示例代码

以下是一个使用dicom-encoding进行DICOM数据编解码的完整示例:

use dicom_encoding::decode::basic::BasicDecoder;
use dicom_encoding::transfer_syntax::TransferSyntaxRegistry;
use dicom_object::mem::InMemDicomObject;
use std::fs::File;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 打开DICOM文件
    let file = File::open("example.dcm")?;
    let reader = BufReader::new(file);
    
    // 获取传输语法注册表
    let registry = TransferSyntaxRegistry::new();
    
    // 创建基本解码器
    let decoder = BasicDecoder::default();
    
    // 解码DICOM文件
    let obj = InMemDicomObject::read_with(reader, &registry, &decoder)?;
    
    // 访问DICOM标签
    if let Some(patient_name) = obj.element_by_name("PatientName")?.to_str() {
        println!("Patient Name: {}", patient_name);
    }
    
    if let Some(study_date) = obj.element_by_name("StudyDate")?.to_str() {
        println!("Study Date: {}", study_date);
    }
    
    Ok(())
}

高级用法

以下是一个更复杂的示例,展示了如何编码和解码DICOM数据:

use dicom_encoding::{
    decode::basic::BasicDecoder,
    encode::basic::BasicEncoder,
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_object::{mem::InMemDicomObject, FileMetaTableBuilder};
use std::fs::File;
use std::io::{BufReader, BufWriter};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取原始DICOM文件
    let input_file = File::open("input.dcm")?;
    let reader = BufReader::new(input_file);
    
    // 初始化传输语法注册表和解码器
    let registry = TransferSyntaxRegistry::new();
    let decoder = BasicDecoder::default();
    
    // 解码DICOM对象
    let mut obj = InMemDicomObject::read_with(reader, &registry, &decoder)?;
    
    // 修改DICOM数据
    obj.put_str("PatientName", "John Doe")?;
    obj.put_str("PatientID", "123456")?;
    
    // 创建文件元信息
    let meta = FileMetaTableBuilder::new()
        .transfer_syntax("1.2.840.10008.1.2.1") // 显式VR小端序
        .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.2") // CT图像存储
        .media_storage_sop_instance_uid("1.2.3.4.5.6.7.8.9.0")
        .build()?;
    
    // 创建输出文件
    let output_file = File::create("output.dcm")?;
    let writer = BufWriter::new(output_file);
    
    // 使用编码器写入DICOM文件
    let encoder = BasicEncoder::default();
    obj.write_with_meta(writer, meta, &encoder)?;
    
    println!("DICOM file successfully processed!");
    Ok(())
}

完整示例代码

以下是一个完整的DICOM文件处理示例,包含读取、修改和保存操作:

use dicom_encoding::{
    decode::basic::BasicDecoder,
    encode::basic::BasicEncoder,
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_object::{mem::InMemDicomObject, FileMetaTableBuilder};
use std::{
    fs::File,
    io::{BufReader, BufWriter},
    path::Path,
};

fn process_dicom_file(
    input_path: &Path,
    output_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
    // 1. 读取DICOM文件
    let input_file = File::open(input_path)?;
    let reader = BufReader::new(input_file);
    
    // 2. 初始化传输语法注册表和解码器
    let registry = TransferSyntaxRegistry::new();
    let decoder = BasicDecoder::default();
    
    // 3. 解码DICOM对象
    let mut dicom_obj = InMemDicomObject::read_with(reader, &registry, &decoder)?;
    
    // 4. 打印原始患者信息
    println!("原始DICOM信息:");
    if let Ok(patient_name) = dicom_obj.element_by_name("PatientName")?.to_str() {
        println!("- 患者姓名: {}", patient_name);
    }
    if let Ok(patient_id) = dicom_obj.element_by_name("PatientID")?.to_str() {
        println!("- 患者ID: {}", patient_id);
    }
    
    // 5. 修改DICOM数据
    println!("\n正在修改DICOM数据...");
    dicom_obj.put_str("PatientName", "张伟")?;
    dicom_obj.put_str("PatientID", "P20230001")?;
    dicom_obj.put_str("StudyDescription", "胸部CT扫描")?;
    
    // 6. 创建新的文件元信息
    let meta = FileMetaTableBuilder::new()
        .transfer_syntax("1.2.840.10008.1.2.1") // 显式VR小端序
        .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.2") // CT图像存储
        .media_storage_sop_instance_uid("2.16.840.1.113883.3.1234.5678.9012.3456")
        .build()?;
    
    // 7. 保存修改后的DICOM文件
    let output_file = File::create(output_path)?;
    let writer = BufWriter::new(output_file);
    
    let encoder = BasicEncoder::default();
    dicom_obj.write_with_meta(writer, meta, &encoder)?;
    
    println!("\nDICOM文件处理完成,已保存到: {}", output_path.display());
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input_path = Path::new("input.dcm");
    let output_path = Path::new("output_processed.dcm");
    
    process_dicom_file(input_path, output_path)
}

特性

  • 支持DICOM标准的各种编码格式
  • 提供高效的编解码实现
  • 与DICOM-rs项目其他组件良好集成
  • 支持显式和隐式VR编码
  • 提供多种传输语法的支持

许可证

dicom-encoding采用MIT或Apache-2.0双许可证授权。


1 回复

Rust医学影像处理库dicom-encoding使用指南

概述

dicom-encoding是一个用于处理DICOM(医学数字成像和通信)标准数据的Rust库,提供高效的编解码和解析功能,支持DICOM文件的各种操作。

主要特性

  • 支持DICOM标准的读取和写入
  • 高效的编解码实现
  • 支持多种传输语法(Transfer Syntax)
  • 提供数据元素的解析和构建
  • 兼容多种DICOM数据类型

安装方法

在Cargo.toml中添加依赖:

[dependencies]
dicom-encoding = "0.2"
dicom-object = "0.4"

基本使用方法

1. 读取DICOM文件

use dicom_object::open_file;
use dicom_encoding::transfer_syntax::TransferSyntaxRegistry;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 打开DICOM文件
    let obj = open_file("example.dcm")?;
    
    // 获取元数据
    let meta = obj.meta();
    println!("Transfer Syntax: {}", meta.transfer_syntax());
    
    // 获取特定标签数据
    if let Some(patient_name) = obj.element_by_name("PatientName")?.str() {
        println!("Patient Name: {}", patient_name);
    }
    
    Ok(())
}

2. 创建DICOM文件

use dicom_object::mem::InMemDicomObject;
use dicom_object::MetaBuilder;
use dicom_encoding::transfer_syntax::TransferSyntaxRegistry;
use dicom_dictionary_std::tags;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建元数据
    let meta = MetaBuilder::new()
        .transfer_syntax("1.2.840.10008.1.2.1") // 显式VR小端序
        .build()?;
    
    // 创建DICOM对象
    let mut obj = InMemDicomObject::new(meta);
    
    // 添加数据元素
    obj.put(tags::PATIENT_NAME, "John Doe");
    obj.put(tags::PATIENT_ID, "123456");
    obj.put(tags::MODALITY, "CT");
    
    // 写入文件
    obj.write_to_file("output.dcm")?;
    
    Ok(())
}

3. 处理像素数据

use dicom_object::open_file;
use dicom_encoding::adapters::PixelDataObject;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let obj = open_file("ct_scan.dcm")?;
    
    // 获取像素数据
    if let Some(pixel_data) = obj.decode_pixel_data()? {
        let data = pixel_data.to_bytes();
        println!("Pixel data length: {} bytes", data.len());
        
        // 获取图像参数
        let cols = pixel_data.columns();
        let rows = pixel_data.rows();
        let samples = pixel_data.samples_per_pixel();
        println!("Image size: {}x{} ({} samples)", cols, rows, samples);
    }
    
    Ok(())
}

高级功能

1. 自定义传输语法处理

use dicom_encoding::transfer_syntax::{TransferSyntax, TransferSyntaxRegistry};
use dicom_encoding::submit_transfer_syntax;

// 定义自定义传输语法处理器
struct MyCustomTransferSyntax;

impl TransferSyntax for MyCustomTransferSyntax {
    fn uid(&self) -> &str {
        "1.2.840.10008.1.2.99" // 自定义UID
    }
    
    // 实现其他必要方法...
}

// 注册自定义传输语法
submit_transfer_syntax!(MyCustomTransferSyntax);

2. 批量处理DICOM文件

use std::path::Path;
use dicom_object::open_file;

fn process_directory(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
    for entry in dir.read_dir()? {
        let entry = entry?;
        let path = entry.path();
        
        if path.extension().map(|e| e == "dcm").unwrap_or(false) {
            let obj = open_file(&path)?;
            // 处理每个DICOM文件...
            println!("Processed: {:?}", path);
        }
    }
    Ok(())
}

性能提示

  1. 对于大批量处理,考虑使用dicom-encoding提供的低级API
  2. 复用TransferSyntaxRegistry实例以避免重复初始化
  3. 对于只读操作,使用FileDicomObject而不是完全加载到内存

错误处理

dicom-encoding提供了丰富的错误类型,建议使用Rust的?操作符进行错误传播:

use dicom_core::error::Error as DicomError;

fn process_dicom(file_path: &str) -> Result<(), DicomError> {
    let obj = open_file(file_path)?;
    // ...处理逻辑
    Ok(())
}

完整示例:DICOM文件查看器

下面是一个完整的DICOM文件查看器示例,结合了读取元数据和像素数据的功能:

use dicom_object::open_file;
use dicom_encoding::adapters::PixelDataObject;
use dicom_core::error::Error as DicomError;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取DICOM文件
    let file_path = "sample.dcm";
    let obj = open_file(file_path)?;
    
    // 打印基本信息
    println!("=== DICOM文件信息 ===");
    println!("文件路径: {}", file_path);
    
    // 获取元数据
    let meta = obj.meta();
    println!("传输语法: {}", meta.transfer_syntax());
    println!("SOP类UID: {}", meta.media_storage_sop_class_uid());
    println!("实例UID: {}", meta.media_storage_sop_instance_uid());
    
    // 打印常用DICOM标签
    println!("\n=== 患者信息 ===");
    if let Some(patient_name) = obj.element_by_name("PatientName")?.str() {
        println!("患者姓名: {}", patient_name);
    }
    if let Some(patient_id) = obj.element_by_name("PatientID")?.str() {
        println!("患者ID: {}", patient_id);
    }
    
    println!("\n=== 检查信息 ===");
    if let Some(study_date) = obj.element_by_name("StudyDate")?.str() {
        println!("检查日期: {}", study_date);
    }
    if let Some(modality) = obj.element_by_name("Modality")?.str() {
        println!("设备类型: {}", modality);
    }
    
    // 处理像素数据
    println!("\n=== 图像数据 ===");
    if let Some(pixel_data) = obj.decode_pixel_data()? {
        let data = pixel_data.to_bytes();
        println!("像素数据大小: {} 字节", data.len());
        
        let cols = pixel_data.columns();
        let rows = pixel_data.rows();
        let samples = pixel_data.samples_per_pixel();
        println!("图像尺寸: {}x{} 像素", cols, rows);
        println!("每像素采样数: {}", samples);
        
        // 获取像素值范围
        if let Some((min, max)) = pixel_data.min_max() {
            println!("像素值范围: {} - {}", min, max);
        }
    } else {
        println!("无像素数据");
    }
    
    Ok(())
}

总结

dicom-encoding库为Rust开发者提供了强大的DICOM数据处理能力,从简单的元数据读取到复杂的像素数据处理,都能高效完成。通过合理使用其API,可以构建高性能的医学影像处理应用。

回到顶部