DICOM 图像显示
医用信息系统 0619010101 周岭静
一、摘要:
DICOM 是医学图像存储和传输的国际标准,DCMTK 是免费开源的针对DICOM 标准
的开发包。解读DICOM 文件格式并解决DICOM 医学图像显示问题是医学图像处理的基
础,对医学影像技术的研究具有重要意义。解读了DICOM 文件格式并介绍了调窗处理的原
理,利用VC++ 和DCMTK 实现医学图像显示和调窗功能。
二、开发工具:
本实验采用C++ 和DCMTK 来实现DICOM 图像文件的读取显示。
三、准备工作
①去DCMTK 官方网站http://www.dcmtk.org/dcmtk.php.en 下载两个压缩包:
DCMTK 3.5.4-source code and documentation(2005-12-20) 和支持库文件DCMTK
3.5.4-support libraries for Windows 并解压缩。
②去Cmake(DCMTK 软件包编译工具)官方网站
http://www.cmake.org/HTML/index.html 下载cmake2.6 并安装。
③用cmake 制作工程文件。
用cmake 打开DCMTK3.5.4,点击两次configure 然后点击ok生成工程文件。在VC++
中打开工程文件dcmtk.dsw,并编译。编译完后再打开项目文件INSTALL.dsp,编译后会生
成一个DCMTK-3.5.4-win32-i386 的目录,其中包括所有可用的lib 和include 头文件。
④将生成的lib 和include 文件复制到VC++安装目录中的VC98 中lib 和include 文件中。
并将下载的支持库文件夹中lib 和include 也存放在VC98 中lib 和include 文件夹中。
⑤C++工作环境设置:
启动Microsoft Visual C++ 6.0,选择“新建—>工程—>MFC工程”,如下图一所示,选
择Single Document,然后Finish 就可以了。
选择Project->Settings 菜单,在弹出的对话框中选择“C/C++”属性页,在“Category”
中选择“Preprocessor”项,在“Additional include directories”下面的编辑框中输入放置MITK
头文件的位置。本实验中设置如下图二所示。
仍然是“Project settings”对话框,选择“Link”属性页,在“Category”中选择“Input”
项,在“Additional library path”下面的编辑框中输入你放置Mitk_dll.lib的位置,本实验中
- 1 -
设置如图三所示。
图一:新建MFC工程
图二:设置头文件路径
- 2 -
图三:设置 MITK 库文件路径
四、读取显示代码实现及其结果
以上为DCMTK 开发包和VC 做了准备工作后,就可以进行代码编写了, 本文调用过
程在CDICOMReadDlg 类中实现。利用开发包提供的DICOMImage 类来实现对DICOM 格
式文件的读取显示。需要调用以下函数: DICOMImage() 和createWindowsDIB()。其中
DICOMImage()用来打开一个DICOM 文件,createWindowsDIB()用来创建DIB 位图,利用
自己定义的Dib 类来调用这个函数把图像显示在显示器上。
①DICOM 文件的打开CfileDialog *FD = newCFileDialog(TRUE,NULL,NULL,
OFN_FILEMUSTEXIST,NULL,this);
DICOMImage *dcm=new DICOMImage(FD->GetPathName());
代码如下:
void CAnDICOMShowView::OnOpenDcmFile() //打开DCM文件
{
RECT rect;
CDC *pDC = GetDC();
CString strName;
CString strDcmFileName;
CFileDialog DcmFileDlg( TRUE, NULL, NULL, OFN_HIDEREADONLY |
OFN_FILEMUSTEXIST, "Dcm Files (*.dcm)|*.dcm|All Files (*.*)|*.*||", NULL );
- 3 -
DcmFileDlg.m_ofn.lpstrTitle = "打开DCM文件";
if( DcmFileDlg.DoModal() == IDOK )
strDcmFileName = DcmFileDlg.GetPathName();
{
}
else
return ;
DcmFileFormat * pDICOMFile = new DcmFileFormat();
pDICOMFile->loadFile( strDcmFileName );
DcmDataset * pDataset = pDICOMFile->getDataset();
E_TransferSyntax xfer = pDataset->getOriginalXfer(); //传输语法
unsigned long ulFStart = 0l, ulFCount = 0l;
DICOMImage * pDICOMImg = new DICOMImage (pDataset, xfer, 0,
ulFStart,ulFCount);
}
②保存和图像有关的信息用LPBITMAPINFOHEADER的结构来保存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;//pDICOMImg->getDepth();
m_lpBMIH->biCompression
= BI_RGB;
m_lpBMIH->biSizeImage
= 0;
m_lpBMIH->biXPelsPerMeter = 0;
m_lpBMIH->biYPelsPerMeter = 0;
void * pDICOMDibits;
- 4 -
this->GetClientRect(&rect);
③创建读出的图像Dib并转化为8位DIB
pDICOMImg->createWindowsDIB( pDICOMDibits, 0, 0, 24, 1, true);
StretchDIBits( pDC->GetSafeHdc(),
(rect.right-rect.left-m_lpBMIH->biWidth)/2,
(rect.bottom-rect.top-m_lpBMIH->biHeight)/2,
m_lpBMIH->biWidth,
m_lpBMIH->biHeight,
0,
0,
m_lpBMIH->biWidth,
m_lpBMIH->biHeight,
pDICOMDibits,
(LPBITMAPINFO) m_lpBMIH,
DIB_RGB_COLORS,
SRCCOPY);
④调用显示API 进行显示
dib.Display(&dc,0,0,600*wandh,600,0,0,dib.GetWidth(),dib.GetHeight());
下图为应用本程序读取显示的颅骨CT 图片。
图四:读取显示的颅骨CT图片
五、窗宽、窗位调节
医学图像分辨率较高,像素灰阶值通常不低于12Bit4096 级,而普通显示器由于动态范
围有限,并受到操作系统限制,只能提供8Bit256 级灰度,由于各种组织有相对稳定的取值,
- 5 -
进行图像分割处理时只对特定范围内的像素值感兴趣,因此,处理系统必须能根据研究者的
需要而显示特定像素值,屏蔽其它范围的像素值。一般而言,该功能通过调节窗宽和窗位实
现,调节窗宽和窗位是医学图像处理中用以观察不同密度的组织结构或病变的一种显示技
术,调窗处理的原理是根据预知的窗宽和窗位值,获得需要显示的窗口的大小(窗宽)和中心
位置(窗位),从而将窗口内的值转换成显示时的最亮和最暗范围内的值,高于窗口灰度范围
的部分置为最亮,低于窗口灰度范围部分设为最暗。调窗处理在数学表达上就是图像灰度值
与显示值的转换,公式如下:
(1)
其中,v 为图像数据,G(v)为显示器的显示值,gm 为显示器的最大显示值,w 为窗宽,
c 为窗位。在调窗处理中,窗宽(Window center)是指需要显示图像的范围,调节窗宽主要
是影响显示对比度,窗宽越大,图像灰度层次多,组织对比度减少,细节显示差。窗位(Window
center)表示显示区域的中心位置。
DCMTK 中的DICOMImage 类提供的setWindow() 函数可以实现对窗宽窗位的调节其
在DICOMImage.h 定义如下:
int setWindow(const double center,const double width) //设定的窗位、窗宽
{
}
return((Image=NULL)&&(Image->getMonoImagePtr()!=NULL));
Image->getMonoImagePtr()->setWindow(center,width);
代码实现:
void CAnDICOMShowView::OnDraw(CDC* pDC)
{
CAnDICOMShowDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
RECT rect;
- 6 -
this->GetClientRect( &rect);
CBrush brush( RGB(0,0,0) ),* pOldBrush;
pOldBrush = pDC->SelectObject( &brush );
pDC->FillRect( &rect,&brush);
pDC->SelectObject( pOldBrush );
brush.DeleteObject();
}
利用鼠标右键滑动调节窗宽窗位,在OnMouse-Move()调用setWindow()实现调节窗宽
窗位:
dcm->setWindow(GetDlgItemInt(IDC_C),GetDlgItemInt(IDC_W));//调窗处理
RefreshDraw() ; // 转换并显示调窗之后的DICOM 文件
下图是经过调窗处理前后的颅骨CT 图片对比:
图五:调窗处理前后的颅骨CT图片对比
六、将DCM图片转换为BMP图片
代码如下:
FILE *pFile;
pFile = fopen("F:\\ZLJ\\AnDICOMShow\\testBmp.bmp","wb");
pDICOMImg->writeBMP(pFile,24,0);
fclose(pFile);
七、在图像中显示病人的信息:
OFString patientsName;
//定义病人的姓名
CString strTemp;
if(pDataset->findAndGetOFString( DCM_PatientsName,patientsName).good())
- 7 -
{
}
strTemp.Format("%s",patientsName);
//读取病人的姓名
pDC->TextOut(20,50,strTemp);
//在坐标为(20,50)的地方显示病人的姓名
strTemp.Format("%d",pDicomImg->getWidth());
//读取图片的宽度
pDC->TextOut(20,70,strTemp);
//在坐标为(20,70)的地方显示图片宽度
strTemp.Format("%d",pDicomImg->getHeight());
//读取图片的高度
pDC->TextOut(20,90,strTemp);
//在坐标为(20,70)的地方显示图片的高度
pDC->SelectObject(pOldPen);
newPen.DeleteObject();
//删除画笔
用上述方法,还能够显示更多病人的信息,在此就不一一列举了。
显示病人的信息如下图所示:
图六:颅骨CT病人的信息(姓名、图片宽度、图片高度)
八、结束语
DICOM 作为医学图像存档和通信的国际标准,是所有医学影像技术的基础,DICOM
文件的读取显示是后续的医学图像处理的基础。DCMTK 为我们提供了实现DICOM 协议的
一个平台,使得我们可以在它的基础上轻松的完成自己的主要工作,而不必把太多的精力放
在实现DICOM 协议的细节问题上,使得医学图像的研究开发高效、速度快。
- 8 -