请教如何读取矩阵生成图像用DCMTK读取DCM图像的CT值

1768人阅读
医学影像DCM是个类似PNG的分块格式,内涵丰富医疗信息,由于应用领域较窄,OpenCV没有提供对其加载支持,一般采用dcmtk库进行加载。
博主本着研究探索的精神写了这段代码,并分享出来,提供了解析DCM的DIB数据、宽高、窗宽窗位、像素间距的功能,支持反色DCM。
将来可以参考spec文档进行扩充,可以在大框架中加入块的处理,从而抽取更多感兴趣的信息,也可以加入压缩DCM的支持。
// 输入:文件名
// 输出:宽高 窗宽窗位 像素间距 dib
unsigned short* dcmLoadImage(char* fn, int& width, int& height, int& windowWidth, int& windowLevel, double& pixelSpacing)
// 读取整个文件到内存
FILE* f = fopen(fn, &rb&);
fseek(f, 0, SEEK_END);
int dcmSize = ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char* dcm = new unsigned char[dcmSize];
fread(dcm, dcmSize, 1, f);
fclose(f);
width = -1;
height = -1;
windowWidth = -1;
windowLevel = -1;
pixelSpacing = 0.0;
bool invert =
unsigned short* dib = NULL;
int dibSize = -1;
int p = 132;
while( p&dcmSize )
short group = *(short*)(dcm+p);
short element = *(short*)(dcm+p);
//cout&&setfill('0')&&hex&&setw(4)&&group&&&,&&&setw(4)&&element&&setfill('\0')&&dec&&
if(group==0x0002)
if(element==0x0001)// 2,1
else// 2,*
char vr[3];
vr[0] = dcm[p++];
vr[1] = dcm[p++];
vr[2] = '\0';
short size = *(short*)(dcm+p);
int size = *(int*)(dcm+p);
if(size==-1)
if(group==0x0028&&element==0x0010)
height = *(short*)(dcm+p);
if(group==0x0028&&element==0x0030)
pixelSpacing = atof((char*)dcm+p);
if(group==0x0028&&element==0x0004)
invert = !strncmp((char*)dcm+p, &MONOCHROME1&, 11);
else if(group==0x0028&&element==0x0011)
width = *(short*)(dcm+p);
else if(group==0x0028&&element==0x1050)
windowLevel = atoi((char*)dcm+p);
else if(group==0x0028&&element==0x1051)
windowWidth = atoi((char*)dcm+p);
else if(group==0x7FE0&&element==0x0010)
dib = new unsigned short[dibSize];
memcpy(dib, dcm+p, dibSize);
assert(p==dcmSize);
assert(width!=-1);
assert(height!=-1);
assert(windowLevel!=-1);
assert(windowWidth!=-1);
assert(dib!=NULL);
assert(dibSize==width*height*2);
// 反图做修正
if(invert)
for(int i=0; i&width* i++)
dib[i] ^= 0xFFFF;
windowLevel = 65535-windowL
void dcmReleaseImage(unsigned short* dib)
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:33619次
排名:千里之外
原创:19篇
评论:25条
(1)(1)(1)(1)(2)(1)(2)(1)(2)(5)(1)(1)(1)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'下次自动登录
现在的位置:
& 综合 & 正文
DCMTK 开源库的学习笔记2:直接操作dcm文件中像素数据的尝试
DCMTK官网给出了JPEG格式压缩的DCM文件解压缩的方法(http://support.dcmtk.org/docs/mod_dcmjpeg.html),代码摘录如下:
DJDecoderRegistration::registerCodecs(); // register JPEG codecs
if (fileformat.loadFile("test_jpeg.dcm").good())
DcmDataset *dataset = fileformat.getDataset();
// decompress data set if compressed
dataset-&chooseRepresentation(EXS_LittleEndianExplicit, NULL);
// check if everything went well
if (dataset-&canWriteXfer(EXS_LittleEndianExplicit))
fileformat.saveFile("test_decompressed.dcm", EXS_LittleEndianExplicit);
DJDecoderRegistration::cleanup(); // deregister JPEG codecs
通过尝试,生成的test_decompressed.dcm"的传输语义,transferSyntex发生了改变,且像素数据区中的数据就代表了dcm图像中的真实像素值。利用UltraEdit等二进制编辑软件打开后一目了然:
原本压缩的像素数据区,被解压了出来:30 F8 30 F8 30 F8……,dcm文件中每个像素用16位来表示,采用的小端存储模式,30 F8就是十进制的-2000,即测试图像的填充背景的CT值。
博文(http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data)给出了过去解压后的真实像素数据内存指针的方法,主要是的语句是:
DcmElement* element = NULL;
result = data-&findAndGetElement(DCM_PixelData, element);
if (result.bad() || element == NULL)
short* pixD
result = element-&getUint8Array(pixData);
此时pixData就指向了上图中的30 F8 30 F8 30 F8像素数据区的首地址。至此可以直接对dcm的像素进行操作,如下图是对其进行二值化的结果:
此处有一个问题未能解决:如果在对pixData指向的区域进行操作后,调用保存函数saveFile时未选择EXS_LittleEndianExplicit格式,生成的结果依然是原始图像。
&&&&推荐文章:
【上篇】【下篇】11951人阅读
dicom(3)
和DCMTK显示DICOM医学图像
摘 要 DICOM是医学影像存储和传输的国际标准,它的制定为不同的医学影像设备和用户提供了统一的接口标准和交互协议。解读 DICOM 的医学图像文件格式以及利用 显示方法显示DICOM医学图像。
关键词 DICOM;PACS; DCMTK; 医学图像; 文件格式; 传输语法
The display of DICOM medical Image with VC++ and DCMTK
【Abstract】DICOM is the international standard of medical images archiving and communication. It provides the interface standard and communication protocol for different medical imaging equipments and their users. Analysis on the storage format of DICOM3.0 medical image files and displays them by using displaying methods in
【Keywords】 DICOM;PACS ;DCMTK ;medical Image;file fromat;transfer syntax
DICOM(Digital Imaging and Communications in Medicine)是NEMA(美国制造商协会)和ACR(美国放射学会)联合制定的一种规定数字医学影像和相关信息的格式及其信息交换方法的国际标准,现已几乎成为世界各国都遵循的医学图像标准,是医院间以及国际间医学图像交流的基础。 PACS(Picture Archiving and Communication System)是图像存档和通讯系统,它以数字的方法来存储、管理、传送和显示医学影像和相关信息,具有图像质量高,存储、传输和复制无失真,传送迅速,影像资料可共享等突出的特点。其中,医学图像的显示和处理是直接面向临床医护人员,它显示的图像质量、使用的方便性和系统的处理速度等指标直接关系到系统的应用成败,在PACS中起着重要作用。
DCMTK(DICOM Tool Kit)是一套针对 DICOM 标准,由Kuratorium OFFIS e.V.、Healthcare Information and Communication Systems、Escherweg 等机构联合开发的面向软件设计工程师的开源软件开发包。它用ANSI C 和 C++混合编程,实现了医学图像的传输、存储和打印等功能,实现了DICOM标准的绝大部分功能,完全以源代码的形式呈现。DCMTK 开发包可从网上轻松下载到。目前全球有很多家医院和公司在使用它。它是现在主流的DICOM的开发包,后面我们将以DCMTK为工具来显示 DICOM 图像。
2DICOM医学图像文件格式
DICOM格式图像文件是指按照 DICOM 标准而存储的文件。DICOM文件一般由 DICOM文件头和 DICOM数据集合组成。DICOM数据集合由 DICOM数据元素(Data Element) 按一定顺序排列组成, 而 DICOM数据元素则是 DICOM文件最基本的构成单元(图1 DICOM 文件格式)。
2.1 DICOM 文件头
DICOM 文件头(DICOM File Meta Information)的最开始是文件前言,他由128 B的00H组成,接下来是DICOM前缀,包含了字符串“DICM”,一般用这4字节判别是否是一个DICOM文档。
图1 DICOM 文件格式
2.2 DICOM 数据元素
在DICOM文件中最基本的单元是数据元素,DICOM数据集就是由DICOM数据元素按照一定的顺序排列组成的。
标识符 一个2 B无符号整数对,分别代表组号和元素号,DICOM所有的数据元素都可以用标签来惟一表示。
数据类型(VR) 2 B的字符串,指明了该数据元素中的数据是哪种类型。不同的数据类型决定了数据的不同读取方式。
数据长度 一个2 B或4 B(取决于显示或隐示VR)的无符号整数,指明该数据元素的数据域中数据的长度。
数据域 指明数据的具体数值,该字段的数据类型由数据元素的VR所明确定义。
上面有关数据元素的定义,我们举一个具体的例子来说明:00 28 00 10 55 53 02 00 00 01(十六进制)。其中0x是图像行数的标识符;0x5553是VR数据描述,在DICOM标准中代表字符串“US”;0x0200是数据长度;0x0001就是图像行数的具体值。
3显示DICOM图像
环境的准备
(1)DCMTK开发包的官方网站是 http://www.dcmtk.org,只需要下载两项:DCMTK <st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year=".4 - source code and documentation ()和DCMTK <st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year=".4 - support libraries for Windows
(2)cmake安装(编译)工具的官方网站是http://www.cmake.org,下载cmake2.4并安装。解压dcmtk开发包,用cmake使dcmtk开发包并生成工程文件。用cmake打开dcmtk开发包,需要说明的是几个WITH_*选项就是“DCMTK <st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year=".4 - support libraries for Windows”解压出来的东西。点击两次configure之后就可以点ok生成工程文件了。
(3)用工程,并生成一些静态连接库。这些静态连接库和头文件是用来在VC++下开发需要使用的,将这些文件分别都复制dcmtk_dcmtk_
(4)运行VC ,点击tools 目录的options 命令,然后在directories 环境中作以下设置:
& 在Include files 中加入E:/dcmtk-<st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year=".4/dcmtk_include
& 在Library files 中加入E:/dcmtk-<st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year=".4/dcmtk_lib(假设dcmtk的E:/dcmtk-3.5.4中)
3.2代码实现&&&&&&&&&&&&&&
以上为DCMTK开发包和VC做了准备开发环境之后,就可以进行代码的编写了。下面讲述VC下调用哪些类或函数进行DICOM图像的解析和显示。(将以下代码加入到view类的onDraw函数中)
(1)DICOM文件的读取
&&& &pDicomFile = new DcmFileFormat();
//读DICOM文件
pDicomFile-&loadFile(filename);
//得到数据集
&&& &DcmDataset *pDataset = pDicomFile-&getDataset();
(2)读和图像有关的信息
//得到传输语法
E_TransferSyntax xfer = pDataset-&getOriginalXfer();
//根据传输语法构造DicomImage从fstart帧开始一共fcount帧
DicomImage pDicomImg = new DicomImage (pDataset, xfer, 0, fstart, fcount);
//通过以下的方法得到并用BitmapHeadInformation的结构体来保存DICOM文件的信息
LPBITMAPINFOHEADER m_lpBMIH;
m_lpBMIH = (LPBITMAPINFOHEADER) new char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
&&& m_lpBMIH-&biSize = sizeof(BITMAPINFOHEADER);
&&& m_lpBMIH-&biWidth = pDicomImg-&getWidth();
&&& m_lpBMIH-&biHeight = pDicomImg-&getHeight();
&&& m_lpBMIH-&biPlanes = 1;
&&& m_lpBMIH-&biBitCount = 24;
&&& m_lpBMIH-&biCompression = BI_RGB;
&&& m_lpBMIH-&biSizeImage = 0;
&&& m_lpBMIH-&biXPelsPerMeter = 0;
&&& m_lpBMIH-&biYPelsPerMeter = 0;
(3) 读出的图像数据
void* pDicomD
//得到DICOM文件第frame的DIB数据(假设是24位的)
pDicomImg-&createWindowsDIB(pDicomDibits, 0, frame, 24, 1, 1);
(4) 调用显示API直接进行显示(图2 DICOM图像显示结果)
StretchDIBits(pDC-&GetSafeHdc(),0,0,m_lpBMIH-&diWidth,m_lpBMIH -&diHeight,0,0,m_lpBMIH-&diWidth,m_lpBMIH-&diHeight,pDicomDibits, (LPBITMAPINFO) m_lpBMIH,DIB_RGB_COLORS, SRCCOPY);
图2 DICOM图像显示结果
DICOM 作为医学图像存档和通信的国际标准,是所有医学影像技术的基础,DCMTK已经是比较成熟和功能齐全的开源软件,采用 DCMTK来开发DICOM图像的方法具有使得开发高效和速度快的优点。PACS在医院的应用越来越广泛,如何充分利用海量的医学影像,更好地辅助医学影像诊断和满足医师的科研和使用需求已成为越来越迫切的需求,加强医学图像后处理软件的开发和研究非常必要,这也是我们今后努力的方向。目前不能支持 DICOM 标准中所有传输语法的编解码,导致部分DCM 文件的解读存在困难,尚须改进。在此,只给出简单的DICOM图像文件的显示思路及实例,希望能对从事医学图像的工作者有所启发。
参 考 文 献
[1] The DICOM standard.& http://medical.nema.org/dicom/2007/Wednesday, January 10, 2007
[2] 曹玉磊.DICOM标准研究与图像处理工具的实现[D]. 西安电子科技大学,2007
[3] 高勇.基于DICOM的医学图像系统研究[D]. 西南交通大学,2006
[4] 周长发.精通 Visual C++图像编程[M].电子工业出版社,2004年.
[5] 王立功,刘伟强,于甬华,王广志.DICOM的医学图像文件格式解析与应用研究[J]. 计算机工程与应用. 2006 年第 29期.
[6]林春漪,尹俊勋,马丽红,陈健宇.论解读DICOM医学图像文件及其显示的VC++实施方法[J]. 现代医学仪器与应用,2005年第17卷第 1期.
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42914次
排名:千里之外
原创:14篇
评论:12条
(2)(4)(1)(2)(5)(3)(1)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'2416人阅读
转自 http://bbs.csdn.net/topics/
&636人阅读&&&
医学影像DCM是个类&#20284;PNG的分块&#26684;式,内涵丰富医疗信息,由于应用领域较窄,OpenCV没有提供对其加载支持,一般采用dcmtk库进行加载。
博主本着研究探索的精神写了这段代码,并分享出来,提供了解析DCM的DIB数据、宽高、窗宽窗位、像素间距的功能,支持反色DCM。
将来可以参考spec文档进行扩充,可以在大框架中加入块的处理,从而抽取更多感兴趣的信息,也可以加入压缩DCM的支持。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14581次
排名:千里之外
转载:29篇
(3)(1)(2)(5)(1)(6)(1)(5)(6)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 怎么用matlab读取图像 的文章

 

随机推荐