DICOMDIR结构

来源:互联网 发布:淘宝售后绩效怎么考核 编辑:程序博客网 时间:2024/05/04 17:01

无论是在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实现


///////////////////////////////////////////////////////////////////////////////
//
// Filename: uDICOMDIR.pas
//
// Summary:
//    DicomStation Source With Delphi7
//
// Modification History:
//    Date         By       Summary
//    --------     -------- ---------------------------------------------
//    07/24/2011   hegb     Original Creation
///////////////////////////////////////////////////////////////////////////////
unit uDICOMDIR;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  //Instance Class
  TImageItem = class(TObject)
    NextDirRecordOffset: LongWord; //(0004,1400)
    RecordInUseFlag: Word; //(0004,1410)
    LowerLevelDirOffset: LongWord; //(0004,1420)
    DirRecordType: string; //(0004,1430)
    ReferenceFileID: string; //(0004,1500)
    ReferenceTransSyntaxUID: string; //(0004,1512)
    InstanceNumber: string; //(0020,0013)
  public
    constructor Create;
    destructor Destroy; override;
  end;

  //Series Class
  TSeriesItem = class(TObject)
    NextDirRecordOffset: LongWord; //(0004,1400)
    RecordInUseFlag: Word; //(0004,1410)
    LowerLevelDirOffset: LongWord; //(0004,1420)
    DirRecordType: string; //(0004,1430)
    Modality: string; //(0008,0060)
    SeriesInstanceUID: string; //(0020,000E)
    SeriesNumber: string; //(0020,0011)
  private
    ImageList: TList; //Image for this Series
  public
    procedure AddImage(pImage: TImageItem);

    constructor Create;
    destructor Destroy; override;
  end;

  //Study Class
  TStudyItem = class(TObject)
    NextDirRecordOffset: LongWord; //(0004,1400)
    RecordInUseFlag: Word; //(0004,1410)
    LowerLevelDirOffset: LongWord; //(0004,1420)
    DirRecordType: string; //(0004,1430)
    StudyDate: string; //(0008,0020)
    StudyTime: string; //(0008,0030)
    AccessionNumber: string; //(0008, 0005) /////////(0008,0050) ===== SH
    StudyInstanceUID: string; //(0020,000D)
    StudyID: string; //(0020,0010)
  private
    SeriesList: TList; //Series for this Study
  public
    procedure AddSeries(pSeries: TSeriesItem);

    constructor Create;
    destructor Destroy; override;
  end;

  //Patient Structure
  TPatientItem = class(TObject)
    NextDirRecordOffset: LongWord; //(0004,1400)
    RecordInUseFlag: Word; //(0004,1410)
    LowerLevelDirOffset: LongWord; //(0004,1420)
    DirRecordType: string; //(0004,1430)
    PatientName: string; //(0010,0010)
    PatientID: string; //(0010,0020)
  private
    StudyList: TList; //Study for this Patient
  public
    procedure AddStudy(pStudy: TStudyItem);

    constructor Create;
    destructor Destroy; override;
  end;

  //DicomDir Class
  TDicomDir =  class(TObject)
    GroupLength: LongWord; //(0002,0000)
    FileMetaVersion: string[2];  //(0002,0001)        ====OB====
    MediaSOPClassUID: string;  //(0002,0002)
    MediaSOPInstanceUID: string;  //(0002,0003)
    TransferSyntaxUID: string;  //(0002,0010)
    ImplementClassUID: string;  //(0002,0012)
    ImplementVersionName: string; //(0002,0013)
    FilesetID: string; //(0004,1130)
    RootDirFistRecord: LongWord; //(0004,1200)
    RootDirLastRecord: LongWord; //(0004,1202)
    FileSetConsFlag: Word;   //(0004,1212)
    DirRecordSequence: LongWord; //(0004,1220)     ====SQ====
    SOPClassUID: string; //(0008, 0016)
  private
    PatientList: TList; //Patient for DICOMDIR
  public
    procedure AddPatient(pPatient: TPatientItem);
    procedure ClearPatient;

    function WriteDicomDir(FilePath: string): Boolean;
    constructor Create;
    destructor Destroy; override;
  end;

function GetEvenStr(const str: string): string;

var
  g_pDICOMDIR: TDicomDir;

implementation

const
  GroupTagLen = 2;   //Group Number -- 2bytes
  ElementTagLen = 2; //Element Number -- 2bytes
//  VR2 = 2;           //Explicit VR时,如果VR = OB,OW,OF,SQ,UT,UN时,VR占用2字节
//  VR4 = 4;           //Explicit VR时,如果VR <> OB,OW,OF,SQ,UT,UN时,VR占用4字节
//  VR_Len2 = 2;       //Explicit VR时,如果VR = OB,OW,OF,SQ,UT,UN时,Value Length占用2字节
//  VR_Len4 = 4;       //Explicit VR时,如果VR <> OB,OW,OF,SQ,UT,UN时,Value Length占用4字节

var
  DICOM_signature: array[0..131] of byte =
    (
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0,
       68, 73, 67 , 77
    );

  VR_Reserved: array[0..1] of Byte = (0, 0);

  ItemBegin_Group: Word = $FFFE;
  ItemBegin_Element: Word = $E000;
  ItemEnd_Group: Word = $FFFE;
  ItemEnd_Element: Word = $E00D;
  ItemEnd_Sequence: Word = $E0DD;

  ItemBegin_Value: LongWord = $FFFFFFFF;
  ItemEnd_Value: LongWord = $00000000;

  iOffSet: LongWord = 0;

procedure WriteDicomDir;
begin
end;

function SwapLong(Value: Cardinal): Cardinal;
asm
  BSWAP EAX
end;

function GetEvenStr(const str: string): string;
begin
  if Length(str) mod 2 <> 0 then
    Result := str + Char(0)
  else
    Result := str;
end;



原创粉丝点击