`
chinamming
  • 浏览: 140044 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

DICOM文件格式与编程

 
阅读更多

任何图像文件格式无非是由两个部分组成:存参数的 header 和图点数据(pixel data)。
BMP、 JPEG、TIFF 之类的格式的 header 只描述图像的基本参数:如几行、几列、每点用了几位、有没有压缩、调色板等等。Header 往往是固定长度的。
而医疗影像还要许多其它参数,如病人基本资料、检验基本资料、系列资料、位置资料等等。而且每种Modality 和每种 image 所需要的内容不一样。因此,一般的图像格式不能使用。

一、DICOM 的 4 个内容层次
1、 Patient (病人)
2、 Study (检验)
3、 Series (系列)
4、 Image (图像)
尽管头几层的内容在很多图像里是相同的,但它们在每个图像文件里都要有。
每一层叫一个Information Entity或IE(从relational database schema 设计引用而来)。每一层又细分成Module。每个Module里面的最小单元叫做一个attribute或element。
现在举个例子:CR 图像 (DICOM Part 3, A.2.3, Table A.2-1
1. Patient IE:
a. Patient Module (参考 C.7.1.1)
2. Study IE:
a. Study Module (参考 C.7.2.1)
b. Patient Study Module (参考 C.7.2.2)
3. Series IE:
a. General Series (参考 C.7.3.1)
b. CR Series (参考 C.8.1..1)
c. General Equipment (参考 C.7.5.1)
4. Image IE:
a. Genrral Image (C.7.6.1)
b. Image Pixel (C.7.6.3)
c. Contrast/bolus (C.7.6.4)
d. CR Image (C.8.1.2)
...
i. SOP Common (C.12.1)
将这些 modules (tables) 里的所有 elements 都找出来就做成了一个 CR 图像的架构。
要注意的是这些 module 有些是一定要的 (modatory) 有些是用户选用的 (user)。到了每个 module 里 attribute/element 表又有分五类 Type 1, 1C, 2, 2C 和 3。 Type 1 是一定要的,2 也是一定要的但是内容可以是空的。Type 3 则可要可不要。所以浓缩一下,一个 CR 图像里的元素 (elements) 也不是太多。把这些表格展开后,这些 elements 组成一个 dataset。
那么,写到一个文件里或通过网路传送又是个什么格式呢?这就要看 Part 5。一个元素 (element) 的结构是:
1. group tag: 16-bit
2. element tag: 16-bit
3. length (or VR/length): 32-bit
4. data (bytes of length)
对应每一个用到的 element DICOM 标准 Part 6 都定义了一个 group tag 和 element tag。比如说:
patient name: 0x0010, 0x0010
patient ID: 0x0010, 0x0020
...
VR说的是element格式,比如说patinet name 的VR是PN。格式是 last_name^first_name^middle_name^prefix^surfix。那么我的英文名字就是: Wang^JB^^Dr.^
往外写时要做几个事情:
1. 要把所有元素按 group tage 和 element tag 理一遍 (sort)。从小排到大。
2. 如果是写 DICOM 介质的 DICOM file 还先写 128 bytes preamble (一般是空白),加 "DICM", 加 group 2 Meta header。(讲到 Part 10 时再细说)
3. 如果 dataset 里面含有 Sequence elements, sequence 里面每一个 Item 又是一个 dataset。
有了这些知识,你就可以开始写一个小小的 BMP 到 DICOM 的转化程序。关键资料:
Modality (0008, 0060): SC
Photometric Interpretation (0028, 0004): RGB
SOP Class UID: 1.2.840.10008.1.5.4.1.1.7
最简单的办法是写一个 structure 然后一个 array。

typedef struct DicomElem 
{
  short int group_tag,
  short int element_tag,
  char VR[4],
  int length,
  char data[128]
} DicomElem;

DicomElem CRDataSet [] =
{
{ 0x0008, 0x0005, "CS", 10, "ISO_IR 100"},
{ 0x0008, 0x0008, "CS", 16, "ORIGINAL//PRIMARY"},
  ...
{0x0010, 0x0010, "PN", 16, "My^Test^Image^^ "},
{0x0010, 0x0020, "SH", 6, "123456"},
...
{0,0,"",0,""}
};

void WriteCDImage(FILE *fp)
{
  DicomElem elem = CRDataSet[0];
  unsigned long int lComboTag;
  int nCols, nRows;
  unsigned char *pPixelData
  unsigned long int lPixelLength;

  pPixelData = LoadBMPImgeData("MyImage.bmp", nCols, nRows, lPixelLength);

  while(CRDataSet[i].group_tag)
  {
     lComboTag = (CRDataSet[i].group_tag << 16) | CRDataSet[i].element_tag;
    tch(lComboTag)
     {

       case 0x00280010:
           *((short int *)CRDataSet[i].data) = nCols;
        break;
       case 0x00280011:
           *((short int *)CRDataSet[i].data) = nRows;
       break;
       ...
     }
     
   // Write group and element tag
   fwrite(&lComboTag, 1, sizeof(long), fp);

   // Write VR
   fwrite(CRDataSet[i].VR, 1, 2, fp);

   if (lComboTag != 0x7fe00010)
     {
        fwrite(CRDataSet[i].length, 1, sizeof(short), fp);
        fwrite(CRDataSet[i].data, 1, CRDataSet.length, fp);
      }
   else
       {
          fwrite("/0/0", 1, 2, fp); // Two blank bytes after VR
          fwrite(&lPixelLength, 1, sizeof(long), fp);  // Length
         fwrite(pPixelData, 1, lPixelLength, fp);   
       }

  i++; 

  }

}

unsigned char *LoadBMPImgeData(char *fileName, int &nCols, int &nRows, unsigned long &lPixelLength)
{
....
}

细节自己去写。

二、DICOM文件读写最难的是两件事情
DICOM Sequence
DICOM Pixel Data
Sequence 在 C 里的类比是一个 structure 的 array,是结构套结构,所以读起来难。更麻烦的是 Sequence 还可以不定义长度, 即长度是 -1。要靠你自己去找 (FFFE, E0DD) 来决定 Sequence 是否结束。
Array 里面的每个 structure就是 DICOM Sequence 里的一个 Item。Item 的开头是一个特定 element (FFFE, E000)。 如果 Item 的长度是 -1, 要靠找到 (FFFE, E00D) 来决定 Item 的结束。
Pixel Data (7fe0, 0010) 是一个特殊的 DICOM element。总是在所有元素的最后面。它与 Sequence 有两个相似的地方:长度区总是 32-位 (即 explicit VR 的情况下要在 VR 区后面填两个 bytes,然后再加 4-bytes 的长度。
如图像是压缩的,每幅图用一个 item 来存。 第一个 item 是个 offset table。每幅图的 offset 是一个 dword (4 bytes),第一幅图的 offset 是 0。

三、DICOM file 细节问题
element 的 data 长度一定要是一个偶数。
要注意 big endian 和 little endian 的区别。软件要自动判断机器的 endian 和 DICOM 文件的 transfer syntax。常见的:Intel PC 是 little endian, Sun 是 big endian。
如果机器的 endian 和数据的 endian 不对的话要做 byte swap。要做 byte swap 的有所有的根数字有关的 binary data, 即 VR = SS, US, SL, UL, FL, FD, OW, AT 等等。DICOM group tag 和 element tag 也要分别做两个 byte 的 swap。Item 指的是 DICOM Sequence 的 Item。

0x7fe0, 0x0010, "OB", ' '' ', 0xffffffff    // tag, VR, 长度
0xFFFE, 0x0000, 0xffffffff                  // Offset item begins
0x00000000  // Offset of first image = 0
0x00001000  // Offset of second image = 4096 (for example)
...
0xFFFE, 0xE00D  // End of offset item
0xFFFE, 0x0000, 0x00001000      // first image item and length = 4096 (for example)
...             // (4096 bytes)
0xFFFE, 0xE00D  // end of first image
...
0xFFFE, 0xE0DD  // End o of pixel data sequence



分享到:
评论

相关推荐

    DICOM文件格式与编程;VC++实现;

    DICOM文件格式与编程;VC++实现; DICOM文件格式与编程;VC++实现;

    DICOM文件编程[借鉴].pdf

    DICOM文件编程[借鉴].pdf

    DICOM格式文件

    DICOM 文件格式的介绍,编程方法介绍说明。

    Dicom格式的文件

    Dicom格式的文件,大家可以在编程时直接使用

    DICOM格式文件(*.dcm),600张dcm格式CT图像,另附dcm浏览器

    提示一个坑,当时搞了很久,后来才发现的:其中series-000001文件夹里是JPEG2000压缩格式的dcm文件(32MB),免费版的DCMTK库是不支持的,可以用其他软件(如gdcmconv)解压为原始图像(181M),如果还打不开可以...

    DICOM图像文件解析及程序设计

    :分析DICOM标准,建立解析DICOM文件的模型,研 究DICOM文件解析及其图像显示的方法。以DICOM3.0标 准为对象,提出将DICOM 文件划分为概念模型、数据模型、 物理模型3个层面;以概念模型、数据模型为指导进行解析 ...

    裸数据转成dicom图像格式

    该代码文件实现了将CT图像裸数据如何生成dicom格式文件

    DICOM格式医学图像的读取与显示

    DICOM(digital imaging and communications in medicine)...本研究首先分析了DICOM格式图像文件的结构,然后给出开窗显示的理论分析,最后,利用C/C++语言VC++开发环境下编程实现了DICOM格式医学冈像的渎取和显示。

    DICOM格式医学图像及其图像信息的显示

    摘要:目的 探讨 DICOM 格式医学图像的读取与显示方法, 为后续的图像处理和临床诊断提供预处理和理论 础。方法 首先分析 DICOM 格式文件的结构, 然后给出开窗显示的理论分析, 最后,利用 C /C+ + 语言在 VC﹢ 开发环境...

    绝对可用的dicom医学图像格式转换为BMP格式(仅含exe程序)

    采用MFC和delphi混合编程形成的可执行文件,代码量太大,且不是我开发的,我只是调用,不方便公开。可以支持目前大部分的dicom标准的图像的转换,但必须在exe同级目录下放置TempImage文件夹才可以。如果想修改此目录...

    2010 DICOM格式医学图像的读取与显示.pdf

    摘要: 目的 探讨 D I CO M 格式医学图像的读取与显示方法, 为后续的图像处理和临 床诊断提 供预处理和 理论 基础。方法 首先分析 D I CO M 格式文件的结构, 然后给出开窗显示的理论分析, 最后, 利用 C / C + + ...

    DICOM转换为BMP程序

    DICOM转换为BMP程序 DICOM 数字影像 学习研究影像编程很有帮助

    Dicom3医学影像文件浏览

    很简单的Dicom3文件浏览小软件,适合学习医学影像文件编程的初学者,VS2010C# 编译通过。

    2010 用Matlab和VC++实现DICOM医学图像的显示.pdf

    摘要:DICOM是各种数字化影像设备的图像格式和数据传输标准。许多医学图像都采用了DICOM标准。DICOM医学图像的编 码和显示是医学图像研究的基础。该文介绍了DICOM的相关概念和医学图像的组织结构。列出了数据集进行...

    医学数字影像和通讯dicom编程简介

    关于数字影像和通讯的文档,描述清楚。包括dicom文件结构、如何编写dicom程序和利用开发包开发dicom程序。

    DICOM3DSDK.rar

    一套成熟的DICOM开发包,以ACTIVEX方式发布,支持cc++、delphi、vb、c#、vb.net等多种编程语言,是你快速开发PACS软件的理想选择,帮助 文件和例子程序请到www.dicom3dsdk.cn下载。主要功能包括: 网络通讯: 支持...

    DICOM3DSDK-PACS 开发包

    一套成熟的DICOM开发包,以ACTIVEX方式发布,支持cc++、delphi、vb、c#、vb.net等多种编程语言,是你快速开发PACS软件的理想选择,帮助 文件和例子程序请到www.dicom3dsdk.cn下载。主要功能包括: 网络通讯: 支持...

    DICOM_ITK_VTK:使用 ITK 4.7.1 读取 DICOM 串行图像,并使用 VTK 6.2.rc1 渲染卷。 OS X 10.10

    编程环境** 操作系统 ** - OS X 10.10 ** 工具链 ** - CMake 3.1.3、GDB 7.8 ** VTK 版本 ** - VTK 6.2.rc1 ** ITK 版本 ** - ITK 4.7.1VTK的编译** BUILD_SHARED_LIBS ** - 开启** CMAKE_BUILD_TYPE ** - 发布** ...

    VC与Labview、Matlab编程论文资料[2].rar

    基于MFC的Word文件编程.pdf 基于MFC的产品结构树管理系统的实现.pdf 基于MFC的代码编辑器设计方法.pdf 基于MFC的加密解密工具的开发.pdf 基于MFC的动态链接库的创建和调用方法研究.pdf 基于MFC的工程软件界面设计....

Global site tag (gtag.js) - Google Analytics