DICOMDIR结构分析与实现

无论是在DICOM文件还是DICOM通信中,其信息都是由许多data element(数据单元)的集合所表示,每个data element表示一个属性,如病人姓名、图像类型等等。这些data element按照Tag值从小到大依次连接,类似于数据结构的链表或者数组(SQ类型有另外的编码方式,以后会讲到),请看下图,一个data element包含四个字段Tag,VR,ValueLength,Value Field.

 

DICOMDIR 是一个可变长度 迷你 database 文件。由 group (0002, xxxx) 和 group (0004, xxxx) 为主题。描述的是一个 4 层的树状结构 (tree structure)。

1. Patient
2. Study
3. Series
4. Image

 

 

将data element的数据结构编码为字节流时受以下几个因素影响:

1.传输语法: Implicit/Explicit VR,      BIG/LITTLE Endian

2.VR

当采用implicit VR时,其编码如下,这个时候是没有VR字段的,它采用data dictionary默认的VR.

 

 

 

DICOMDir结构的delphi实现:

  1 ///////////////////////////////////////////////////////////////////////////////
  2 //
  3 // Filename: uDICOMDIR.pas
  4 //
  5 // Summary:
  6 //    DicomStation Source With Delphi7
  7 //
  8 // Modification History:
  9 //    Date         By       Summary
 10 //    --------     -------- ---------------------------------------------
 11 //    07/24/2011   hegb     Original Creation
 12 ///////////////////////////////////////////////////////////////////////////////
 13 unit uDICOMDIR;
 14 
 15 interface
 16 
 17 uses
 18   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 19   Dialogs, StdCtrls;
 20 
 21 type
 22   //Instance Class
 23   TImageItem = class(TObject)
 24     NextDirRecordOffset: LongWord; //(0004,1400)
 25     RecordInUseFlag: Word; //(0004,1410)
 26     LowerLevelDirOffset: LongWord; //(0004,1420)
 27     DirRecordType: string; //(0004,1430)
 28     ReferenceFileID: string; //(0004,1500)
 29     ReferenceTransSyntaxUID: string; //(0004,1512)
 30     InstanceNumber: string; //(0020,0013)
 31   public
 32     constructor Create;
 33     destructor Destroy; override;
 34   end;
 35 
 36   //Series Class
 37   TSeriesItem = class(TObject)
 38     NextDirRecordOffset: LongWord; //(0004,1400)
 39     RecordInUseFlag: Word; //(0004,1410)
 40     LowerLevelDirOffset: LongWord; //(0004,1420)
 41     DirRecordType: string; //(0004,1430)
 42     Modality: string; //(0008,0060)
 43     SeriesInstanceUID: string; //(0020,000E)
 44     SeriesNumber: string; //(0020,0011)
 45   private
 46     ImageList: TList; //Image for this Series
 47   public
 48     procedure AddImage(pImage: TImageItem);
 49 
 50     constructor Create;
 51     destructor Destroy; override;
 52   end;
 53 
 54   //Study Class
 55   TStudyItem = class(TObject)
 56     NextDirRecordOffset: LongWord; //(0004,1400)
 57     RecordInUseFlag: Word; //(0004,1410)
 58     LowerLevelDirOffset: LongWord; //(0004,1420)
 59     DirRecordType: string; //(0004,1430)
 60     StudyDate: string; //(0008,0020)
 61     StudyTime: string; //(0008,0030)
 62     AccessionNumber: string; //(0008, 0005) /////////(0008,0050) ===== SH
 63     StudyInstanceUID: string; //(0020,000D)
 64     StudyID: string; //(0020,0010)
 65   private
 66     SeriesList: TList; //Series for this Study
 67   public
 68     procedure AddSeries(pSeries: TSeriesItem);
 69 
 70     constructor Create;
 71     destructor Destroy; override;
 72   end;
 73 
 74   //Patient Structure
 75   TPatientItem = class(TObject)
 76     NextDirRecordOffset: LongWord; //(0004,1400)
 77     RecordInUseFlag: Word; //(0004,1410)
 78     LowerLevelDirOffset: LongWord; //(0004,1420)
 79     DirRecordType: string; //(0004,1430)
 80     PatientName: string; //(0010,0010)
 81     PatientID: string; //(0010,0020)
 82   private
 83     StudyList: TList; //Study for this Patient
 84   public
 85     procedure AddStudy(pStudy: TStudyItem);
 86 
 87     constructor Create;
 88     destructor Destroy; override;
 89   end;
 90 
 91   //DicomDir Class
 92   TDicomDir =  class(TObject)
 93     GroupLength: LongWord; //(0002,0000)
 94     FileMetaVersion: string[2];  //(0002,0001)        ====OB====
 95     MediaSOPClassUID: string;  //(0002,0002)
 96     MediaSOPInstanceUID: string;  //(0002,0003)
 97     TransferSyntaxUID: string;  //(0002,0010)
 98     ImplementClassUID: string;  //(0002,0012)
 99     ImplementVersionName: string; //(0002,0013)
100     FilesetID: string; //(0004,1130)
101     RootDirFistRecord: LongWord; //(0004,1200)
102     RootDirLastRecord: LongWord; //(0004,1202)
103     FileSetConsFlag: Word;   //(0004,1212)
104     DirRecordSequence: LongWord; //(0004,1220)     ====SQ====
105     SOPClassUID: string; //(0008, 0016)
106   private
107     PatientList: TList; //Patient for DICOMDIR
108   public
109     procedure AddPatient(pPatient: TPatientItem);
110     procedure ClearPatient;
111 
112     function WriteDicomDir(FilePath: string): Boolean;
113     constructor Create;
114     destructor Destroy; override;
115   end;
116 
117 function GetEvenStr(const str: string): string;
118 
119 var
120   g_pDICOMDIR: TDicomDir;
121 
122 implementation
123 
124 const
125   GroupTagLen = 2;   //Group Number -- 2bytes
126   ElementTagLen = 2; //Element Number -- 2bytes
127 //  VR2 = 2;           //Explicit VR时,如果VR = OB,OW,OF,SQ,UT,UN时,VR占用2字节
128 //  VR4 = 4;           //Explicit VR时,如果VR <> OB,OW,OF,SQ,UT,UN时,VR占用4字节
129 //  VR_Len2 = 2;       //Explicit VR时,如果VR = OB,OW,OF,SQ,UT,UN时,Value Length占用2字节
130 //  VR_Len4 = 4;       //Explicit VR时,如果VR <> OB,OW,OF,SQ,UT,UN时,Value Length占用4字节
131 
132 var
133   DICOM_signature: array[0..131] of byte =
134     (
135        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
136        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
137        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
138        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
139        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
140        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
141        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
142        0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
143        68, 73, 67 , 77
144     );
145 
146   VR_Reserved: array[0..1] of Byte = (0, 0); 
147 
148   ItemBegin_Group: Word = $FFFE;
149   ItemBegin_Element: Word = $E000;
150   ItemEnd_Group: Word = $FFFE;
151   ItemEnd_Element: Word = $E00D;
152   ItemEnd_Sequence: Word = $E0DD;
153 
154   ItemBegin_Value: LongWord = $FFFFFFFF;
155   ItemEnd_Value: LongWord = $00000000;
156 
157   iOffSet: LongWord = 0; 
158 
159 procedure WriteDicomDir;
160 begin
161 end;
162 
163 function SwapLong(Value: Cardinal): Cardinal;
164 asm
165   BSWAP EAX
166 end;
167 
168 function GetEvenStr(const str: string): string;
169 begin
170   if Length(str) mod 2 <> 0 then
171     Result := str + Char(0)
172   else
173     Result := str;
174 end;

 

posted @ 2012-12-26 10:33  微笑的艾米  阅读(1068)  评论(0编辑  收藏  举报