🧑 博主简介: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-httplib
和nlohmann/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项目配置
- 创建一个新的C++空项目。
- 在项目属性中:
- 添加vcpkg的头文件路径:
vcpkg\installed\x64-windows\include
。 - 添加vcpkg的库路径:
vcpkg\installed\x64-windows\lib
。 - 链接
cpp-httplib.lib
和nlohmann_json.lib
(根据需要)。
- 添加vcpkg的头文件路径:
三、C++实现DICOMweb功能
以下展示如何使用C++与Orthanc的DICOMweb接口交互,实现以下功能:
- QIDO-RS:查询DICOM研究。
- WADO-RS:检索DICOM元数据。
- 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系统下的注意事项
防火墙配置:
- 确保Orthanc的端口(默认8042和4242)未被Windows防火墙阻止。
- 在Windows PowerShell中运行以下命令开放端口:
netsh advfirewall firewall add rule name="Orthanc" dir=in action=allow protocol=TCP localport=8042,4242
文件路径:
- Windows使用反斜杠(\)作为路径分隔符,但在C++字符串中需转义为
\\
,或使用原始字符串(如R"(path\to\file)"
)。 - 示例:
"C:\\Users\\Username\\sample.dcm"
。
- Windows使用反斜杠(\)作为路径分隔符,但在C++字符串中需转义为
依赖库的DLL:
- 确保
cpp-httplib
和nlohmann/json
的动态链接库(.dll)在可执行文件的目录下,或已添加到系统PATH。 - vcpkg会自动将DLL放置在
vcpkg\installed\x64-windows\bin
。
- 确保
字符编码:
- Orthanc的DICOMweb接口使用UTF-8编码,确保C++程序的字符串处理兼容UTF-8。
- 在Visual Studio中,设置项目属性为“使用Unicode字符集”。
性能优化:
- 对于大规模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可用于提取元数据或进行预处理(如匿名化)。
六、实际应用场景
医院影像工作站:
- 开发Windows桌面应用,通过DICOMweb从Orthanc检索影像并显示。
- 使用C++结合OpenGL或VTK实现影像渲染。
自动化影像处理:
- 开发批量上传DICOM文件的工具,结合DCMTK进行元数据验证。
- 实现影像匿名化后上传到Orthanc。
远程诊断系统:
- 开发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/