65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 DCMTK 和 CxImage 将 DICOM 图像转换为通用图形格式(反之亦然)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (19投票s)

2005 年 11 月 10 日

CPOL

3分钟阅读

viewsIcon

355881

downloadIcon

12360

将 DICOM 文件转换为 BMP/JPG 及反之

引言

本文介绍了一个最小的可运行的示例应用程序,作为一个起点,展示如何将 DICOM 图像转换为常见的图形格式(例如 BMP、JPG、TIF 等)以及反之。我们的示例应用程序基于两个开源库,它们是 DCMTK 和 CxImage

背景

DICOM 标准(医学数字成像和通信)是由美国电气制造商协会 (NEMA) 创建的标准,旨在简化医疗图像(如 CT 扫描、MRI 和超声)的分发和交换。在本文中,我们将重点关注文件格式转换。文件格式在 DICOM 标准的第 10 部分中进行了描述,您可以从这里下载[^]。这里还有一个对文件格式的简短介绍可用

DCMTK 是一个广泛使用的 DICOM 标准开源实现;它是一组 C/C++ 库和应用程序,带有完整的源代码。要编译本文中的示例,您需要先下载 DCMTK。如果您在构建下载的 DCMTK 包时遇到问题,请参考DCMTK for Dummies

本文中使用的另一个库是 CxImage,它是一个 C++ 类,可以以一种非常简单快速的方式加载、保存、显示和转换图像。它支持几乎所有常见的图形类型,例如 BMP、JPG、TIF、PNG 等。在本文中,我们将扩展这个库,通过使用 DCMTK 提供的 DICOM 格式编码/解码功能来支持显示和转换 DICOM 图像。下载 CxImage并按照其使用指南确保它可以在您的机器上成功编译。

Using the Code

我们简单地从基类 CxImage 派生我们的 CxImageDCM 类。这样做使 CxImageDCM 类能够使用从基类继承的方法加载和解码通用图形。派生类中有三个额外的方法,LoadDCM(…)SaveAsDCM(…)SaveAsJPG(…),它们分别用于解码、编码和转换 DICOM 图像。

//
class CxImageDCM : public CxImage  
{
public:
    CxImageDCM();
    virtual ~CxImageDCM();
    
    bool LoadDCM(const TCHAR* filename);
    bool SaveAsDCM(const TCHAR* filename);
    bool SaveAsJPG(const TCHAR* fileName);

};//

加载 DCM

在示例应用程序中,使用 DCMTK 提供的类加载和解码 DICOM 图像,然后将其转换为临时位图文件以供以后操作

//
bool CxImageDCM::LoadDCM(const TCHAR* filename)
{  
    DcmFileFormat *dfile = new DcmFileFormat();
    OFCondition cond = dfile->loadFile(filename, EXS_Unknown,
                      EGL_withoutGL,DCM_MaxReadLength,OFFalse);
    
    if (cond.bad()) {
        AfxMessageBox(cond.text());
    }
    
    E_TransferSyntax xfer = 
            dfile->getDataset()->getOriginalXfer();
    DicomImage *di = new DicomImage(dfile, xfer, 
                         CIF_AcrNemaCompatibility, 0, 1);
    
    if (di->getStatus() != EIS_Normal)
        AfxMessageBox(DicomImage::getString(di->getStatus()));
    
    di->writeBMP("c:\\from_dicom.bmp",24);
    
    return CxImage::Load("c:\\from_dicom.bmp",CXIMAGE_FORMAT_BMP);
    
}//

从 DCM 转换

在加载 DCM 文件后,您可以使用 CxImage 提供的编码功能将其保存为通用图形文件,或者您也可以使用 DCMTK 的编码插件进行转换(但是,CxImage 支持更多格式)

//
bool CxImageDCM::SaveAsJPG(const TCHAR* fileName)
{//you may also use DCMTK's JPG encoding plug-in
    return CxImage::Save(fileName,CXIMAGE_FORMAT_JPG);

}//

转换为 DCM

要将通用图形文件转换为 DCM 文件,您需要先加载通用图形,然后设置必要的标签并将像素数据复制到目标 DCM 文件

//
bool CxImageDCM::SaveAsDCM(const TCHAR* filename)
{
    CxImageDCM::IncreaseBpp(24);
    char uid[100]; 
    DcmFileFormat fileformat; 
    DcmDataset *dataset = fileformat.getDataset(); 
    dataset->putAndInsertString(DCM_SOPClassUID, 
               UID_SecondaryCaptureImageStorage); 
    /* ... */
    //dataset->putAndInsertUint32(DCM_MetaElementGroupLength,128);
    dataset->putAndInsertUint16(DCM_FileMetaInformationVersion,
                                                          0x0001);
    /* ... */    
    dataset->putAndInsertString(DCM_UID,
        UID_MultiframeTrueColorSecondaryCaptureImageStorage);
    dataset->putAndInsertString(DCM_PhotometricInterpretation,
                                                        "RGB"); 
    //add more tags here
    /* ... */ 
    BYTE* pData=new BYTE[GetHeight()*info.dwEffWidth];
    BYTE* pSrc=GetBits(head.biHeight-1);
    BYTE* pDst=pData;
    for(long y=0; y < head.biHeight; y++){
        memcpy(pDst,pSrc,info.dwEffWidth);
        pSrc-=info.dwEffWidth;
        pDst+=info.dwEffWidth;
    }
    dataset->putAndInsertUint8Array(DCM_PixelData, 
                 pData, GetHeight()*info.dwEffWidth); 
    delete[] pData;
    
    OFCondition status = fileformat.saveFile(filename, 
                           EXS_LittleEndianImplicit,
                           EET_UndefinedLength,EGL_withoutGL); 
    if (status.bad()) 
        AfxMessageBox("Error: cannot write DICOM file ");
    
    return true;     
}//

关注点

在本文中,使用 CxImage 提供的编码功能将 DICOM 图像转换为 JPG 文件(或 CxImage 支持的其他格式)。实际上,DCMTK 已经有一个名为 dcmj2pnm 的成熟实用程序,用于将 DICOM 图像转换为 BMP、PNG、TIF 或 JPG 图像。对于 dcmj2pnm 不支持的其他格式,例如 GIF、TGA、PCX、WBMP 等,您可以使用 CxImage 的编码功能来编写自己的转换函数。这里需要澄清的一件事是,我们的示例应用程序只是一个提供入门点的玩具实用程序。要编写一个像样的 DICOM 图像转换器,您需要考虑更多与 DICOM 相关的选项。有关更多信息,您可以参考 dcmj2pnm 的实现。(它包含在 DCMTK 源代码包中。)

根据我的经验,CxImage 易于使用;它“可以以简单快速的方式加载、保存、显示和转换图像”。但是,当您必须从基类 CxImage 派生一个新的图像编码器/解码器时,我发现它很烦人。基类必须知道所有派生类才能提供多态行为。幸运的是,在我们的示例中,派生类 CxImageDCM 只需要它从基类继承的编码/解码函数,所以我懒得去动 CxImage 的源代码。

参考文献

© . All rights reserved.