你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 C# 和 DICOMweb 标准 API

本文介绍如何通过使用 C# 和示例 .dcm DICOM® 文件来使用 DICOMweb 服务。

使用以下示例文件:

  • blue-circle.dcm
  • dicom-metadata.csv
  • green-square.dcm
  • red-triangle.dcm

示例 DICOM 文件的文件名、studyUID、seriesUID 和 instanceUID 为:

文件 StudyUID SeriesUID InstanceUID
green-square.dcm 1.2.826.0.1.3680043.8.498.13230779778012324449356534479549187420 1.2.826.0.1.3680043.8.498.45787841905473114233124723359129632652 1.2.826.0.1.3680043.8.498.12714725698140337137334606354172323212
red-triangle.dcm 1.2.826.0.1.3680043.8.498.13230779778012324449356534479549187420 1.2.826.0.1.3680043.8.498.45787841905473114233124723359129632652 1.2.826.0.1.3680043.8.498.47359123102728459884412887463296905395
blue-circle.dcm 1.2.826.0.1.3680043.8.498.13230779778012324449356534479549187420 1.2.826.0.1.3680043.8.498.77033797676425927098669402985243398207 1.2.826.0.1.3680043.8.498.13273713909719068980354078852867170114

注意

这些文件中的每一个都代表一个实例,并且是同一研究的一部分。 此外,绿色正方形和红色三角形属于同一系列,而蓝色圆形属于单独的系列。

先决条件

若要使用 DICOMweb 标准 API,需要部署 DICOM 服务实例。 有关详细信息,请参阅使用 Azure 门户部署 DICOM 服务

部署 DICOM 服务实例后,检索应用服务的 URL:

  1. 登录 Azure 门户
  2. 搜索“最近的资源”并选择你的 DICOM 服务实例
  3. 复制 DICOM 服务的服务 URL。 在发出请求时,请确保将版本指定为 URL 的一部分。 有关详细信息,请参阅 DICOM 服务的 API 版本控制

在应用程序中,安装 NuGet 包:

创建 DicomWebClient

部署 DICOM 服务后,创建 DicomWebClient。 运行代码片段以创建 DicomWebClient,在本教程的其余部分中会用到它。 确保已安装两个 NuGet 包。 有关详细信息,请参阅使用 Azure CLI 获取用于 DICOM 服务的访问令牌

string webServerUrl ="{Your DicomWeb Server URL}"
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(webServerUrl);
IDicomWebClient client = new DicomWebClient(httpClient);
client.HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", “{Your token value}”); 

使用 DicomWebClient,我们现在可以执行存储、检索、搜索和删除操作。

存储 DICOM 实例 (STOW)

通过使用 DicomWebClient,我们现在可以存储 DICOM 文件。

存储单个实例

“存储单个实例”演示如何上传单个 DICOM 文件。

详细信息

  • POST /studies
DicomFile dicomFile = await DicomFile.OpenAsync(@"{Path To blue-circle.dcm}");
DicomWebResponse response = await client.StoreAsync(new[] { dicomFile });

存储特定研究的实例

“存储特定研究的实例”演示如何将 DICOM 文件上传到指定的研究。

详细信息

  • POST /studies/{study}
DicomFile dicomFile = await DicomFile.OpenAsync(@"{Path To red-triangle.dcm}");
DicomWebResponse response = await client.StoreAsync(new[] { dicomFile }, "1.2.826.0.1.3680043.8.498.13230779778012324449356534479549187420");

在继续学习本教程的下一部分之前,请使用上述任一方法上传 green-square.dcm 文件。

检索 DICOM 实例 (WADO)

代码片段演示如何使用之前创建的 DicomWebClient 执行每个检索查询。

其余示例中会使用这些变量。

string studyInstanceUid = "1.2.826.0.1.3680043.8.498.13230779778012324449356534479549187420"; //StudyInstanceUID for all 3 examples
string seriesInstanceUid = "1.2.826.0.1.3680043.8.498.45787841905473114233124723359129632652"; //SeriesInstanceUID for green-square and red-triangle
string sopInstanceUid = "1.2.826.0.1.3680043.8.498.47359123102728459884412887463296905395"; //SOPInstanceUID for red-triangle

检索研究中的所有实例

详细信息

  • GET /studies/{study}
DicomWebResponse response = await client.RetrieveStudyAsync(studyInstanceUid);

之前上传的全部三个 dcm 文件都是同一研究的一部分,因此响应应返回全部三个实例。 验证响应的状态代码是否为 OK,以及是否返回了全部三个实例。

使用检索的实例

以下代码片段演示如何访问检索的实例。 它还演示了如何访问实例的某些字段,以及如何将其另存为 dcm 文件。

DicomWebAsyncEnumerableResponse<DicomFile> response = await client.RetrieveStudyAsync(studyInstanceUid);
await foreach (DicomFile file in response)
{
    string patientName = file.Dataset.GetString(DicomTag.PatientName);
    string studyId = file.Dataset.GetString(DicomTag.StudyID);
    string seriesNumber = file.Dataset.GetString(DicomTag.SeriesNumber);
    string instanceNumber = file.Dataset.GetString(DicomTag.InstanceNumber);

    file.Save($"<path_to_save>\\{patientName}{studyId}{seriesNumber}{instanceNumber}.dcm");
}

检索研究中所有实例的元数据

此响应检索单个研究中所有实例的元数据。

详细信息

  • GET /studies/{study}/metadata
DicomWebResponse response = await client.RetrieveStudyMetadataAsync(studyInstanceUid);

之前上传的全部三个 dcm 文件都是同一研究的一部分,因此响应应返回全部三个实例的元数据。 验证响应的状态代码是否为 OK,以及是否返回了所有元数据。

检索系列中的所有实例

此响应检索单个系列中的所有实例。

详细信息

  • GET /studies/{study}/series/{series}
DicomWebResponse response = await client.RetrieveSeriesAsync(studyInstanceUid, seriesInstanceUid);

此系列有两个实例(绿色正方形和红色三角形),因此响应应返回这两个实例。 验证响应的状态代码是否为 OK,以及是否返回了这两个实例。

检索系列中所有实例的元数据

此响应检索单个研究中所有实例的元数据。

详细信息

  • GET /studies/{study}/series/{series}/metadata
DicomWebResponse response = await client.RetrieveSeriesMetadataAsync(studyInstanceUid, seriesInstanceUid);

该系列有两个实例(绿色正方形和红色三角形),因此响应应返回这两个实例的元数据。 验证响应的状态代码是否为 OK,以及是否返回了这两个实例的元数据。

检索一系列研究中的单个实例

此请求检索单个实例。

详细信息

  • GET /studies/{study}/series{series}/instances/{instance}
DicomWebResponse response = await client.RetrieveInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

该响应应仅返回红色三角形实例。 验证响应的状态代码是否为 OK,以及是否返回了该实例。

检索一系列研究中的单个实例的元数据

此请求检索单个研究和系列中单个实例的元数据。

详细信息

  • GET /studies/{study}/series/{series}/instances/{instance}/metadata
DicomWebResponse response = await client.RetrieveInstanceMetadataAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

该响应应仅返回红色三角形实例的元数据。 验证响应的状态代码是否为 OK,以及是否返回了元数据。

从单个实例中检索一个或多个帧

此请求从单个实例中检索一个或多个帧。

详细信息

  • GET /studies/{study}/series/{series}/instances/{instance}/frames/{frames}
DicomWebResponse response = await client.RetrieveFramesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, frames: new[] { 1 });

该响应应返回红色三角形中的唯一帧。 验证响应的状态代码是否为 OK,以及是否返回了该帧。

查询 DICOM (QIDO)

注意

有关支持的 DICOM 属性,请参阅 DICOM 一致性声明

搜索检查

此请求按 DICOM 属性搜索一个或多个研究。

详细信息

  • GET /studies?StudyInstanceUID={study}
string query = $"/studies?StudyInstanceUID={studyInstanceUid}";
DicomWebResponse response = await client.QueryStudyAsync(query);

验证响应是否包含一个研究,以及响应代码是否正常。

搜索序列

此请求按 DICOM 属性搜索一个或多个系列。

详细信息

  • GET /series?SeriesInstanceUID={series}
string query = $"/series?SeriesInstanceUID={seriesInstanceUid}";
DicomWebResponse response = await client.QuerySeriesAsync(query);

验证响应是否包含一个系列,以及响应代码是否正常。

搜索研究中的系列

此请求按 DICOM 属性搜索单个研究中的一个或多个系列。

详细信息

  • GET /studies/{study}/series?SeriesInstanceUID={series}
string query = $"/studies/{studyInstanceUid}/series?SeriesInstanceUID={seriesInstanceUid}";
DicomWebResponse response = await client.QueryStudySeriesAsync(studyInstanceUid, query);

验证响应是否包含一个系列,以及响应代码是否正常。

搜索实例

此请求按 DICOM 属性搜索一个或多个实例。

详细信息

  • GET /instances?SOPInstanceUID={instance}
string query = $"/instances?SOPInstanceUID={sopInstanceUid}";
DicomWebResponse response = await client.QueryInstancesAsync(query);

验证响应是否包含一个实例,以及响应代码是否正常。

搜索研究中的实例

此请求按 DICOM 属性搜索单个研究中的一个或多个实例。

详细信息

  • GET /studies/{study}/instances?SOPInstanceUID={instance}
string query = $"/studies/{studyInstanceUid}/instances?SOPInstanceUID={sopInstanceUid}";
DicomWebResponse response = await client.QueryStudyInstanceAsync(studyInstanceUid, query);

验证响应是否包含一个实例,以及响应代码是否正常。

搜索研究和系列中的实例

此请求按 DICOM 属性搜索单个研究和单个系列中的一个或多个实例。

详细信息

  • GET /studies/{study}/series/{series}/instances?SOPInstanceUID={instance}
string query = $"/studies/{studyInstanceUid}/series/{seriesInstanceUid}/instances?SOPInstanceUID={sopInstanceUid}";
DicomWebResponse response = await client.QueryStudySeriesInstanceAsync(studyInstanceUid, seriesInstanceUid, query);

验证响应是否包含一个实例,以及响应代码是否正常。

删除 DICOM

注意

删除并不是 DICOM 标准的一部分,只是为了方便起见才添加的。

删除研究和系列中的特定实例

此请求删除单个研究和单个系列中单个实例。

详细信息

  • DELETE /studies/{study}/series/{series}/instances/{instance}
string sopInstanceUidRed = "1.2.826.0.1.3680043.8.498.47359123102728459884412887463296905395";
DicomWebResponse response = await client.DeleteInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUidRed);

此响应从服务器中删除红色三角形实例。 如果成功,响应状态代码不包含任何内容。

删除研究中的特定系列

此请求删除单个研究中的单个系列(以及所有子实例)。

详细信息

  • DELETE /studies/{study}/series/{series}
DicomWebResponse response = await client.DeleteSeriesAsync(studyInstanceUid, seriesInstanceUid);

该响应从服务器中删除绿色正方形实例(它是系列中唯一留下的元素)。 如果成功,响应状态代码不包含任何内容。

删除特定研究

此请求删除单个研究(以及所有子系列和实例)。

详细信息

  • DELETE /studies/{study}
DicomWebResponse response = await client.DeleteStudyAsync(studyInstanceUid);

该响应从服务器中删除蓝色圆圈实例(它是系列中唯一留下的元素)。 如果成功,响应状态代码不包含任何内容。

注意

DICOM® 是美国电气制造商协会的注册商标,适用于其有关医疗信息数字通信的标准出版物。