ITK-读取DICOM文件标签

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

前言

       ‌‌在医学影像领域,DICOM(医学数字成像和通信)格式是存储和传输医学图像的行业标准,其文件头中包含的元数据标签承载着患者信息、扫描参数等关键内容。准确读取这些标签对临床诊断、影像分析及研究数据管理至关重要。Insight Segmentation and Registration Toolkit(ITK)作为开源的医学图像处理框架,提供了高效处理DICOM数据的能力。

       本文将通过实例代码,详细介绍如何利用ITK读取DICOM文件中的元数据标签,涵盖从文件读取、标签解析到特定信息提取的完整流程,为医学影像开发者提供实用的技术参考。

环境准备

参见:Windows下用CMake编译ITK及配置测试_itk配置-CSDN博客

功能说明

       本程序通过ITK库实现了DICOM医学图像的读取与元数据解析,主要功能包括:

  1. DICOM图像读取:使用itkImageFileReaderitkGDCMImageIO组件读取2D DICOM图像,支持自动解析DICOM格式规范。

  2. 元数据全量解析:遍历DICOM头文件中的所有元数据标签,通过GDCM字典将数字标签(如0010|0010)转换为可读名称(如 "Patient's Name"),并输出标签值。

  3. 特定标签查询:演示如何通过标签号0010|0010查询患者姓名,演示如何通过标签号0008|1050查询检查日期。

  4. 图像技术参数获取:提取DICOM文件中的像素类型(如 SHORT、USHORT)和组件类型(如 SCALAR、VECTOR),为后续图像处理提供基础信息。

使用说明

  1. 需安装ITK库及相关依赖。
  2. test.dcm替换为你的DICOM文件路径。
  3. 编译时需链接 ITK的库文件。 

完整代码

#include "itkImageFileReader.h"    /
#include "itkGDCMImageIO.h"         
#include "itkMetaDataObject.h"      

int main()
{
    // --------------------------- 定义图像基本参数 ---------------------------
    using PixelType = short;          // 定义像素类型为short,适用于医学影像的灰度值范围
    constexpr unsigned int Dimension = 2;  // 定义图像维度为2D(适用于切片图像)
    using ImageType = itk::Image<PixelType, Dimension>;  // 组合像素类型和维度定义ITK图像类型

    // --------------------------- 创建图像读取器 ---------------------------
    using ReaderType = itk::ImageFileReader<ImageType>;  // 定义图像文件读取器类型
    auto reader = ReaderType::New();  // 新建读取器实例(ITK采用智能指针管理内存)

    // --------------------------- 配置DICOM图像IO ---------------------------
    using ImageIOType = itk::GDCMImageIO;  // 定义GDCM图像IO类型(基于GDCM库处理DICOM)
    auto dicomIO = ImageIOType::New();  // 新建DICOM图像IO实例
    reader->SetImageIO(dicomIO);  // 将图像IO设置到读取器,使其能解析DICOM格式

    // --------------------------- 设置读取参数并执行 ---------------------------
    reader->SetFileName("test.dcm");  // 设置要读取的DICOM文件名
    try {
        reader->Update();  // 触发图像读取和更新操作(可能抛出异常)
    }
    catch (const itk::ExceptionObject& ex) {
        std::cout << ex << std::endl;  // 捕获并输出ITK异常信息
        return EXIT_FAILURE;
    }

    // --------------------------- 提取DICOM元数据字典 ---------------------------
    using DictionaryType = itk::MetaDataDictionary;  // 定义元数据字典类型
    const DictionaryType& dictionary = dicomIO->GetMetaDataDictionary();  // 从IO获取元数据字典

    // --------------------------- 遍历元数据字典 ---------------------------
    using MetaDataStringType = itk::MetaDataObject<std::string>;  // 定义字符串类型元数据对象
    auto itr = dictionary.Begin();  // 获取字典迭代器起始位置
    auto end = dictionary.End();    // 获取字典迭代器结束位置

    std::cout << "===== DICOM元数据标签列表 =====" << std::endl;
    while (itr != end) {
        itk::MetaDataObjectBase::Pointer entry = itr->second;  // 获取当前元数据项

        // 尝试将元数据项转换为字符串类型(DICOM标签通常以字符串存储)
        MetaDataStringType::Pointer entryvalue = dynamic_cast<MetaDataStringType*>(entry.GetPointer());

        if (entryvalue) {
            std::string tagkey = itr->first;  // 获取DICOM标签键(格式为组号|元素号)
            std::string labelId;  // 用于存储标签对应的可读名称
            bool found = itk::GDCMImageIO::GetLabelFromTag(tagkey, labelId);  // 从GDCM获取标签名称

            std::string tagvalue = entryvalue->GetMetaDataObjectValue();  // 获取标签对应的值

            // 输出带标签名称的键值对(若标签存在于GDCM字典中)
            if (found) {
                std::cout << "(" << tagkey << ") " << labelId << " = " << tagvalue.c_str() << std::endl;
            }
            else {
                std::cout << "(" << tagkey << ") Unknown = " << tagvalue.c_str() << std::endl;
            }
        }
        ++itr;  // 移动到下一个元数据项
    }

    // --------------------------- 查询特定DICOM标签(患者姓名)---------------------------
    std::string entryId = "0010|0010";  // 患者姓名的DICOM标签(0010组0010元素)
    auto tagItr = dictionary.Find(entryId);  // 在字典中查找该标签

    if (tagItr != end) {
        // 尝试将找到的元数据项转换为字符串类型(常量版本)
        MetaDataStringType::ConstPointer entryvalue = dynamic_cast<const MetaDataStringType*>(tagItr->second.GetPointer());
        if (entryvalue) {
            std::string tagvalue = entryvalue->GetMetaDataObjectValue();  // 获取患者姓名值
            std::cout << "\n===== 患者信息 =====" << std::endl;
            std::cout << "Patient's Name (" << entryId << ") is: " << tagvalue.c_str() << std::endl;
        }
    }

    // --------------------------- 查询特定DICOM标签(检查日期)---------------------------
    std::string tagkey = "0008|1050";  // 检查日期的DICOM标签(0008组1050元素)
    std::string labelId;
    if (itk::GDCMImageIO::GetLabelFromTag(tagkey, labelId)) {  // 获取标签名称
        std::string value;
        std::cout << labelId << " (" << tagkey << "): ";
        if (dicomIO->GetValueFromTag(tagkey, value)) {  // 获取标签值
            std::cout << value;
        }
        else {
            std::cout << "(No Value Found in File)";  // 若文件中无该值
        }
        std::cout << std::endl;
    }
    else {
        std::cerr << "Trying to access inexistent DICOM tag." << std::endl;  // 标签不存在
    }

    // --------------------------- 获取图像像素类型信息 ---------------------------
    itk::IOPixelEnum pixelType = reader->GetImageIO()->GetPixelType();  // 获取像素类型枚举值
    itk::IOComponentEnum componentType = reader->GetImageIO()->GetComponentType();  // 获取组件类型枚举值
    std::cout << "\n===== 图像技术参数 =====" << std::endl;
    std::cout << "PixelType: " << reader->GetImageIO()->GetPixelTypeAsString(pixelType) << std::endl;  // 输出像素类型名称
    std::cout << "Component Type: " << reader->GetImageIO()->GetComponentTypeAsString(componentType) << std::endl;  // 输出组件类型名称

    return EXIT_SUCCESS;
}

测试效果 

​输出:格式为ID-描述-数值

  

对比:

  

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翟天保Steven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值