dicom读取方法.docx

上传人:b****6 文档编号:6556456 上传时间:2023-01-07 格式:DOCX 页数:11 大小:127.19KB
下载 相关 举报
dicom读取方法.docx_第1页
第1页 / 共11页
dicom读取方法.docx_第2页
第2页 / 共11页
dicom读取方法.docx_第3页
第3页 / 共11页
dicom读取方法.docx_第4页
第4页 / 共11页
dicom读取方法.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

dicom读取方法.docx

《dicom读取方法.docx》由会员分享,可在线阅读,更多相关《dicom读取方法.docx(11页珍藏版)》请在冰豆网上搜索。

dicom读取方法.docx

dicom读取方法

Dicom格式文件解析器

学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码流处理。

只不过确实比较繁琐。

分析

整体结构先是128字节所谓的导言部分,说俗点就是没啥意义的破数据跳过就是了,然后是dataElement依次排列的方式就是一个dataElement接一个dataElement的方式排到文件结尾通俗的讲dataElement就是指tag就是破Dicom标准里定义的数据字典。

tag是4个字节表示的前两字节是组号后两字节是偏移号比如0008,0018。

所有dataElement在文件中都是按tag排序的比如0002,00010002,00020003,0011

文件整体结构如下:

又把论文里的这图贴上来总结的很好。

单个dataElement的结构如下:

显示VR:

VR为OBOWOFUTSQUN的元素结构

组号

元素号

VR

预留

值长度

数据元素值

2

2

2

2(0x00,0x00)

4

由数据长度决定

显示VR:

VR为普通类型时元素结构(少了预留那一行)

组号

元素号

VR

值长度

数据元素值

2

2

2

4

由数据长度决定

隐式VR时元素结构

组号

元素号

值长度

数据元素值

2

2

4

由数据长度决定

 

要问VR是啥东东,值表示法啥叫值表示法啊俺不懂intstringshortushort懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。

VR总共27个跟c#值类型对应关系我都写好了:

1stringgetVF(stringVR,byte[]VF)

2{

3stringVFStr=;

4switch(VR)

5{

6case"SS":

7VFStr=(VF,0).ToString();

8break;

9case"US":

10VFStr=(VF,0).ToString();

11

12break;

13case"SL":

14VFStr=(VF,0).ToString();

15

16break;

17case"UL":

18VFStr=(VF,0).ToString();

19

20break;

21case"AT":

22VFStr=(VF,0).ToString();

23

24break;

25case"FL":

26VFStr=(VF,0).ToString();

27

28break;

29case"FD":

30VFStr=(VF,0).ToString();

31

32break;

33case"OB":

34VFStr=(VF,0);

35break;

36case"OW":

37VFStr=(VF,0);

38break;

39case"SQ":

40VFStr=(VF,0);

41break;

42case"OF":

43VFStr=(VF,0);

44break;

45case"UT":

46VFStr=(VF,0);

47break;

48case"UN":

49VFStr=break;

51default:

52VFStr=break;

54}

55returnVFStr;

56}

找个dicom文件在十六进制编辑器下瞧瞧给你整明白:

所有dataElement从前到后按tag又可简单分段:

文件元dataElement

不受传输语法影响总是以显示VR方式表示因为它里面就定义了传输语法

普通dataElement

受传输语法影响显示VR表示方式还是隐式VR表示方式

像素数据dataElement

最重要也是最大的一个数据项其实存储的就是图像数据

 

几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。

文件元dataElement和跟像素数据相关的dataElement都很重要,其他的很多如果全部照顾完的话估计得写上千行switch语句吧,所以没有必要一般我们一般只关键的tag。

并且在隐式语法下要确定VR也必须根据字典来确定

关键的tag如下:

1stringgetVR(stringtag)

2{

3switch(tag)

4{

5case"0002,0000":

))

59{

60case".jpg":

61(filename,62break;

63case".bmp":

64(filename,65break;

66case".png":

67(filename,68break;

69default:

70break;

71}

72}

73publicboolgetImg()ubstring(5));

82cols=(tags["0028,0011"].Substring(5));

83

84colors=(tags["0028,0002"].Substring(5));

85dataLen=(tags["0028,0100"].Substring(5));

86validLen=(tags["0028,0101"].Substring(5));

87

88gdiImg=newBitmap(cols,rows);

89

90BinaryReaderdicomFile=newBinaryReader(fileName));

91

92;

93

94longreads=0;

95for(inti=0;i<;i++)

96{

97for(intj=0;j<;j++)

98{

99if(reads>=pixDatalen)

100break;

101byte[]pixData=(dataLen/8*colors);

102reads+=;

103

104Colorc=;

105if(colors==1)

106{

107intgrayGDI;

108

109doublegray=(pixData,0);

110oString("x4")+","+

152().ToString("x4");

153

154stringVR=;

155UInt32Len=0;

156//读取VR跟Len

157//对OBOWSQ要做特殊处理先置两个字节0然后4字节值长度

158//------------------------------------------------------这些都是在读取VR一步被阻断的情况

159if(0,4)=="0002")//文件头特殊情况

160{

161VR=newstring

(2));

162

163if(VR=="OB"||VR=="OW"||VR=="SQ"||VR=="OF"||VR=="UT"||VR=="UN")

164{

165;

166Len=();

167}

168else

169Len=();

170}

171elseif(tag=="fffe,e000"||tag=="fffe,e00d"||tag=="fffe,e0dd")//文件夹标签

172{

173VR="**";

174Len=();

175}

176elseif(isExplicitVR==true)//有无VR的情况

177{

178VR=newstring

(2));

179

180if(VR=="OB"||VR=="OW"||VR=="SQ"||VR=="OF"||VR=="UT"||VR=="UN")

181{

182;

183Len=();

184}

185else

186Len=();

187}

188elseif(isExplicitVR==false)

189{

190VR=getVR(tag);//无显示VR时根据tag一个一个去找真烦啊。

191Len=();

192}

193//判断是否应该读取VF以何种方式读取VF

194//-------------------------------------------------------这些都是在读取VF一步被阻断的情况

195byte[]VF={0x00};

196

197if(tag=="7fe0,0010")//图像数据开始了

198{

199pixDatalen=Len;

200pixDataOffset=;

202VR="UL";

203VF=(Len);

204}

205elseif((VR=="SQ"&&Len==||(tag=="fffe,e000"&&Len==)//靠遇到文件夹开始标签了

206{

207if(enDir==false)

208{

209enDir=true;

210(0,;

211folderTag=tag;

212}

213else

214{

215leve++;//VF不赋值

216}

217}

218elseif((tag=="fffe,e00d"&&Len==||(tag=="fffe,e0dd"&&Len==)//文件夹结束标签

219{

220if(enDir==true)

221{

222enDir=false;

223}

224else

225{

226leve--;

227}

228}

229else

230VF=((int)Len);

231

232stringVFStr;

233

234VFStr=getVF(VR,VF);

235

236//----------------------------------------------------------------针对特殊的tag的值的处理

237//特别针对文件头信息处理

238if(tag=="0002,0000")

239{

240fileHeadLen=Len;

241fileHeadOffset=}

243elseif(tag=="0002,0010")//传输语法关系到后面的数据读取

244{

245switch(VFStr)

246{

247case"\0":

//显示little

248isLitteEndian=true;

249isExplicitVR=true;

250break;

251case"\0":

//显示big

252isLitteEndian=false;

253isExplicitVR=true;

254break;

255case"":

//隐式little

256isLitteEndian=true;

257isExplicitVR=false;

258break;

259default:

260break;

261}

262}

263for(inti=1;i<=leve;i++)

264tag="--"+tag;

265//------------------------------------数据搜集代码

266if((VR=="SQ"&&Len==||(tag=="fffe,e000"&&Len==||leve>0)//文件夹标签代码

267{

268(tag+"("+VR+"):

"+VFStr);

269}

270elseif(((tag=="fffe,e00d"&&Len==||(tag=="fffe,e0dd"&&Len==)&&leve==0)//文件夹结束标签

271{

272(tag+"("+VR+"):

"+VFStr);

273(folderTag+"SQ",());

274}

275else

276(tag,"("+VR+"):

"+VFStr);

277}

278}

279}

好了收工。

测试下成果

1if()!

=

2return;

3

4stringfileName=;

5

6handler=newDicomHandler(fileName);

7

8(textBox1);

9

10="DicomViewer-"+;

11

12

13();

这里处理gdi位图的时候直接用的setPix处理速度比较慢所以用了backgroundWorker,实际应用中请使用内存缓冲跟指针的方式

否则效率低了是得不到客户的认可的哦,gdi位图操作可使用lockBits加指针的方式,12位的灰度像素数据可以第一次读取后缓存到内存中以方便后面调窗的快速读取

这点代码也不难哈对指针什么的熟点就行了,前几章都有。

这是ezDicom经过公认测试的软件我们来跟他对比一下,打开

调窗测试,我们注意到两个东西在没有窗宽窗位时默认窗宽是2047+1即2048窗位是2048/2即1024

直观的感受是调窗宽像在调图像对比度,调窗位像在调图像亮度。

窗宽为255的时候图像是最瑞丽的因为255其实就是8位图像的默认窗宽。

注意窗位那里有小小区别,ez窗位显示的是根据1024那里为0开始偏移而我的程序是根据窗宽中间值没有偏移

没有偏移的情况稍微符合逻辑点吧。

但是可以看到原理是一样的结果是一样的。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1