ClearCanvas源码解析2:读取dcm文件
一、基础知识:
1、数据集和元素结构
一个数据集由多个数据元素组成
数据元素可以嵌套为多级(分组)
一个数据元素分:标记、值类型、长度、和值四部分。
传输语法为隐式VR的,没有值类型。
一个标记分:组和组元素,如(0010,0010)
显示VR数据结构:
tag | vr | value length | value filed |
标记 | 值类型 | 长度 | 值 |
隐式VR数据结构:
tag | value length | value filed |
标记 | 长度 | 值 |
数据意义:0002组存储通讯描述;0008组检查特征; 0010组病人信息组; 0028 图像信息;
2、数据元素长度定义:
显示VR,值类型为 OB,OW,OF,OD,SQ,UC,UR,UT,UN
显示VR,其它类型
隐式VRml数据长度:
二、DCM文件结构
用二进制查看文件,可以明显看到文件内容结构:
有了上面的简单知识,下面就可以了解源码是怎么解析DCM文件的。
三、源码内容:
clearcnavas读取文件类ClearCanvas.Dicom.IO.DicomStreamReader
实现函数:public DicomReadStatus Read(DicomTag stopAtTag, DicomReadOptions options)
从第132个字节开始读取内容----》128+4
先读取MetaInfo信息,这个信息不受传输语法影响,,直接按ExplicitVrLittleEndian语法来解析就行,读取结束到0x0002FFFF
MetaInfo信息读取完后,可以确定DCM的传输语法,,后面信息就根据DCM文件的传输语法做解析。。
读取4个字节,得到VR的TAG值。
如果参数e为0x0000,则为标识为Group Length,VR类型为UL,(参照DICOM3.0标准,第3单和第6单);
其它值则先标识为未知,待后面解析。。。。。
这三个TAG是没有VR值的。。。
本人电脑单步调试太慢,,先写到这里,,,未完待续
下面写一个自己的简单小例子,实现简单的显示VR,DCM文件的读写。。
1 static void Main(string[] args) 2 { 3 string filename = @"E:\work\dcm\1.2.840.10008.1.2.4.50.dcm"; 4 5 BinaryReader dcmfile = new BinaryReader(File.OpenRead(filename)); 6 dcmfile.BaseStream.Seek(132, 0); 7 while (true) 8 { 9 var g1 = dcmfile.ReadUInt16(); 10 var g2 = dcmfile.ReadUInt16(); 11 12 13 string vr = Encoding.Default.GetString(dcmfile.ReadBytes(2)); 14 int nRead = Read2Byte(vr) ? 2 : 6; 15 byte[] bRead = dcmfile.ReadBytes(nRead); 16 int nLen = 0; 17 foreach (byte b in bRead) 18 { 19 nLen += b; 20 } 21 22 bRead = dcmfile.ReadBytes(nLen); 23 string val = getVF(vr, bRead); 24 Console.WriteLine(string.Format("({0} ,{1}) {2} {3} {4}", 25 g1.ToString("X").PadLeft(4, '0'), 26 g2.ToString("X").PadLeft(4, '0'), 27 vr, nLen, val)); 28 29 if (g1 == 0x7FE0 && g2 == 0x0010) 30 break; 31 } 32 33 34 Console.ReadKey(); 35 } 36 37 38 private static bool Read2Byte(string vrNmae) 39 { 40 switch (vrNmae) 41 { 42 case "OB": 43 case "OW": 44 case "OF": 45 case "OD": 46 case "SQ": 47 case "UC": 48 case "UT": 49 case "UN": 50 return false; 51 default: 52 break; 53 } 54 return true; 55 } 56 57 private static string getVF(string VR, byte[] VF) 58 { 59 string VFStr = string.Empty; 60 switch (VR) 61 { 62 case "SS": 63 VFStr = BitConverter.ToInt16(VF, 0).ToString(); 64 break; 65 case "US": 66 VFStr = BitConverter.ToUInt16(VF, 0).ToString(); 67 68 break; 69 case "SL": 70 VFStr = BitConverter.ToInt32(VF, 0).ToString(); 71 72 break; 73 case "UL": 74 VFStr = BitConverter.ToUInt32(VF, 0).ToString(); 75 break; 76 case "AT": 77 VFStr = BitConverter.ToUInt16(VF, 0).ToString(); 78 79 break; 80 case "FL": 81 VFStr = BitConverter.ToSingle(VF, 0).ToString(); 82 83 break; 84 case "FD": 85 VFStr = BitConverter.ToDouble(VF, 0).ToString(); 86 87 break; 88 case "OB": 89 VFStr = BitConverter.ToString(VF, 0); 90 break; 91 case "OW": 92 VFStr = BitConverter.ToString(VF, 0); 93 break; 94 case "SQ": 95 VFStr = BitConverter.ToString(VF, 0); 96 break; 97 case "OF": 98 VFStr = BitConverter.ToString(VF, 0); 99 break; 100 case "UT": 101 VFStr = BitConverter.ToString(VF, 0); 102 break; 103 case "UN": 104 VFStr = Encoding.Default.GetString(VF); 105 break; 106 default: 107 VFStr = Encoding.Default.GetString(VF); 108 break; 109 } 110 return VFStr; 111 } 112 }
结果对比::
得到的数据,一模一样。。。
对于图像解析部分,不太建议用clearCanvas,c#对图像操作不如C++。。还是建议用DCMTK来处理图像压缩和解压缩。。
具体实现方法,后面再写。。