使用 Cloud Storage 导入和导出 DICOM 数据

本页面介绍如何将 DICOM 实例导出到 Cloud Storage 并导入 DICOM 对象。DICOM 实例通常是图片,但也可以是另一种类型的永久性数据,例如结构化报告。Cloud Storage 中的 DICOM 对象是位于 Cloud Storage 中的 DICOM 实例。如需了解详情,请参阅 Cloud Storage

设置 Cloud Storage 权限

在将 DICOM 数据导入 Cloud Storage 以及从 Cloud Storage 导入 DICOM 数据之前,您必须向 Cloud Healthcare Service Agent 服务账号授予额外权限。有关详情,请参阅 DICOM 存储 Cloud Storage 权限

导入 DICOM 对象

如需将多个 DICOM 实例文件导入 DICOM 存储区,您可以使用以下任一方法:

以下示例展示了如何从 Cloud Storage 存储桶导入 DICOM 对象。

控制台

要从 Cloud Storage 存储桶导入 DICOM 对象,请完成以下步骤:

  1. 在 Google Cloud 控制台中,进入数据集页面。
    进入“数据集”
  2. 点击包含您要导入 DICOM 对象的 DICOM 存储区的数据集。
  3. 在数据存储区列表中,选择导入操作 DICOM 存储区的列表。

    导入到 DICOM 存储区页面会出现。
  4. 项目列表中,选择一个 Cloud Storage 项目。
  5. 位置列表中,选择一个 Cloud Storage 存储桶。
  6. 要设置导入文件的特定位置,请执行以下操作:
    1. 展开高级选项
    2. 选择替换 Cloud Storage 路径
    3. 要设置特定的文件导入来源,请在位置文本框中使用以下变量定义路径:
      • * - 匹配非分隔符。
      • ** - 匹配字符,包括分隔符。 此名称可与文件扩展名配合使用,以匹配同一类型的所有文件。
      • ? - 匹配 1 个字符。
  7. 点击导入,从定义的来源导入 DICOM 对象。
  8. 要跟踪操作的状态,请点击操作标签页。操作完成后,系统会显示以下指示:
    • 长时间运行的操作状态部分下方的确定标题下会显示一个绿色的对勾标记。
    • 概览部分在操作 ID 的同一行中显示一个绿色对勾标记和一个确定指示符。
    如果您遇到任何错误,请点击操作,然后点击在 Cloud Logging 中查看详细信息

gcloud

要从 Cloud Storage 存储桶导入 DICOM 对象,请使用 gcloud healthcare dicom-stores import gcs 命令。指定父数据集的名称、DICOM 存储区的名称以及该对象在 Cloud Storage 存储桶中的位置。

  • 文件在存储桶中的位置是任意的,无需严格遵循以下示例中指定的格式。
  • 在 Cloud Storage 中指定 DICOM 资源的位置时,您可以使用通配符从一个或多个目录导入多个文件。支持以下通配符:
    • 使用 * 可以匹配零个或更多的非分隔符字符。例如,gs://BUCKET/DIRECTORY/Example*.dcm 匹配 DIRECTORY中的 Example.dcm 和 Example22.dcm。
    • 使用 ** 匹配 0 个或多个字符(包括分隔符)。必须在路径末尾使用,且路径中没有其他通配符。也可与扩展名(如.dcm)一起使用,该扩展名可导入指定目录及其子目录中扩展名中的所有文件。例如,gs://BUCKET/DIRECTORY/**.dcm 会导入 DIRECTORY 及其子目录中扩展名为 .dcm 文件名的所有文件。
    • 使用 ? 可以匹配 1 个字符。例如,gs://BUCKET/DIRECTORY/Example?.dcm 匹配 Example1.dcm,但不匹配 Example.dcm 或 Example01.dcm。

以下示例展示了如何从 Cloud Storage 存储桶导入 DICOM 对象。

gcloud healthcare dicom-stores import gcs DICOM_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --gcs-uri=gs://BUCKET/DIRECTORY/DICOM_INSTANCE.dcm

命令行会显示操作 ID:

name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID

如需查看操作的状态,请运行 gcloud healthcare operations describe 命令并从响应中提供 OPERATION_ID

gcloud healthcare operations describe OPERATION_ID \
  --location=LOCATION \
  --dataset=DATASET_ID

命令完成后,响应将包含 done: true

done: true
metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.dicom.DicomService.ImportDicomData
counter:
  success: SUCCESSFUL_INSTANCES
  failure: FAILED_INSTANCES
createTime: "CREATE_TIME"
endTime: "END_TIME"
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
response:
'@type': "..."

API

要从 Cloud Storage 存储桶导入 DICOM 对象,请使用 projects.locations.datasets.dicomStores.import 方法。

  • 存储桶中的文件位置可能会有所不同,不必与以下示例中指定的格式一致。
  • 在 Cloud Storage 中指定 DICOM 对象的位置时,请使用通配符从一个或多个目录导入多个文件。 支持以下通配符:
    • 使用 * 可以匹配零个或更多的非分隔符字符。例如,gs://BUCKET/DIRECTORY/Example*.dcm 匹配 DIRECTORY中的 Example.dcm 和 Example22.dcm。
    • 使用 ** 匹配 0 个或多个字符(包括分隔符)。必须在路径末尾使用,且路径中没有其他通配符。也可与扩展名(如.dcm)一起使用,该扩展名可导入指定目录及其子目录中扩展名中的所有文件。例如,gs://BUCKET/DIRECTORY/**.dcm 会导入 DIRECTORY 及其子目录中扩展名为 .dcm 文件名的所有文件。
    • 使用 ? 可以匹配 1 个字符。例如,gs://BUCKET/DIRECTORY/Example?.dcm 匹配 Example1.dcm,但不匹配 Example.dcm 或 Example01.dcm。

REST

  1. 导入 DICOM 对象。

    在使用任何请求数据之前,请先进行以下替换:

    • PROJECT_ID:您的 Google Cloud 项目的 ID
    • LOCATION:数据集位置
    • DATASET_ID: DICOM 存储区的父数据集
    • DICOM_STORE_ID:DICOM 存储区 ID
    • BUCKET/PATH/TO/FILE:Cloud Storage 中 DICOM 对象的路径

    请求 JSON 正文:

    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      }
    }
    

    如需发送请求,请选择以下方式之一:

    curl

    将请求正文保存在名为 request.json 的文件中。在终端中运行以下命令,在当前目录中创建或覆盖此文件:

    cat > request.json << 'EOF'
    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      }
    }
    EOF

    然后,执行以下命令以发送 REST 请求:

    curl -X POST \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -d @request.json \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:import"

    PowerShell

    将请求正文保存在名为 request.json 的文件中。在终端中运行以下命令,在当前目录中创建或覆盖此文件:

    @'
    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      }
    }
    '@  | Out-File -FilePath request.json -Encoding utf8

    然后,执行以下命令以发送 REST 请求:

    $cred = gcloud auth print-access-token
    $headers = @{ "Authorization" = "Bearer $cred" }

    Invoke-WebRequest `
    -Method POST `
    -Headers $headers `
    -ContentType: "application/json" `
    -InFile request.json `
    -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:import" | Select-Object -Expand Content
    输出如下所示。响应中包含长时间运行的操作的标识符。如果方法调用可能需要大量时间才能完成,系统就会返回长时间运行的操作。请注意 OPERATION_ID 的值。下一步中需要用到此值。

  2. 获取长时间运行的操作的状态。

    在使用任何请求数据之前,请先进行以下替换:

    • PROJECT_ID:您的 Google Cloud 项目的 ID
    • LOCATION:数据集位置
    • DATASET_ID: DICOM 存储区的父数据集
    • OPERATION_ID:从长时间运行的操作返回的 ID

    如需发送请求,请选择以下方式之一:

    curl

    执行以下命令:

    curl -X GET \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

    PowerShell

    执行以下命令:

    $cred = gcloud auth print-access-token
    $headers = @{ "Authorization" = "Bearer $cred" }

    Invoke-WebRequest `
    -Method GET `
    -Headers $headers `
    -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content
    如果长时间运行的操作仍在运行,服务器将返回响应,其中包含待导入的 DICOM 实例数。 当 LRO 成功完成后,服务器会以 JSON 格式返回包含操作状态的响应:

Go

import (
	"context"
	"fmt"
	"io"

	healthcare "google.golang.org/api/healthcare/v1"
)

// importDICOMInstance imports DICOM objects from GCS.
func importDICOMInstance(w io.Writer, projectID, location, datasetID, dicomStoreID, contentURI string) error {
	ctx := context.Background()

	healthcareService, err := healthcare.NewService(ctx)
	if err != nil {
		return fmt.Errorf("healthcare.NewService: %w", err)
	}

	storesService := healthcareService.Projects.Locations.Datasets.DicomStores

	req := &healthcare.ImportDicomDataRequest{
		GcsSource: &healthcare.GoogleCloudHealthcareV1DicomGcsSource{
			Uri: contentURI,
		},
	}
	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/dicomStores/%s", projectID, location, datasetID, dicomStoreID)

	lro, err := storesService.Import(name, req).Do()
	if err != nil {
		return fmt.Errorf("Import: %w", err)
	}

	fmt.Fprintf(w, "Import to DICOM store started. Operation: %q\n", lro.Name)
	return nil
}

Java

import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.healthcare.v1.CloudHealthcare;
import com.google.api.services.healthcare.v1.CloudHealthcare.Projects.Locations.Datasets.DicomStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1DicomGcsSource;
import com.google.api.services.healthcare.v1.model.ImportDicomDataRequest;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class DicomStoreImport {
  private static final String DICOM_NAME = "projects/%s/locations/%s/datasets/%s/dicomStores/%s";
  private static final JsonFactory JSON_FACTORY = new GsonFactory();
  private static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  public static void dicomStoreImport(String dicomStoreName, String gcsUri) throws IOException {
    // String dicomStoreName =
    //    String.format(
    //        DICOM_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-dicom-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store should be imported from.
    GoogleCloudHealthcareV1DicomGcsSource gcsSource =
        new GoogleCloudHealthcareV1DicomGcsSource().setUri(gcsUri);
    ImportDicomDataRequest importRequest = new ImportDicomDataRequest().setGcsSource(gcsSource);

    // Create request and configure any parameters.
    DicomStores.CloudHealthcareImport request =
        client
            .projects()
            .locations()
            .datasets()
            .dicomStores()
            .healthcareImport(dicomStoreName, importRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("DICOM store import complete." + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(System.out);
    }
  }

  private static CloudHealthcare createClient() throws IOException {
    // Use Application Default Credentials (ADC) to authenticate the requests
    // For more information see https://cloud.google.com/docs/authentication/production
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    // Create a HttpRequestInitializer, which will provide a baseline configuration to all requests.
    HttpRequestInitializer requestInitializer =
        request -> {
          new HttpCredentialsAdapter(credential).initialize(request);
          request.setConnectTimeout(60000); // 1 minute connect timeout
          request.setReadTimeout(60000); // 1 minute read timeout
        };

    // Build the client for interacting with the service.
    return new CloudHealthcare.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName("your-application-name")
        .build();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});
const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const importDicomInstance = async () => {
  // TODO(developer): uncomment these lines before running the sample
  // const cloudRegion = 'us-central1';
  // const projectId = 'adjective-noun-123';
  // const datasetId = 'my-dataset';
  // const dicomStoreId = 'my-dicom-store';
  // const gcsUri = 'my-bucket/my-directory/*.dcm'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/dicomStores/${dicomStoreId}`;
  const request = {
    name,
    resource: {
      // The location of the DICOM instances in Cloud Storage
      gcsSource: {
        uri: `gs://${gcsUri}`,
      },
    },
  };

  const operation =
    await healthcare.projects.locations.datasets.dicomStores.import(request);
  const operationName = operation.data.name;

  const operationRequest = {name: operationName};

  // Wait fifteen seconds for the LRO to finish.
  await sleep(15000);

  // Check the LRO's status
  const operationStatus =
    await healthcare.projects.locations.datasets.operations.get(
      operationRequest
    );

  const {data} = operationStatus;

  if (data.error === undefined) {
    console.log('Successfully imported DICOM instances');
  } else {
    console.log('Encountered errors. Sample error:');
    console.log(
      'Resource on which error occured:',
      data.error.details[0]['sampleErrors'][0]['resource']
    );
    console.log(
      'Error code:',
      data.error.details[0]['sampleErrors'][0]['error']['code']
    );
    console.log(
      'Error message:',
      data.error.details[0]['sampleErrors'][0]['error']['message']
    );
  }
};

importDicomInstance();

Python

def import_dicom_instance(
    project_id, location, dataset_id, dicom_store_id, content_uri
):
    """Imports data into the DICOM store by copying it from the specified
    source.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/dicom
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Returns an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # TODO(developer): Uncomment these lines and replace with your values.
    # project_id = 'my-project'  # replace with your GCP project ID
    # location = 'us-central1'  # replace with the parent dataset's location
    # dataset_id = 'my-dataset'  # replace with the DICOM store's parent dataset ID
    # dicom_store_id = 'my-dicom-store'  # replace with the DICOM store's ID
    # content_uri = 'my-bucket/*.dcm'  # replace with a Cloud Storage bucket and DCM files
    dicom_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    dicom_store_name = f"{dicom_store_parent}/dicomStores/{dicom_store_id}"

    body = {"gcsSource": {"uri": f"gs://{content_uri}"}}

    # Escape "import()" method keyword because "import"
    # is a reserved keyword in Python
    request = (
        client.projects()
        .locations()
        .datasets()
        .dicomStores()
        .import_(name=dicom_store_name, body=body)
    )

    response = request.execute()
    print(f"Imported DICOM instance: {content_uri}")

    return response

如需从 DICOM 存储区中检索单个实例或研究,请使用 Cloud Healthcare API 中实现的检索事务 RESTful 网络服务检索 DICOM 数据

指定存储类别以导入 DICOM 对象(预览版)

默认情况下,projects.locations.datasets.dicomStores.import 方法会将 DICOM 对象导入具有标准存储类别的 DICOM 存储区。从 Cloud Storage 导入 DICOM 对象时,可以设置存储类别。 如需了解详情,请参阅更改 DICOM 存储类别

以下示例展示了如何在从 Cloud Storage 导入 DICOM 对象时指定存储类别。

REST

使用 projects.locations.datasets.dicomStores.import 方法。

  1. 导入 DICOM 对象。

    在使用任何请求数据之前,请先进行以下替换:

    • PROJECT_ID:您的 Google Cloud 项目的 ID
    • LOCATION:数据集位置
    • DATASET_ID: DICOM 存储区的父数据集
    • DICOM_STORE_ID:DICOM 存储区 ID
    • BUCKET/PATH/TO/FILE:Cloud Storage 中 DICOM 对象的路径
    • STORAGE_CLASS:来自 STANDARDNEARLINECOLDLINEARCHIVE 的 DICOM 存储区中的 DICOM 对象的存储类别

    请求 JSON 正文:

    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      },
      "blob_storage_settings": {
        "blob_storage_class": "STORAGE_CLASS"
      }
    }
    

    如需发送请求,请选择以下方式之一:

    curl

    将请求正文保存在名为 request.json 的文件中。在终端中运行以下命令,在当前目录中创建或覆盖此文件:

    cat > request.json << 'EOF'
    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      },
      "blob_storage_settings": {
        "blob_storage_class": "STORAGE_CLASS"
      }
    }
    EOF

    然后,执行以下命令以发送 REST 请求:

    curl -X POST \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -d @request.json \
    "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:import"

    PowerShell

    将请求正文保存在名为 request.json 的文件中。在终端中运行以下命令,在当前目录中创建或覆盖此文件:

    @'
    {
      "gcsSource": {
        "uri": "gs://BUCKET/PATH/TO/FILE.dcm"
      },
      "blob_storage_settings": {
        "blob_storage_class": "STORAGE_CLASS"
      }
    }
    '@  | Out-File -FilePath request.json -Encoding utf8

    然后,执行以下命令以发送 REST 请求:

    $cred = gcloud auth print-access-token
    $headers = @{ "Authorization" = "Bearer $cred" }

    Invoke-WebRequest `
    -Method POST `
    -Headers $headers `
    -ContentType: "application/json" `
    -InFile request.json `
    -Uri "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:import" | Select-Object -Expand Content
    输出如下所示。响应中包含长时间运行的操作的标识符。如果方法调用可能需要大量时间才能完成,系统就会返回长时间运行的操作。请注意 OPERATION_ID 的值。下一步中需要用到此值。

  2. 获取长时间运行的操作的状态。

    在使用任何请求数据之前,请先进行以下替换:

    • PROJECT_ID:您的 Google Cloud 项目的 ID
    • LOCATION:数据集位置
    • DATASET_ID: DICOM 存储区的父数据集
    • OPERATION_ID:从长时间运行的操作返回的 ID

    如需发送请求,请选择以下方式之一:

    curl

    执行以下命令:

    curl -X GET \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

    PowerShell

    执行以下命令:

    $cred = gcloud auth print-access-token
    $headers = @{ "Authorization" = "Bearer $cred" }

    Invoke-WebRequest `
    -Method GET `
    -Headers $headers `
    -Uri "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content
    如果长时间运行的操作仍在运行,服务器将返回响应,其中包含待导入的 DICOM 实例数。 当 LRO 完成后,服务器会以 JSON 格式返回包含操作状态的响应:

对 DICOM 导入请求进行问题排查

如果在执行 DICOM 导入请求期间发生错误,系统会将错误记录到 Cloud Logging。如需了解详情,请参阅在 Cloud Logging 中查看错误日志

导出 DICOM 实例

以下示例展示了如何将 DICOM 实例导出到 Cloud Storage 存储桶。从 DICOM 存储区导出 DICOM 实例时,将导出该存储区中的所有实例。

控制台

要将 DICOM 实例导出到 Cloud Storage,请完成以下步骤:

  1. 在 Google Cloud 控制台中,进入数据集页面。
    进入“数据集”
  2. 点击包含您从中导出 DICOM 实例的数据集。
  3. 在数据存储区列表中,从 DICOM 存储区的操作列表中选择导出
  4. 在出现的导出 DICOM 存储区页面上,选择 Google Cloud Storage 存储分区
  5. 项目列表中,选择一个 Cloud Storage 项目。
  6. 位置列表中,选择一个 Cloud Storage 存储桶。
  7. DICOM 导出设置中,选择用于导出 DICOM 实例的文件类型。您可以选择以下类型:
    • DICOM 文件(.dcm
    • 八位元字符串流
    • 映像(.jpg.png
  8. 要定义其他转移语法,请从转移语法列表中选择语法。
  9. 点击导出,将 DICOM 实例导出到 Cloud Storage 中的指定位置。
  10. 要跟踪操作的状态,请点击操作标签页。操作完成后,系统会显示以下指示:
    • 长时间运行的操作状态部分下方的确定标题下会显示一个绿色的对勾标记。
    • 概览部分在操作 ID 的同一行中显示一个绿色对勾标记和一个确定指示符。
    如果您遇到任何错误,请点击操作,然后点击在 Cloud Logging 中查看详细信息

gcloud

要将 DICOM 实例导出到 Cloud Storage 存储桶,请使用 gcloud healthcare dicom-stores export gcs 命令。

  • 提供父数据集的名称、DICOM 存储区的名称和目标 Cloud Storage 存储桶。
  • 写入 Cloud Storage 存储桶或目录(而非对象),因为 Cloud Healthcare API 会为每个对象创建一个.dcm文件。
  • 如果该命令指定的目录不存在,则会创建该目录。

以下示例展示了 gcloud healthcare dicom-stores export gcs 命令。

gcloud healthcare dicom-stores export gcs DICOM_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --gcs-uri-prefix=gs://BUCKET/DIRECTORY

命令行会显示操作 ID:

name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID

如需查看操作的状态,请运行 gcloud healthcare operations describe 命令并从响应中提供 OPERATION_ID

gcloud healthcare operations describe OPERATION_ID \
  --location=LOCATION \
  --dataset=DATASET_ID

命令完成后,响应将包含 done: true

done: true
metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.dicom.DicomService.ExportDicomData
counter:
  success: SUCCESSFUL_INSTANCES
  failure: FAILED_INSTANCES
createTime: "CREATE_TIME"
endTime: "END_TIME"
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
response:
'@type': "..."

API

要将 DICOM 实例导出到 Cloud Storage 存储桶,请使用 projects.locations.datasets.dicomStores.export 方法。

  • 写入 Cloud Storage 存储桶或目录(而非对象),因为 Cloud Healthcare API 会为每个 DICOM 对象创建一个 .dcm 文件。
  • 如果该命令指定的目录不存在,则会创建该目录。

curl

如需导出 DICOM 实例,请发出 POST 请求并提供以下信息:

  • 父级数据集的名称和位置
  • DICOM 存储区的名称
  • 目标 Cloud Storage 存储桶

以下示例展示了使用 curlPOST 请求。

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'gcsDestination': {
        'uriPrefix': 'gs://BUCKET/DIRECTORY'
      }
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:export"

如果请求成功,服务器将以 JSON 格式返回响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

响应包含操作名称。要跟踪操作的状态,请使用操作 get 方法

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

如果请求成功,服务器将以 JSON 格式返回包含操作状态的响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.dicom.DicomService.ExportDicomData",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter":{
       "success": SUCCESSFUL_INSTANCES
       "failure": FAILED_INSTANCES
    }
  },
  "done": true,
  "response": {
    "@type": "..."
  }
}

PowerShell

如需导出 DICOM 实例,请发出 POST 请求并提供以下信息:

  • 父级数据集的名称和位置
  • DICOM 存储区的名称
  • 目标 Cloud Storage 存储桶

以下示例展示了使用 Windows PowerShell 的 POST 请求。

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'gcsDestination': {
      'uriPrefix': 'gs://BUCKET/DIRECTORY'
    }
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:export" | Select-Object -Expand Content

如果请求成功,服务器将以 JSON 格式返回响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

响应包含操作名称。要跟踪操作的状态,请使用操作 get 方法

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content

如果请求成功,服务器将以 JSON 格式返回包含操作状态的响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.dicom.DicomService.ExportDicomData",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter":{
       "success": SUCCESSFUL_INSTANCES
       "failure": FAILED_INSTANCES
    },
  },
  "done": true,
  "response": {
    "@type": "..."
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	healthcare "google.golang.org/api/healthcare/v1"
)

// exportDICOMInstance exports DICOM objects to GCS.
func exportDICOMInstance(w io.Writer, projectID, location, datasetID, dicomStoreID, destination string) error {
	ctx := context.Background()

	healthcareService, err := healthcare.NewService(ctx)
	if err != nil {
		return fmt.Errorf("healthcare.NewService: %w", err)
	}

	storesService := healthcareService.Projects.Locations.Datasets.DicomStores

	req := &healthcare.ExportDicomDataRequest{
		GcsDestination: &healthcare.GoogleCloudHealthcareV1DicomGcsDestination{
			UriPrefix: destination, // "gs://my-bucket/path/to/prefix/"
		},
	}
	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/dicomStores/%s", projectID, location, datasetID, dicomStoreID)

	lro, err := storesService.Export(name, req).Do()
	if err != nil {
		return fmt.Errorf("Export: %w", err)
	}

	fmt.Fprintf(w, "Export to DICOM store started. Operation: %q\n", lro.Name)
	return nil
}

Java

import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.healthcare.v1.CloudHealthcare;
import com.google.api.services.healthcare.v1.CloudHealthcare.Projects.Locations.Datasets.DicomStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.ExportDicomDataRequest;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1DicomGcsDestination;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class DicomStoreExport {
  private static final String DICOM_NAME = "projects/%s/locations/%s/datasets/%s/dicomStores/%s";
  private static final JsonFactory JSON_FACTORY = new GsonFactory();
  private static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  public static void dicomStoreExport(String dicomStoreName, String gcsUri) throws IOException {
    // String dicomStoreName =
    //    String.format(
    //        DICOM_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-dicom-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store will be exported too.
    GoogleCloudHealthcareV1DicomGcsDestination gcsDestination =
        new GoogleCloudHealthcareV1DicomGcsDestination().setUriPrefix(gcsUri);
    ExportDicomDataRequest exportRequest =
        new ExportDicomDataRequest().setGcsDestination(gcsDestination);

    // Create request and configure any parameters.
    DicomStores.Export request =
        client
            .projects()
            .locations()
            .datasets()
            .dicomStores()
            .export(dicomStoreName, exportRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("DICOM store export complete." + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(System.out);
    }
  }

  private static CloudHealthcare createClient() throws IOException {
    // Use Application Default Credentials (ADC) to authenticate the requests
    // For more information see https://cloud.google.com/docs/authentication/production
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    // Create a HttpRequestInitializer, which will provide a baseline configuration to all requests.
    HttpRequestInitializer requestInitializer =
        request -> {
          new HttpCredentialsAdapter(credential).initialize(request);
          request.setConnectTimeout(60000); // 1 minute connect timeout
          request.setReadTimeout(60000); // 1 minute read timeout
        };

    // Build the client for interacting with the service.
    return new CloudHealthcare.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName("your-application-name")
        .build();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});

const exportDicomInstanceGcs = async () => {
  // TODO(developer): uncomment these lines before running the sample
  // const cloudRegion = 'us-central1';
  // const projectId = 'adjective-noun-123';
  // const datasetId = 'my-dataset';
  // const dicomStoreId = 'my-dicom-store';
  // const gcsUri = 'my-bucket/my-directory'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/dicomStores/${dicomStoreId}`;
  const request = {
    name,
    resource: {
      gcsDestination: {
        // The destination location of the DICOM instances in Cloud Storage
        uriPrefix: `gs://${gcsUri}`,
        // The format to use for the output files, per the MIME types supported in the DICOM spec
        mimeType: 'application/dicom',
      },
    },
  };

  await healthcare.projects.locations.datasets.dicomStores.export(request);
  console.log(`Exported DICOM instances to ${gcsUri}`);
};

exportDicomInstanceGcs();

Python

def export_dicom_instance(project_id, location, dataset_id, dicom_store_id, uri_prefix):
    """Export data to a Google Cloud Storage bucket by copying
    it from the DICOM store.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/dicom
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Returns an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # TODO(developer): Uncomment these lines and replace with your values.
    # project_id = 'my-project'  # replace with your GCP project ID
    # location = 'us-central1'  # replace with the parent dataset's location
    # dataset_id = 'my-dataset'  # replace with the DICOM store's parent dataset ID
    # dicom_store_id = 'my-dicom-store'  # replace with the DICOM store's ID
    # uri_prefix = 'my-bucket'  # replace with a Cloud Storage bucket
    dicom_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    dicom_store_name = f"{dicom_store_parent}/dicomStores/{dicom_store_id}"

    body = {"gcsDestination": {"uriPrefix": f"gs://{uri_prefix}"}}

    request = (
        client.projects()
        .locations()
        .datasets()
        .dicomStores()
        .export(name=dicom_store_name, body=body)
    )

    response = request.execute()
    print(f"Exported DICOM instances to bucket: gs://{uri_prefix}")

    return response

使用过滤条件导出 DICOM 实例

默认情况下,当您将 DICOM 文件导出到 Cloud Storage 时, DICOM 存储区中的所有 DICOM 文件都会导出。同样,将 DICOM 元数据导出到 BigQuery 时,系统会导出 DICOM 存储区中所有 DICOM 数据的元数据。

您可以使用过滤器文件导出部分 DICOM 数据或元数据。

配置过滤器文件

您可以使用过滤器文件定义要导出到 Cloud Storage 或 BigQuery 的 DICOM 文件列表。

过滤器文件中的每一行定义研究、系列或实例,并采用 /studies/STUDY_INSTANCE_UID/series/SERIES_INSTANCE_UID/instances/INSTANCE_UID 格式。

您可以截断一行,以指定过滤器在哪个级别发挥作用。 例如,您可以通过指定 /studies/STUDY_INSTANCE_UID 来导出整个研究,也可以通过指定 /studies/STUDY_INSTANCE_UID/series/SERIES_INSTANCE_UID 来导出整个系列。

请参考以下过滤器文件:

/studies/1.123.456.789
/studies/1.666.333.111/series/123.456
/studies/1.666.333.111/series/567.890
/studies/1.888.999.222/series/123.456/instances/111
/studies/1.888.999.222/series/123.456/instances/222
/studies/1.888.999.222/series/123.456/instances/333

此过滤器文件会过滤以下内容:

  • 研究实例 UID 为 1.123.456.789 的整个研究
  • 在研究 1.666.333.111 中,两个单独的系列,其系列实例 UID 为 123.456567.890
  • 研究 1.888.999.222 和系列 123.456 中实例 ID 分别为 111222333 的三个单独实例

使用 BigQuery 创建过滤条件文件

如需使用 BigQuery 创建过滤条件文件,您必须将 DICOM 存储区的元数据导出到 BigQuery。 导出的元数据会显示 DICOM 存储区中 DICOM 数据的研究、系列和实例 UID。

导出后,请完成以下步骤:

  1. 查询所需的研究、系列和实例 UID。

    例如,将 DICOM 元数据导出到 BigQuery 后,请运行以下查询来串联研究、系列和实例 UID,以符合过滤器文件格式要求:

    SELECT CONCAT
        ('/studies/', StudyInstanceUID, '/series/', SeriesInstanceUID, '/instances/', SOPInstanceUID)
    FROM
        [PROJECT_ID:BIGQUERY_DATASET.BIGQUERY_TABLE]
    
  2. 可选:如果查询返回的大型结果集超过响应大小上限,请在 BigQuery 中将查询结果保存到新的目标表

  3. 将查询结果保存到文件中,并将其导出到 Cloud Storage。如果您在第 2 步中将查询结果保存到了新的目标表,请参阅导出表数据以将表的内容导出到 Cloud Storage。

  4. 根据需要修改导出的文件,并将其用作过滤器文件。 在导出操作中,需要过滤器文件在 Cloud Storage 中的位置。

手动创建过滤条件文件

如需创建包含自定义内容的过滤器文件并将其上传到 Cloud Storage 存储桶,请完成以下步骤:

  1. 创建一个过滤文件,其中包含需要在本地机器上更改存储类别的实例的列表。使用配置过滤器文件部分中所述的格式。

  2. 将过滤文本文件上传到 Cloud Storage 位置。

    gsutil cp PATH_TO_FILTER_FILE/FILTER_FILE_NAME.txt gs://BUCKET/DIRECTORY
    

    替换以下内容:

    • PATH_TO_FILTER_FILE:本地机器上过滤器文件的路径
    • FILTER_FILE_NAME:过滤器文件的名称
    • BUCKET/DIRECTORY:Cloud Storage 位置的路径

    例如:

    gsutil cp my-local-folder/archive-filters.txt gs://my-bucket/my-directory
    

传入过滤条件文件

创建过滤条件文件后,请调用 DICOM 导出操作,并使用 REST API 传入过滤条件文件。以下示例展示了如何使用过滤条件导出 DICOM 数据。

gcloud

如需使用过滤条件将 DICOM 元数据导出到 Cloud Storage,请使用 gcloud beta healthcare dicom-stores export gcs 命令:

gcloud beta healthcare dicom-stores export gcs DICOM_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --gcs-uri-prefix=gs://DESTINATION_BUCKET/DIRECTORY \
  --filter-config-gcs-uri=gs://BUCKET/DIRECTORY/FILTER_FILE

替换以下内容:

  • DICOM_STORE_ID:DICOM 存储区的标识符
  • DATASET_ID:DICOM 存储区的父级数据集的名称
  • LOCATION:DICOM 存储区的父级数据集的位置
  • DESTINATION_BUCKET/DIRECTORY:目标 Cloud Storage 存储桶
  • BUCKET/DIRECTORY/FILTER_FILE:过滤条件文件在 Cloud Storage 存储桶中的位置

输出如下所示:

Request issued for: [DICOM_STORE_ID]
Waiting for operation [projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID] to complete...done.
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID

如需查看操作的状态,请运行 gcloud healthcare operations describe 命令并从响应中提供 OPERATION_ID

gcloud healthcare operations describe OPERATION_ID \
  --location=LOCATION \
  --dataset=DATASET_ID

替换以下内容:

  • OPERATION_ID:从上一条响应中返回的 ID 编号
  • DATASET_ID:DICOM 存储区的父级数据集的名称
  • LOCATION:DICOM 存储区的父级数据集的位置

输出如下所示:

done: true
metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1beta1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1beta1.dicom.DicomService.ExportDicomData
counter:
  success: SUCCESSFUL_INSTANCES
  failure: FAILED_INSTANCES
createTime: 'CREATE_TIME'
endTime: 'END_TIME'
logsUrl: 'https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL'
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
response:
'@type': '...'

API

如需使用过滤条件导出 DICOM 数据,请使用 projects.locations.datasets.dicomStores.export 方法。

curl

如需使用过滤条件文件导出 DICOM 数据,请发出 POST 请求并提供以下信息:

  • 父级数据集的名称和位置
  • DICOM 存储区的名称
  • 目标 Cloud Storage 存储桶
  • 过滤条件文件在 Cloud Storage 存储桶中的位置

以下示例展示了使用 curlPOST 请求。

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'gcsDestination': {
        'uriPrefix': 'gs://BUCKET/DIRECTORY'
      },
      'filterConfig': {
        'resourcePathsGcsUri': 'gs://BUCKET/DIRECTORY/FILTER_FILE'
      }
    }" "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:export"

如果请求成功,则服务器会返回 JSON 格式的以下响应:

{
  "name": "projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_ID"
}

响应包含操作名称。使用操作 get 方法跟踪操作的状态:

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_NAME"

如果请求成功,服务器会返回 JSON 格式的以下响应:

{
  "name": "projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1beta1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1beta1.dicom.DicomService.ExportDicomData",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME"
  },
  "done": true,
  "response": {
    "@type": "..."
  }
}

PowerShell

如需使用过滤条件文件导出 DICOM 数据,请发出 POST 请求并提供以下信息:

  • 父级数据集的名称和位置
  • DICOM 存储区的名称
  • 目标 Cloud Storage 存储桶
  • 过滤条件文件在 Cloud Storage 存储桶中的位置

以下示例展示了使用 Windows PowerShell 的 POST 请求。

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'gcsDestination': {
      'uriPrefix': 'gs://BUCKET/DIRECTORY'
    },
    'filterConfig': {
      'resourcePathsGcsUri': 'gs://BUCKET/DIRECTORY/FILTER_FILE'
  }" `
  -Uri "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/dicomStores/DICOM_STORE_ID:export" | Select-Object -Expand Content

如果请求成功,则服务器会返回 JSON 格式的以下响应:

{
  "name": "projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_ID"
}

响应包含操作名称。使用操作 get 方法跟踪操作的状态:

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1beta1/projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_NAME" | Select-Object -Expand Content

如果请求成功,服务器会以 JSON 格式返回包含操作状态的以下响应。

{
  "name": "projects/PROJECT_ID/locations/REGION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1beta1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1beta1.dicom.DicomService.ExportDicomData",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME"
  },
  "done": true,
  "response": {
    "@type": "..."
  }
}

对 DICOM 导出请求进行问题排查

如果在执行 DICOM 导出请求期间发生错误,系统会将错误记录到 Cloud Logging。如需了解详情,请参阅在 Cloud Logging 中查看错误日志

如果整个操作返回错误,请参阅排查长时间运行的操作问题