在Windows系统中使用C++与Orthanc交互:基于DICOMweb的医学影像应用开发

发布于:2025-05-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

在这里插入图片描述

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用,熟悉DICOM医学影像及DICOM协议,业余时间自学JavaScript,Vue,qt,python等,具备多种混合语言开发能力。撰写博客分享知识,致力于帮助编程爱好者共同进步。欢迎关注、交流及合作,提供技术支持与解决方案。
技术合作请加本人wx(注明来自csdn):xt20160813

在Windows系统中使用C++与Orthanc交互:基于DICOMweb的医学影像应用开发

在之前的文章中,我们详细探讨了Orthanc作为轻量级PACS服务器的核心功能、DICOMweb支持以及Python实现的示例代码。为了进一步扩展Orthanc的应用场景,本文将聚焦于在Windows系统中,使用**C++**开发与Orthanc交互的应用程序,重点展示如何通过DICOMweb接口实现医学影像的查询、检索和上传功能。文章将提供完整的C++示例代码,包含关键注释,并介绍Windows环境下的开发配置和注意事项。


一、为何选择C++与Orthanc交互

C++是一种高性能、跨平台的编程语言,广泛应用于医疗影像处理和PACS系统开发。结合Orthanc的DICOMweb接口,使用C++开发具有以下优势:

  • 高性能:C++的低级控制和内存管理适合处理大型DICOM数据集。
  • 跨平台兼容性:C++代码可轻松移植到Linux或其他系统。
  • 与DICOM库集成:C++与DCMTK、GDCM等DICOM库无缝集成,增强影像处理能力。
  • Windows生态支持:Windows是许多医院和开发环境的首选平台,C++在Windows下有成熟的开发工具链。

本文将使用C++通过HTTP请求与Orthanc的DICOMweb接口交互,展示如何实现QIDO-RS(查询)、WADO-RS(检索)和STOW-RS(上传)功能。


二、开发环境准备

1. 安装Orthanc

在Windows系统中,推荐使用Docker或直接下载预编译的Windows二进制包运行Orthanc:

  • Docker方式
    docker pull orthanc/orthanc
    docker run -p 8042:8042 -p 4242:4242 orthanc/orthanc
    
  • Windows二进制包
    从Orthanc官网(https://www.orthanc-server.com/download.php)下载Windows版本,解压后运行Orthanc.exe

默认配置下,Orthanc的REST API和DICOMweb接口运行在http://localhost:8042

2. C++开发工具

  • 编译器:Visual Studio 2022(社区版免费),支持C++17及以上。
  • HTTP客户端库:使用cpp-httplib,一个轻量级的C++ HTTP客户端库,适合与RESTful接口交互。
  • JSON解析库:使用nlohmann/json,便于处理DICOMweb返回的JSON数据。
  • DICOM处理库(可选):如DCMTK或GDCM,用于解析DICOM文件。

3. 安装依赖库

使用vcpkg(Visual Studio的包管理器)安装cpp-httplibnlohmann/json

# 安装vcpkg(如果尚未安装)
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg integrate install

# 安装cpp-httplib和nlohmann/json
.\vcpkg install cpp-httplib
.\vcpkg install nlohmann-json

4. Visual Studio项目配置

  1. 创建一个新的C++空项目。
  2. 在项目属性中:
    • 添加vcpkg的头文件路径:vcpkg\installed\x64-windows\include
    • 添加vcpkg的库路径:vcpkg\installed\x64-windows\lib
    • 链接cpp-httplib.libnlohmann_json.lib(根据需要)。

三、C++实现DICOMweb功能

以下展示如何使用C++与Orthanc的DICOMweb接口交互,实现以下功能:

  1. QIDO-RS:查询DICOM研究。
  2. WADO-RS:检索DICOM元数据。
  3. STOW-RS:上传DICOM文件。

1. 前置代码:HTTP客户端封装

我们创建一个简单的HTTP客户端类,封装cpp-httplib的请求功能,并使用nlohmann/json解析响应。

#include <httplib.h>
#include <nlohmann/json.hpp>
#include <string>
#include <iostream>
#include <fstream>

using json = nlohmann::json;

// HTTP客户端类,封装与Orthanc的交互
class OrthancClient {
private:
    httplib::Client client;
    std::string dicomWebRoot;

public:
    OrthancClient(const std::string& host, int port, const std::string& root = "/dicom-web")
        : client(host, port), dicomWebRoot(root) {
        client.set_connection_timeout(10); // 设置连接超时为10秒
        client.set_read_timeout(30);       // 设置读取超时为30秒
    }

    // 发送GET请求并返回JSON响应
    json get(const std::string& endpoint, const httplib::Params& params = {}) {
        auto res = client.Get((dicomWebRoot + endpoint).c_str(), params);
        if (res && res->status == 200) {
            return json::parse(res->body);
        }
        throw std::runtime_error("GET request failed: " + std::to_string(res ? res->status : -1));
    }

    // 发送POST请求上传DICOM文件
    bool postDicomFile(const std::string& endpoint, const std::string& filePath) {
        std::ifstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            throw std::runtime_error("Cannot open file: " + filePath);
        }

        // 读取文件内容
        std::vector<char> fileData((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        httplib::MultipartFormDataItems items = {
            { "file", std::string(fileData.begin(), fileData.end()), std::filesystem::path(filePath).filename().string(), "application/dicom" }
        };

        auto res = client.Post((dicomWebRoot + endpoint).c_str(), items);
        return res && res->status == 200;
    }
};

代码注释

  • OrthancClient:封装HTTP客户端,初始化时指定Orthanc服务器的地址、端口和DICOMweb根路径。
  • get:发送GET请求,解析并返回JSON响应。
  • postDicomFile:发送POST请求,上传DICOM文件。

2. QIDO-RS:查询DICOM研究

以下代码展示如何查询患者ID为"12345"的DICOM研究。

void queryStudies(OrthancClient& client) {
    try {
        // 设置查询参数
        httplib::Params params = {
            { "PatientID", "12345" },
            { "00100020", "12345" } // 患者ID的DICOM标签
        };

        // 发送QIDO-RS请求
        json studies = client.get("/studies", params);

        // 解析并打印结果
        for (const auto& study : studies) {
            std::string studyUID = study["0020000D"]["Value"][0].get<std::string>();
            std::cout << "Study Instance UID: " << studyUID << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error in QIDO-RS: " << e.what() << std::endl;
    }
}

代码注释

  • params:设置查询条件,支持DICOM标签或标准字段。
  • client.get:发送GET请求到/dicom-web/studies端点。
  • 响应为JSON数组,包含匹配的研究信息。

3. WADO-RS:检索DICOM元数据

以下代码展示如何检索特定研究的元数据。

void retrieveMetadata(OrthancClient& client, const std::string& studyUID) {
    try {
        // 发送WADO-RS请求
        json metadata = client.get("/studies/" + studyUID + "/metadata");

        // 打印元数据(示例:Study Description)
        if (metadata.contains("00081030")) {
            std::string studyDesc = metadata["00081030"]["Value"][0].get<std::string>();
            std::cout << "Study Description: " << studyDesc << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error in WADO-RS: " << e.what() << std::endl;
    }
}

代码注释

  • /studies/{studyUID}/metadata:WADO-RS端点,返回研究的元数据。
  • metadata:JSON对象,包含DICOM标签及其值。

4. STOW-RS:上传DICOM文件

以下代码展示如何上传DICOM文件到Orthanc。

void uploadDicomFile(OrthancClient& client, const std::string& filePath) {
    try {
        // 发送STOW-RS请求
        bool success = client.postDicomFile("/studies", filePath);
        if (success) {
            std::cout << "DICOM file uploaded successfully: " << filePath << std::endl;
        } else {
            std::cerr << "Failed to upload DICOM file" << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error in STOW-RS: " << e.what() << std::endl;
    }
}

代码注释

  • postDicomFile:以multipart/form-data格式上传DICOM文件。
  • 成功上传后,Orthanc会解析并存储DICOM文件。

5. 主程序

以下是完整的程序入口,整合上述功能。

int main() {
    try {
        // 初始化Orthanc客户端
        OrthancClient client("localhost", 8042);

        // 查询研究
        std::cout << "Querying studies..." << std::endl;
        queryStudies(client);

        // 检索元数据
        std::string studyUID = "1.2.840.113619.2.55.3.60467153.1234.1234567890";
        std::cout << "\nRetrieving metadata for study: " << studyUID << std::endl;
        retrieveMetadata(client, studyUID);

        // 上传DICOM文件
        std::string dicomFile = "path/to/sample.dcm";
        std::cout << "\nUploading DICOM file: " << dicomFile << std::endl;
        uploadDicomFile(client, dicomFile);

    } catch (const std::exception& e) {
        std::cerr << "Main error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

代码注释

  • 主程序初始化OrthancClient,依次调用查询、检索和上传功能。
  • 异常处理确保程序健壮性。

四、Windows系统下的注意事项

  1. 防火墙配置

    • 确保Orthanc的端口(默认8042和4242)未被Windows防火墙阻止。
    • 在Windows PowerShell中运行以下命令开放端口:
      netsh advfirewall firewall add rule name="Orthanc" dir=in action=allow protocol=TCP localport=8042,4242
      
  2. 文件路径

    • Windows使用反斜杠(\)作为路径分隔符,但在C++字符串中需转义为\\,或使用原始字符串(如R"(path\to\file)")。
    • 示例:"C:\\Users\\Username\\sample.dcm"
  3. 依赖库的DLL

    • 确保cpp-httplibnlohmann/json的动态链接库(.dll)在可执行文件的目录下,或已添加到系统PATH。
    • vcpkg会自动将DLL放置在vcpkg\installed\x64-windows\bin
  4. 字符编码

    • Orthanc的DICOMweb接口使用UTF-8编码,确保C++程序的字符串处理兼容UTF-8。
    • 在Visual Studio中,设置项目属性为“使用Unicode字符集”。
  5. 性能优化

    • 对于大规模DICOM文件上传,建议使用异步I/O或多线程以提高性能。
    • 调整cpp-httplib的超时参数,适应网络环境。

五、扩展:与DCMTK集成

若需解析或生成DICOM文件,可集成DCMTK库。以下是使用DCMTK读取DICOM文件并上传到Orthanc的示例:

1. 安装DCMTK

通过vcpkg安装DCMTK:

.\vcpkg install dcmtk

2. 示例代码:读取DICOM文件并上传

#include <dcmtk/dcmdata/dctk.h>

void uploadDicomWithDCMTK(OrthancClient& client, const std::string& filePath) {
    try {
        // 使用DCMTK加载DICOM文件
        DcmFileFormat fileFormat;
        OFCondition status = fileFormat.loadFile(filePath.c_str());
        if (status.bad()) {
            throw std::runtime_error("Failed to load DICOM file: " + status.text());
        }

        // 验证DICOM文件有效性
        DcmDataset* dataset = fileFormat.getDataset();
        if (!dataset) {
            throw std::runtime_error("Invalid DICOM file");
        }

        // 上传文件
        client.postDicomFile("/studies", filePath);
        std::cout << "DICOM file validated and uploaded: " << filePath << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error in DCMTK upload: " << e.what() << std::endl;
    }
}

代码注释

  • DcmFileFormat:加载DICOM文件并验证其格式。
  • 在上传前,DCMTK可用于提取元数据或进行预处理(如匿名化)。

六、实际应用场景

  1. 医院影像工作站

    • 开发Windows桌面应用,通过DICOMweb从Orthanc检索影像并显示。
    • 使用C++结合OpenGL或VTK实现影像渲染。
  2. 自动化影像处理

    • 开发批量上传DICOM文件的工具,结合DCMTK进行元数据验证。
    • 实现影像匿名化后上传到Orthanc。
  3. 远程诊断系统

    • 开发C++服务端程序,通过DICOMweb实时查询和传输影像到远程客户端。

七、总结

通过C++在Windows系统中与Orthanc的DICOMweb接口交互,开发者可以构建高性能、可靠的医学影像应用。本文提供的示例代码展示了查询、检索和上传DICOM文件的核心功能,并通过DCMTK扩展了DICOM文件处理能力。结合Windows的开发工具链和Orthanc的轻量级特性,C++开发者能够快速实现从桌面应用到服务器端服务的多种场景。

对于更复杂的应用,建议进一步探索Orthanc的插件系统或与其他影像处理库(如ITK、VTK)集成。

参考资源

  • Orthanc官方文档:https://book.orthanc-server.com/
  • cpp-httplib GitHub:https://github.com/yhirose/cpp-httplib
  • nlohmann/json GitHub:https://github.com/nlohmann/json
  • DCMTK官方文档:https://dicom.offis.de/

网站公告

今日签到

点亮在社区的每一天
去签到