mcpField
I
imaging-data-commons

imaging-data-commons

github.com/jaechang-hits数据与数据库38467 次安装1 周前更新
代码仓库

关于 imaging-data-commons

idc-index 是供研究人员筛选和下载 NCI Imaging Data Commons 公共癌症影像数据的 Python 客户端。内置元数据索引支持本地 DuckDB SQL 查询,影像可从公共 AWS 或 Google Cloud Storage 存储桶下载。

主要功能

  1. 01用 SQL 本地查询内置元数据
  2. 02浏览集合、患者、研究和序列
  3. 03按 DICOM 标识筛选下载内容
  4. 04下载前预估队列大小
  5. 05生成 OHIF 或 Slim 浏览器链接

适用场景

  1. 01按 DICOM 元数据筛选癌症影像队列
  2. 02构建可复现的机器学习研究队列
  3. 03下载指定 DICOM 序列进行处理
  4. 04分享影像序列的浏览器链接

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill imaging-data-commons

安装后在 Claude Code 中输入/imaging-data-commons确认已加载。

详细介绍

NCI Imaging Data Commons(idc-index)

概述

NCI Imaging Data Commons(IDC)是最大的癌症影像公开数据集,托管了 175+ 个 DICOM 数据集(CT、MR、PET、玻片显微镜、分割、结构化报告)。idc-index Python 客户端将整个 IDC 元数据目录作为 parquet 文件打包在 pip wheel 中;IDCClient() 会将其加载到 DuckDB,因此 sql_query() 可在本地运行,不产生任何网络调用。

图像下载通过内置的 s5cmd 可执行文件,从公共 AWS S3(默认)或 Google Cloud Storage 存储桶中流式传输。无需 GCP/AWS 凭据、无需支付 BigQuery 费用,也无需服务账号 JSON。

适用场景

  • 按模态、癌症类型、解剖部位或 DICOM 标签搜索公开的癌症影像数据集
  • 基于有版本记录的 IDC 版本构建可复现的 ML 队列(分割、分类、多模态)
  • 无需下载,使用 SQL 大规模查询全部 175+ 个数据集中的 DICOM 元数据
  • 下载特定 DICOM 序列,用于本地处理或模型训练
  • 生成 OHIF/Slim 查看器 URL,以便在浏览器中分享或交互式查看序列
  • 如果只需要读取、编辑或匿名化已有的本地 DICOM 文件,请改用 pydicom-medical-imaging
  • 如果要在下载后进行全切片病理图像预处理(切块、染色标准化),请改用 histolab

前置条件

  • Python 包:idc-index(>=0.12)、pandas、pydicom(用于下载后读取 DICOM 文件)
  • 数据要求:查询无需数据。下载时需要准备与 series_size_MB 相当的可用磁盘空间
  • 环境:无需身份验证。所有数据均可公开访问。wheel 内置 parquet 索引和用于高速 S3 传输的 s5cmd 可执行文件
  • 速率限制:本地 SQL 查询(在本地 parquet 上运行 DuckDB)没有限制。批量下载受网络带宽限制,而非 API 配额限制
# Skip when already provisioned in a pixi or conda env
pip install idc-index pydicom

快速开始

from idc_index import IDCClient

client = IDCClient()
print('IDC version:', client.get_idc_version())
print('Collections:', len(client.get_collections()))
print('First 5:', client.get_collections()[:5])
df = client.sql_query("""
    SELECT collection_id, COUNT(DISTINCT SeriesInstanceUID) AS n_series
    FROM index
    WHERE Modality = 'CT'
    GROUP BY collection_id
    ORDER BY n_series DESC LIMIT 5
""")
print(df)

核心 API

模块 1:客户端初始化与数据集

IDCClient() 是唯一入口。它会加载 parquet 索引,将其注册为名为 index 的 DuckDB 表,并验证内置的 s5cmd。get_collections() 会返回普通 Python 列表,其中包含小写的数据集 ID,例如 nsclc_radiomics、lidc_idri 和 tcga_gbm。

from idc_index import IDCClient

client = IDCClient()
collections = client.get_collections()
print("total:", len(collections), "type:", type(collections).__name__)
print("lung-related:", [c for c in collections if "lung" in c or "nsclc" in c][:5])
模块 2:sql_query(对本地索引执行 DuckDB 查询)

推荐使用的队列筛选 API。表名为 index;安装后会自动注册其他表(prior_versions_index,以及可选的 sm_index、clinical_index)。返回 pandas DataFrame。对于涉及 Modality、BodyPartExamined、series_size_MB 或任意 DICOM 标签的筛选,请使用此 API。idc-index 中已不再提供旧版 get_series(collection_id=..., modality=...) 签名。

# Cohort: small CT series in NSCLC Radiomics, sorted by size for cheap testing
df = client.sql_query("""
    SELECT SeriesInstanceUID, StudyInstanceUID, PatientID, Modality, series_size_MB
    FROM index
    WHERE collection_id = 'nsclc_radiomics'
      AND Modality = 'CT'
    ORDER BY series_size_MB ASC
    LIMIT 5
""")
print(df[["PatientID", "Modality", "series_size_MB"]])
# Cross-collection lung CT count, using DuckDB ILIKE for case-insensitive matching
df = client.sql_query("""
    SELECT collection_id, COUNT(DISTINCT SeriesInstanceUID) AS n
    FROM index
    WHERE Modality = 'CT' AND BodyPartExamined ILIKE '%LUNG%'
    GROUP BY collection_id
    ORDER BY n DESC LIMIT 5
""")
print(df)
模块 3:分层浏览(患者、检查、序列)

要按 DICOM 层级导航(Collection -> Patient -> Study -> Series),请使用带类型的辅助函数。每个函数都接受 outputFormat 参数,可设为 dict(默认)、df 或 list。注意:get_dicom_series() 接受 studyInstanceUID(而非 collection_id)。如果要按数据集或模态筛选序列,请使用 sql_query()。

patients = client.get_patients('nsclc_radiomics', outputFormat='df')
print("patients:", patients.shape, list(patients.columns)[:5])

# Walk down the hierarchy from one patient
pid = patients["PatientID"].iloc[0]
studies = client.get_dicom_studies(pid, outputFormat='df')
print("studies for", pid, ":", studies.shape)

study_uid = studies["StudyInstanceUID"].iloc[0]
series = client.get_dicom_series(study_uid, outputFormat='df')
print("series in study:", series.shape, "modalities:", series["Modality"].unique().tolist())
模块 4:download_from_selection(现代下载方式)

推荐的下载方法。可接受 collection_id、patientId、studyInstanceUID、seriesInstanceUID、sopInstanceUID 或 crdc_series_uuid 的任意组合(每个参数均可为字符串或列表)。筛选条件按顺序应用。使用 dry_run=True 可在下载数据前估算队列大小。文件会保存到 dirTemplate 下(默认:%collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID)。

import tempfile, glob, os

# Pick the smallest CT series for a fast smoke test (about 40 MB)
df = client.sql_query("""
    SELECT SeriesInstanceUID FROM index
    WHERE collection_id = 'nsclc_radiomics' AND Modality = 'CT'
    ORDER BY series_size_MB ASC LIMIT 1
""")
uid = df["SeriesInstanceUID"].iloc[0]

out = tempfile.mkdtemp(prefix='idc_dl_')
client.download_from_selection(
    downloadDir=out,
    seriesInstanceUID=[uid],
    quiet=True,
    show_progress_bar=False,
    source_bucket_location='aws',  # 'aws' (default) or 'gcs'
)
files = glob.glob(os.path.join(out, "**/*.dcm"), recursive=True)
print(f"downloaded {len(files)} DICOM files to {out}")
# Size a cohort before downloading
client.download_from_selection(
    downloadDir='./preview',
    collection_id='nsclc_radiomics',
    dry_run=True,
)
模块 5:download_dicom_series(便捷封装函数)

下载单个序列。内部会调用 download_from_selection(seriesInstanceUID=...)。接受字符串或 UID 列表。

import tempfile, glob, os
out = tempfile.mkdtemp(prefix='idc_dl_')
client.download_dicom_series(
    seriesInstanceUID=uid,            # string or list
    downloadDir=out,
    quiet=True,
    show_progress_bar=False,
)
print("files:", len(glob.glob(os.path.join(out, "**/*.dcm"), recursive=True)))
模块 6:get_viewer_URL(浏览器可视化)

返回 IDC OHIF(放射学)或 Slim(切片显微镜)查看器的可分享 URL。如果省略 viewer_selector,则根据模态自动选择查看器。

url = client.get_viewer_URL(seriesInstanceUID=uid)
print("Open in browser:", url)

# Force a specific viewer
url_v2 = client.get_viewer_URL(seriesInstanceUID=uid, viewer_selector='ohif_v2')
print(url_v2)
模块 7:使用 pydicom 检查已下载的 DICOM

下载后,文件会按 dirTemplate 组织。使用 pydicom 检查头信息和像素。

import pydicom, glob, os
dcm_files = sorted(glob.glob(os.path.join(out, "**/*.dcm"), recursive=True))
ds = pydicom.dcmread(dcm_files[0])
print("PatientID:", ds.PatientID)
print("Modality :", ds.Modality)
print("Rows x Cols:", ds.Rows, "x", ds.Columns)
print("Pixel array:", ds.pixel_array.shape)

核心概念

本地优先、无需身份验证的架构

IDC 客户端有些特别:client = IDCClient() 完全离线即可执行查询。parquet 索引(数百 MB,随 idc-index-data 一同提供)会读入内存,并注册为名为 index 的 DuckDB 表。每个 sql_query()、get_collections()、get_patients() 等操作都是本地 pandas/DuckDB 操作。只有在执行 download_from_selection() / download_dicom_series() 时才会产生网络流量;这些操作会调用内置的 s5cmd 可执行文件,从公共存储桶复制数据(默认使用 s3://idc-open-data/...;通过 source_bucket_location=gcs 切换到 gcs)。因此无需 gcloud 身份验证、GCP 项目 ID、BigQuery 计费或 API 密钥。

DICOM 层级和标识符

IDC 遵循标准的 DICOM 模型:Collection(collection_id,小写并使用下划线,例如 nsclc_radiomics)-> Patient(PatientID)-> Study(StudyInstanceUID)-> Series(SeriesInstanceUID)-> Instance(SOPInstanceUID)。默认情况下,下载以 series 为单位进行。crdc_series_uuid 是一种替代的不可变标识符,适合长期引用。

版本控制

索引固定为已安装的 idc-index-data 包版本(client.get_idc_version(),例如 v24)。为确保可复现性,请在环境中固定 idc-index 和 idc-index-data 的版本。较旧版本仍可通过 sql_query() 中的 prior_versions_index 表访问。

常见工作流

工作流 1:队列选择 -> 清单 -> 下载

目标:构建包含小型 CT series 的 CSV 清单,用于 ML 原型开发,然后下载这些数据。

from idc_index import IDCClient
import pandas as pd, tempfile, os, glob

client = IDCClient()

# Step 1: SQL cohort: small CTs across three lung collections
cohort = client.sql_query("""
    SELECT SeriesInstanceUID, PatientID, collection_id, Modality, series_size_MB
    FROM index
    WHERE collection_id IN ('nsclc_radiomics', 'tcga_luad', 'tcga_lusc')
      AND Modality = 'CT'
      AND series_size_MB < 60
    ORDER BY series_size_MB ASC
""")
print(f"Cohort: {len(cohort)} series, total {cohort['series_size_MB'].sum():.1f} MB")

# Step 2: Save manifest
cohort.to_csv('ct_lung_manifest.csv', index=False)

# Step 3: Download a small subset
out = tempfile.mkdtemp(prefix='idc_cohort_')
client.download_from_selection(
    downloadDir=out,
    seriesInstanceUID=cohort["SeriesInstanceUID"].head(2).tolist(),
    quiet=True,
    show_progress_bar=False,
)
print("downloaded", len(glob.glob(os.path.join(out, "**/*.dcm"), recursive=True)), "files")
工作流 2:检查单个患者的层级信息

目标:无需编写 SQL,即可从 collection -> patient -> studies -> series 深入查看 DICOM 头信息。

from idc_index import IDCClient
import tempfile, glob, os, pydicom

client = IDCClient()

# Pick first patient in the collection
patients = client.get_patients('nsclc_radiomics', outputFormat='df')
pid = patients["PatientID"].iloc[0]

studies = client.get_dicom_studies(pid, outputFormat='df')
series_df = client.get_dicom_series(studies["StudyInstanceUID"].iloc[0], outputFormat='df')
print(f"Patient {pid}: {len(studies)} studies, {len(series_df)} series in first study")
print("modalities:", series_df["Modality"].unique().tolist())

# Pick the smallest image series (CT/MR, not SR/SEG) and download
imaging = series_df[series_df["Modality"].isin(["CT", "MR", "PT"])]
target_uid = imaging.sort_values("series_size_MB").iloc[0]["SeriesInstanceUID"]
out = tempfile.mkdtemp(prefix='idc_one_')
client.download_dicom_series(seriesInstanceUID=target_uid, downloadDir=out,
                             quiet=True, show_progress_bar=False)

ds = pydicom.dcmread(sorted(glob.glob(os.path.join(out, "**/*.dcm"), recursive=True))[0])
print("first slice:", ds.Modality, ds.pixel_array.shape)
print("viewer:", client.get_viewer_URL(seriesInstanceUID=target_uid))

关键参数

参数模块 / 函数默认值范围 / 选项效果
outputFormatget_patients / get_dicom_studies / get_dicom_seriesdictdict, df, list访问器方法的返回类型
seriesInstanceUIDdownload_from_selection / download_dicom_seriesNonestr 或 list[str]按 DICOM SeriesInstanceUID 筛选
collection_iddownload_from_selection / get_patientsNone / 必需小写字符串,例如 nsclc_radiomics按 collection 筛选(小写,使用下划线)
source_bucket_locationdownload_from_selection / download_dicom_seriesawsaws, gcs用于拉取数据的公共存储桶
dirTemplatedownload_from_selection%collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID使用 %- 前缀 DICOM 标签的模板字符串;若为 None,则使用平面布局磁盘上的文件夹层级
dry_rundownload_from_selection / download_dicom_seriesFalseTrue/False计算队列大小,但不下载
use_s5cmd_syncdownload_from_selection / download_dicom_seriesFalseTrue/False使用 s5cmd sync(续传部分下载内容)代替 cp
viewer_selectorget_viewer_URLNone(自动)ohif_v2, ohif_v3, slim强制使用指定的浏览器查看器

最佳实践

  1. 除单个层级步骤以外的所有筛选都使用 sql_query():它会返回 DataFrame,通过 DuckDB 可即时扩展到完整的约 1000 万行索引,并支持任意 DICOM 标签。只有在已知父级 UID 时,才使用 get_patients / get_dicom_studies / get_dicom_series。

  2. 始终对大型队列进行试运行:调用 download_from_selection(..., dry_run=True) 会在传输任何字节之前显示总大小。像 lidc_idri 这样的小型数据集约为 120 GB,而 nlst 超过 10 TB。

  3. 固定 idc-index 和 idc-index-data 的版本:索引版本决定了可复现性。在数据集说明或论文方法部分记录 client.get_idc_version()(例如 v24)。

  4. 大多数下载优先使用 AWS:source_bucket_location=aws 是默认设置,从大多数高校网络访问时速度最快。只有在与存储桶同区域的 GCP 计算环境中运行时,才切换到 gcs。

  5. 不要默认使用旧版 BigQuery 流程:bigquery-public-data.idc_current.dicom_all 仍然可用,但需要 GCP 身份验证和计费,且已不再是推荐方式。一个可选示例见 Recipes。

常见示例

示例:跨模态患者队列(同一患者的 CT 和 MR)

适用场景:构建一个要求每位患者都具有两种模态的多模态研究。

df = client.sql_query("""
    SELECT PatientID
    FROM index
    WHERE collection_id = 'tcga_gbm'
    GROUP BY PatientID
    HAVING SUM(CASE WHEN Modality = 'CT' THEN 1 ELSE 0 END) > 0
       AND SUM(CASE WHEN Modality = 'MR' THEN 1 ELSE 0 END) > 0
""")
print(f"Patients with both CT and MR in TCGA-GBM: {len(df)}")
示例:批量生成用于 QA 的查看器 URL

适用场景:向协作者发送一份待目视检查的系列影像清单。

sample = client.sql_query("""
    SELECT SeriesInstanceUID, Modality
    FROM index WHERE collection_id = 'lidc_idri' AND Modality = 'CT'
    LIMIT 5
""")
for _, row in sample.iterrows():
    print(row.Modality, client.get_viewer_URL(seriesInstanceUID=row.SeriesInstanceUID))
示例:可选进阶用法(使用 BigQuery 进行跨数据集联接)

适用场景:需要将 IDC 元数据与另一个 BigQuery 公共数据集联接(例如 TCGA 临床数据),并且已配置好带计费的 GCP 项目。其他所有场景都优先使用 sql_query()。

# Requires: a google-cloud-bigquery install and gcloud application-default credentials.
from google.cloud import bigquery
bq = bigquery.Client(project='your-gcp-project-id')
df = bq.query("""
    SELECT collection_id, Modality, COUNT(DISTINCT SeriesInstanceUID) AS n
    FROM `bigquery-public-data.idc_current.dicom_all`
    WHERE Modality IN ('CT', 'MR', 'PET')
    GROUP BY collection_id, Modality
    ORDER BY n DESC LIMIT 20
""").to_dataframe()
print(df)

故障排除

问题原因解决方案
ImportError: No module named idc_index未安装软件包运行 pip install idc-index(无需设置身份验证)
首次调用 IDCClient() 很慢正在将 parquet 索引加载到内存(1-3 s,每个进程仅一次)在多次查询间复用客户端;不要每次调用都重新实例化
sql_query: Catalog Error: Table idc_index does not exist表名错误DuckDB 表名为 index,而不是 idc_index 或 dicom_all
get_dicom_series(collection_id=..., modality=...) 引发 TypeErrorAPI 已过时;此函数签名已移除改用带有 WHERE collection_id 和 Modality 筛选条件的 sql_query
download_from_selection 因 s5cmd: command not found 出错随附的 s5cmd 不在 PATH 中重新安装 idc-index;wheel 中包含 s5cmd。在 NixOS/非 glibc 系统上,将 IDC_INDEX_S5CMD_EXE 设置为系统 s5cmd
下载停滞或速度很慢网络瓶颈,而非身份验证问题如果使用 GCP,尝试设置 source_bucket_location=gcs;否则使用 use_s5cmd_sync=True 以便恢复传输
ValueError: collection_id ... does not existCollection ID 区分大小写,并使用下划线使用小写字母和下划线:lidc_idri,而不是 LIDC-IDRI;检查 client.get_collections()
pydicom 无法读取像素数据传输语法已压缩安装 pylibjpeg、pylibjpeg-libjpeg、gdcm,然后重试 ds.pixel_array

相关技能

  • pydicom-medical-imaging - 读取、编辑和匿名化从 IDC 下载的 DICOM 文件
  • histolab-wsi-processing - 为全切片图像(IDC SM 模态)生成图块并进行染色归一化
  • pathml - 用于计算病理学的端到端 ML 流水线,可处理 IDC 切片集合

参考资料

评论

支持 Markdown