zoukankan      html  css  js  c++  java
  • DCMTK3.6.1(MD支持库)安装说明

    【前言】

    最近,因为需要开发DICOM网管模块,必须使用DCMTK的DcmNet模块。但是DCMTK3.6.0在DcmNet模块中只提供两个实验阶段的网络类DcmSCU和DcmSCP。而且他们并没有完全实现DICOM的C-Echo、C-Find、C-Get、C-Move和C-store操作。只实现了C-Echo和C-Find操作。

     

    调研了一番,发现DCMTK小组在最新的snapshot版本中(DCMTK3.6.1 2012-08-31),已经实现了DICOM全部操作。而且他们官方论坛中,开发人员在回答疑问时候,针对3.6.0中出现的bug等问题。他们也是鼓励大家直接用最新的DCMTK3.6.1.

    当然他们也建议大家自己去通过底层代码实现DcmScu的其他的操作。不过对于我们这种新手来讲确实很困难,而且关键问题在后期的3.6.1版本的代码变化很大。我们自己手写的,以后不方便兼容。

     

    所以最终我还是下载了最新的DCMTK3.6.1-20120831,但是他有一个问题,目前只支持在linux上编译和运行。windows环境,他们并没有提供支持库。于是又让我踌躇了一番,自己也手动试着基于3.6.0写了点代码,但是真的是超级难。最终下定决心在win7上编译3.6.1,并利用DCMTK3.6.0的support(MD)Library。在DCMTK官方论坛开发人员的帮助下,最终编译成功。也实现DcmScu的例子网络访问。

    【开发环境】

    操作系统:win7 32bit

    开发工具:VS2008 + Qt4.7.4

    1、DCMTK: DCMTK3.6.120120831

    2、DCMTK support libraries for windows: dcmtk-3.6.0-win32-i386-support_MD.zip

    3、CMake:cmake-2.8.9-win32-x86.exe

     

    目前我的Qt项目都是基于MD/MDd的运行时库。

     

    【安装过程】

    1、将支持库中的相应lib文件,include文件,bin文件拷贝到VS2008安装目录的相应文件夹下。

    A.在解压得到的支持库的文件夹下搜索_d.lib文件(xxx_d.lib为DEBUG版本的支持库,xxx_o.lib为RELEASE版本支持库),应该会得到7个结果,将这些文件复制到一个单独的文件夹下,并把它们的名字中的_d去掉,例如将zlib_d.lib重命名为zlib.lib。将重命名后的文件拷贝至VS2008安装目录下的lib文件夹下,在我的win7 32bit电脑上是C:Program FilesMicrosoft Visual Studio 9.0VClib
     
    B.在解压得到的支持库的文件夹下搜索include,应该得到5个文件夹,将这些文件夹复制到C:Program FilesMicrosoft Visual Studio 9.0VC下,选择合并文件夹,也就是将include文件夹下的内容全部复制到C:Program FilesMicrosoft Visual Studio 9.0VCinclude目录下。
     
    C.将D:DCMTKdcmtk-3.6.0-win32-i386-support_MDopenssl-1.0.0cin下的五个文件复制到C:Program FilesMicrosoft Visual Studio 9.0VCin下。

    2、CMake编译

    A、设置source code 路径: D:DCMTKdcmtk-3.6.1_20120831

    B、设置binaries路径: D:DCMTKDCMTK-bin

    C、选择Configure:visual studio 9 2008

    D、等待configure完毕后,会有很多find和not find,无所谓。

    E、选中Advanced单选框,然后在红色区域设置:

    set DCMTK_OVERWRITE_WIN32_COMPILER_FLAG = OFF;(不选中,这样可以使生成项目运行时库都是MD/MDd,而不是默认的MT/MTd)

    set "DCMTK_WITH_ICONV" to "ON" (选中)

    set "DCMTK_WITH_OPENSSL" to "ON"(选中)

    set "DCMTK_WITH_PNG" to "ON" (选中)

    set "DCMTK_WITH_TIFF" to "ON" (选中)

    set "DCMTK_WITH_XML" to "ON" (选中)

    set "DCMTK_WITH_ZLIB" to "ON" (选中)

    F、点击Generate,很快就完成。这时候VS项目源码已经生成。

    3、VS2008编译项目源码


    A、用VS打开 D:DCMTKDCMTK-binDCMTK.sln

    B、点击Build->Batch Build,选择ALL_BUILD项目的debug版,点击右边的Build。耐心等待。会有很多个warning,应该是由字符编码不统一引起的。最后会看到82个编译 成功,0个失败。

    C、再选择Build->Batch Build,这次选择INSTALL项目的debug版本,点击右边的Build。最后会显示1个工程编译成功,这时在你选择的安装目录下(默认是C:Program FilesDCMTK)就会有lib,bin,include,etc,share文件夹,里面就是之后写程序做医学图像处理所需要的库文件了

    4、代码测试

    A. 新建一个Qt application,把以上源代码复制粘贴进main.cpp去。 B. 右键单击工程名,选择属性(properties),在Configuration Properties->C/C++->General下,
    Additional Include Directories里加入上一步编译出来的include文件夹,我的Win7 32bit电脑上是
    C:Program FilesDCMTKinclude,这一步是为了让程序能够找到头文件。
    C. C/C++->code generation里,Runtime Library 选择/MDd,这一步是要和之前CMAKE的编译选项一致。
    (我的Qt项目默认就是/MDd) D. Linker->General里,Additional Library Directories里填写上一步编译出来的lib文件夹,我的Win7 32bit
    电脑上是C:Program FilesDCMTKlib,这一步是为了让程序能够找到之前编译好的lib文件。
    E. Linker->Input里,在Additional Dependencies 里依次加上
    wsock32.lib netapi32.lib ofstd.lib oflog.lib dcmdata.lib dcmnet.lib zlib.lib
    这一步是加入具体我们程序需要的lib文件。

    F. Debug,ok,编译工程,运行成功。访问了www.dicomserver.co.uk的DICOM服务器。

    源代码如下:

    The code uses the public DICOM server at www.dicomserver.co.uk which is offered by Dave Harvey (MedicalObjects). :-) There are also logs you can check at the server in order to debug your application.

     

    /* 
     * 
     *  Copyright (C) 2011-2012, OFFIS e.V. 
     *  All rights reserved.  See COPYRIGHT file for details. 
     * 
     *  This software and supporting documentation were developed by 
     * 
     *    OFFIS e.V. 
     *    R&D Division Health 
     *    Escherweg 2 
     *    D-26121 Oldenburg, Germany 
     * 
     * 
     *  Module:  dcmnet 
     * 
     *  Author:  Michael Onken 
     * 
     *  Purpose: Test for move feature of the DcmSCU class 
     */ 
     
    #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */ 
    #include "dcmtk/dcmnet/testscu.h" 
    #include "dcmtk/dcmnet/diutil.h" 
     
    #define OFFIS_CONSOLE_APPLICATION "testscu" 
     
    static OFLogger echoscuLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION); 
     
    static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v" 
      OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $"; 
     
    // our application entity title used for calling the peer machine 
    #define APPLICATIONTITLE     "TEST-SCU" 
     
    // host name of the peer machine 
    #define PEERHOSTNAME         "www.dicomserver.co.uk" 
     
    // TCP/IP port to connect to the peer machine 
    #define PEERPORT 11112 
     
    // application entity title of the peer machine 
    #define PEERAPPLICATIONTITLE "MOVESCP" 
     
    // MOVE destination AE Title 
    #define MOVEAPPLICATIONTITLE "TEST-SCU" 
     
    static Uint8 findUncompressedPC(const OFString& sopClass, 
                                    DcmSCU& scu) 
    { 
      Uint8 pc; 
      pc = scu.findPresentationContextID(sopClass, UID_LittleEndianExplicitTransferSyntax); 
      if (pc == 0) 
        pc = scu.findPresentationContextID(sopClass, UID_BigEndianExplicitTransferSyntax); 
      if (pc == 0) 
        pc = scu.findPresentationContextID(sopClass, UID_LittleEndianImplicitTransferSyntax); 
      return pc; 
    } 
     
    // ******************************************** 
     
    int main(int argc, char *argv[]) 
    { 
      /* Setup DICOM connection parameters */ 
      OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); 
      DcmTestSCU scu; 
      // set AE titles 
      scu.setAETitle(APPLICATIONTITLE); 
      scu.setPeerHostName(PEERHOSTNAME); 
      scu.setPeerPort(PEERPORT); 
      scu.setPeerAETitle(PEERAPPLICATIONTITLE); 
      // Use presentation context for FIND/MOVE in study root, propose all uncompressed transfer syntaxes 
      OFList<OFString> ts; 
      ts.push_back(UID_LittleEndianExplicitTransferSyntax); 
      ts.push_back(UID_BigEndianExplicitTransferSyntax); 
      ts.push_back(UID_LittleEndianImplicitTransferSyntax); 
      scu.addPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel, ts); 
      scu.addPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel, ts); 
      scu.addPresentationContext(UID_VerificationSOPClass, ts); 
     
      /* Initialize network */ 
      OFCondition result = scu.initNetwork(); 
      if (result.bad()) 
      { 
        DCMNET_ERROR("Unable to set up the network: " << result.text()); 
        return 1; 
      } 
     
      /* Negotiate Association */ 
      result = scu.negotiateAssociation(); 
      if (result.bad()) 
      { 
        DCMNET_ERROR("Unable to negotiate association: " << result.text()); 
        return 1; 
      } 
     
      /* Let's look whether the server is listening: 
         Assemble and send C-ECHO request 
       */ 
      result = scu.sendECHORequest(0); 
      if (result.bad()) 
      { 
        DCMNET_ERROR("Could not process C-ECHO with the server: " << result.text()); 
        return 1; 
      } 
     
      /* Assemble and send C-FIND request */ 
      OFList<QRResponse*> findResponses; 
      DcmDataset req; 
      req.putAndInsertOFStringArray(DCM_QueryRetrieveLevel, "STUDY"); 
      req.putAndInsertOFStringArray(DCM_StudyInstanceUID, ""); 
      T_ASC_PresentationContextID presID = findUncompressedPC(UID_FINDStudyRootQueryRetrieveInformationModel, scu);
      if (presID == 0) 
      { 
        DCMNET_ERROR("There is no uncompressed presentation context for Study Root FIND"); 
        return 1; 
      } 
      result = scu.sendFINDRequest(presID, &req, &findResponses); 
      if (result.bad()) 
        return 1; 
      else 
        DCMNET_INFO("There are " << findResponses.size() << " studies available"); 
     
      /* Assemble and send C-MOVE request, for each study identified above*/ 
      presID = findUncompressedPC(UID_MOVEStudyRootQueryRetrieveInformationModel, scu); 
      if (presID == 0) 
      { 
        DCMNET_ERROR("There is no uncompressed presentation context for Study Root MOVE"); 
        return 1; 
      } 
      OFListIterator(QRResponse*) study = findResponses.begin(); 
      Uint32 studyCount = 1; 
      OFBool failed = OFFalse; 
      // Every while loop run will get all image for a specific study 
      while (study != findResponses.end() && result.good())
      { 
        // be sure we are not in the last response which does not have a dataset 
        if ( (*study)->m_dataset != NULL) 
        { 
          OFString studyInstanceUID; 
          result = (*study)->m_dataset->findAndGetOFStringArray(DCM_StudyInstanceUID, studyInstanceUID); 
          // only try to get study if we actually have study instance uid, otherwise skip it 
          if (result.good()) 
          { 
            req.putAndInsertOFStringArray(DCM_StudyInstanceUID, studyInstanceUID); 
            // fetches all images of this particular study 
            result = scu.sendMOVERequest(presID, MOVEAPPLICATIONTITLE, &req, NULL /* we are not interested into responses*/); 
            if (result.good()) 
            { 
              DCMNET_INFO("Received study #" << std::setw(7) << studyCount << ": " << studyInstanceUID); 
              studyCount++; 
            } 
          }
        } 
        study++;
      } 
      if (result.bad()) 
      { 
        DCMNET_ERROR("Unable to retrieve all studies: " << result.text()); 
      }
      while (!findResponses.empty())
      {
        delete findResponses.front();
        findResponses.pop_front();
      }
      /* Release association */ 
      scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
      return 0; 
    }

    P.S: The header file would be trivial:

     

    #ifndef TESTSCU_H 
    #define TESTSCU_H 
     
    #include "dcmtk/config/osconfig.h"  /* make sure OS specific configuration is included first */ 
     
    #include "dcmtk/dcmnet/scu.h"     /* Covers most common dcmdata classes */ 
     
     
    class DcmTestSCU : public DcmSCU 
    { 
     
    public: 
     
      DcmTestSCU()  {} 
      ~DcmTestSCU() {} 
     
    }; 
     
    #endif // TESTSCU_H

    参考文章:

    1、DcmSCU example program

    2、DCMTK3.6.0(MD支持库)安装说明

    3、how to use DCMTK 3.6.1 on win7

    ------------------------------------

    柳北风儿

    http://qimo601.iteye.com

    ------------------------------------

    DCMTK3.6.1编译失败总结

    针对DCMTK3.6.1 编译的错误总结:

    1、完全默认CMake配置, DCMTK编译成功。但无支持库externallibraries (OpenSSL, zlib, libtiff, libpng, libxml2 and libiconv)

    结果:如果不加支持库,运行网上例子,肯定出错。1>Linking...1> LINK : fatal error LNK1181: cannot open input file 'zlib.lib'

    2、设置了MD支持库,在VC里配置好文件,手动修改CMakeList.txt为MD/MDd。会出现如下错误:warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs; use等运行时库冲突错误。

    3、按照DCMTK官方编译方法失败。官方配置CMake属性,加上3.6.0MD支持库,

    libpng support:
    set "DCMTK_WITH_PNG" to "ON" and
    set "WITH_LIBPNGINC" e.g. to "C:libpng-1.4.2"

    libtiff support:
    set "DCMTK_WITH_TIFF" to "ON" and
    set "WITH_LIBTIFFINC" e.g. to "C: iff-3.9.2"

    OpenSSL support:
    set "DCMTK_WITH_OPENSSL" to "ON" and
    set "WITH_OPENSSLINC" e.g. to "C:openssl-1.0.0"

    zlib support:
    set "DCMTK_WITH_ZLIB" to "ON" and
    set "WITH_ZLIBINC" e.g. to "C:zlib-1.2.5"

    libiconv support:
    set "DCMTK_WITH_ICONV" to "ON" and
    set "WITH_LIBICONVINC" e.g. to "C:libiconv-1.14"
    以及设置DCMTK_OVERWRITE_WIN32_COMPILER_FLAG = OFF;

    缺少libiconv的编译后的支持库。

    最后还是按照如上方法,完全实现DCMTK3.6.1在win7上的编译。

  • 相关阅读:
    Java I/O(二 使用)
    Java 基本I/O的学习总结(一 是什么)
    设计模式(一)
    浏览器输入一个网址(发生的过程)
    final关键字的4种用法
    JavaScript(4)——闭包与this对象以及window对象
    JavaScript(3)—— 正则表达式
    JavaScript(2)——对象属性、原型与原型链
    JavaScript(1)——变量、函数声明及作用域
    构建分布式配置中心阿波罗(Apollo)
  • 原文地址:https://www.cnblogs.com/h2zZhou/p/4979707.html
Copyright © 2011-2022 走看看