关于 imaging-data-commons
idc-index 是供研究人员筛选和下载 NCI Imaging Data Commons 公共癌症影像数据的 Python 客户端。内置元数据索引支持本地 DuckDB SQL 查询,影像可从公共 AWS 或 Google Cloud Storage 存储桶下载。
主要功能
- 01用 SQL 本地查询内置元数据
- 02浏览集合、患者、研究和序列
- 03按 DICOM 标识筛选下载内容
- 04下载前预估队列大小
- 05生成 OHIF 或 Slim 浏览器链接
适用场景
- 01按 DICOM 元数据筛选癌症影像队列
- 02构建可复现的机器学习研究队列
- 03下载指定 DICOM 序列进行处理
- 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))
关键参数
| 参数 | 模块 / 函数 | 默认值 | 范围 / 选项 | 效果 |
|---|---|---|---|---|
| outputFormat | get_patients / get_dicom_studies / get_dicom_series | dict | dict, df, list | 访问器方法的返回类型 |
| seriesInstanceUID | download_from_selection / download_dicom_series | None | str 或 list[str] | 按 DICOM SeriesInstanceUID 筛选 |
| collection_id | download_from_selection / get_patients | None / 必需 | 小写字符串,例如 nsclc_radiomics | 按 collection 筛选(小写,使用下划线) |
| source_bucket_location | download_from_selection / download_dicom_series | aws | aws, gcs | 用于拉取数据的公共存储桶 |
| dirTemplate | download_from_selection | %collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID | 使用 %- 前缀 DICOM 标签的模板字符串;若为 None,则使用平面布局 | 磁盘上的文件夹层级 |
| dry_run | download_from_selection / download_dicom_series | False | True/False | 计算队列大小,但不下载 |
| use_s5cmd_sync | download_from_selection / download_dicom_series | False | True/False | 使用 s5cmd sync(续传部分下载内容)代替 cp |
| viewer_selector | get_viewer_URL | None(自动) | ohif_v2, ohif_v3, slim | 强制使用指定的浏览器查看器 |
最佳实践
-
除单个层级步骤以外的所有筛选都使用 sql_query():它会返回 DataFrame,通过 DuckDB 可即时扩展到完整的约 1000 万行索引,并支持任意 DICOM 标签。只有在已知父级 UID 时,才使用 get_patients / get_dicom_studies / get_dicom_series。
-
始终对大型队列进行试运行:调用 download_from_selection(..., dry_run=True) 会在传输任何字节之前显示总大小。像 lidc_idri 这样的小型数据集约为 120 GB,而 nlst 超过 10 TB。
-
固定 idc-index 和 idc-index-data 的版本:索引版本决定了可复现性。在数据集说明或论文方法部分记录 client.get_idc_version()(例如 v24)。
-
大多数下载优先使用 AWS:source_bucket_location=aws 是默认设置,从大多数高校网络访问时速度最快。只有在与存储桶同区域的 GCP 计算环境中运行时,才切换到 gcs。
-
不要默认使用旧版 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=...) 引发 TypeError | API 已过时;此函数签名已移除 | 改用带有 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 exist | Collection 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 切片集合
参考资料
- idc-index GitHub - 源代码、README 和问题跟踪器(权威 API)
- PyPI 上的 idc-index - 最新版本
- learn.canceridc.dev - IDC 官方教程、笔记本和概念指南
- IDC 门户 - 用于浏览集合和查看器 URL 的浏览器界面
- IDC BigQuery 数据集 - 可选的高级/跨数据集 SQL(需要 GCP 结算)