pydicom 是做什麼的?
使用 pydicom 進行 DICOM 資料集的輸入/輸出 (I/O) 和像素處理。此處審查的當前穩定版本為 3.0.2。它修復了 CVE-2026-32711,這是一個精心製作的 DICOMDIR 路徑遍歷問題。pydicom 3.0.2 聲明需要 Python >=3.10;其內建的 DICOM 字典版本為 2024c,而現行的 DICOM 標準可能更新。
強制性安全邊界
- 僅限於處理使用者有權存取的本機資料。
- DICOM 元資料、檔案名稱、私有元素、覆蓋圖、結構化內容和像素可能包含受保護的健康資訊 (PHI)。
- 預設情況下,絕不列印
Dataset、匯出完整元資料/JSON,或將元素值記錄到日誌中。應使用已記錄的允許清單和彙總輸出。 - pydicom 是一個通用的 DICOM 框架,而非診斷檢視器。像素輸出、驗證、轉換和外掛程式的可用性不構成診斷聲明。
- 去識別化是針對特定設定檔、目的、接收者、管轄區域和威脅情境而定。需要隱私/DICOM 專家的驗證。
- 絕不聲稱標籤移除腳本符合 DICOM PS3.15、HIPAA、GDPR 或其他法規。應保留原始檔案並稽核衍生輸出。
- 將確定性的假名化金鑰和 UID 映射視為重新識別機密:採用最小權限原則和加密/受管機密儲存,絕不將其提交、同步、記錄或與衍生檔共用,並定義備份、輪換、撤銷和銷毀程序。洩露的金鑰會使預期的隔離失效;輪換也會改變確定性的映射關係。
- 在解析不受信任或異常大的資料集之前,設置明確的輸入檔案、檔案數量、影格數量、解碼位元組和輸出限制。
安裝
建立或啟用一個隔離環境,然後安裝經過審查的確定版本:
uv pip install "pydicom==3.0.2"
未壓縮的像素陣列和影像渲染:
uv pip install "pydicom==3.0.2" "numpy==2.5.1" "Pillow==12.3.0"
僅安裝部署所需的傳輸語法外掛程式:
# 透過 pylibjpeg 支援 JPEG/JPEG-LS、JPEG 2000/HTJ2K 和更快的 RLE
uv pip install "numpy==2.5.1" "pylibjpeg==2.1.0" \
"pylibjpeg-libjpeg==2.4.0" "pylibjpeg-openjpeg==2.5.0" \
"pylibjpeg-rle==2.2.0"
# JPEG-LS 編碼器/解碼器
uv pip install "numpy==2.5.1" "pyjpegls==1.5.1"
# 備用解碼器,提供特定平台的 wheel 套件
uv pip install "python-gdcm==3.2.6"
外掛程式的授權條款和 wheel 套件因套件/平台而異;請在部署前進行審查。Pillow 存在已知的解碼限制,且 pydicom 提醒必須獨立檢查外掛程式的輸出。
原生編解碼器的 wheel 套件會擴大供應鏈和記憶體安全的邊界。對於受控部署,請在可信的建置主機上解析這些確定的版本鎖定,鎖定並驗證 wheel 套件的雜湊/來源,將經批准的工件鏡像到內部環境,對其進行掃描,並透過雜湊強制執行來安裝,而不是在執行時期從公開索引解析。
選擇工作流程
- 需要彙總概覽:執行
scripts/extract_metadata.py。 - 需要有限制的技術檢查:執行
scripts/dicom_inventory.py。 - 需要編解碼器部署預檢:執行
scripts/transfer_syntax_inspector.py。 - 需要影格/記憶體規劃:執行
scripts/pixel_frame_planner.py。 - 需要一個非診斷的渲染影格:執行
scripts/dicom_to_image.py。 - 需要一個假名化的衍生檔:閱讀去識別化章節,建立一個經站點審查的行動設定檔,然後依序執行
scripts/anonymize_dicom.py和scripts/deidentification_audit.py。 - 需要檢查一個敏感的 UID 映射:執行
scripts/uid_mapping_validator.py。
安全地讀取資料集
dcmread() 會回傳一個 FileDataset,它是 Dataset 的子類別,包含檔案格式的狀態,例如 file_meta、前導碼和原始編碼。
from pathlib import Path
import pydicom
path = Path("authorized/input.dcm")
ds = pydicom.dcmread(
path,
stop_before_pixels=True,
specific_tags=[
"SOPClassUID",
"Modality",
"Rows",
"Columns",
"NumberOfFrames",
],
)
technical = {
"sop_class": ds.get("SOPClassUID"),
"modality": ds.get("Modality"),
"rows": ds.get("Rows"),
"columns": ds.get("Columns"),
}
使用:
stop_before_pixels=True用於僅處理元資料。specific_tags=[...]用於最小允許清單。defer_size="1 MiB"用於後續寫入時必須保留的大數值。force=False(預設值)。force=True僅繞過檔案格式標頭檢查;它並不證明位元組是有效的 DICOM。
不要對臨床資料呼叫 print(ds)、repr(ds) 或將值迭代到日誌中。
Dataset、DataElement 和序列
透過關鍵字存取標準元素並檢查是否存在:
modality = ds.get("Modality", "UNSPECIFIED")
if "ReferencedImageSequence" in ds:
for item in ds.ReferencedImageSequence:
referenced_class = item.get("ReferencedSOPClassUID")
透過標籤存取,例如 ds[0x0010, 0x0010],會回傳一個 DataElement;其 .value 是分開的。Sequence 的行為類似於一個巢狀 Dataset 項目的列表。隱私操作必須遞迴到每個序列項目中,而不僅是頂層。
建立檔案時,使用 FileMetaDataset 處理群組 0002,保持資料集和檔案元資料的 SOP UID 一致,設定傳輸語法 UID,並以強制檔案格式寫入:
from pydicom import dcmwrite
from pydicom.dataset import FileDataset, FileMetaDataset
from pydicom.uid import CTImageStorage, ExplicitVRLittleEndian, generate_uid
meta = FileMetaDataset()
meta.MediaStorageSOPClassUID = CTImageStorage
meta.MediaStorageSOPInstanceUID = generate_uid()
meta.TransferSyntaxUID = ExplicitVRLittleEndian
ds = FileDataset(None, {}, file_meta=meta, preamble=b"\0" * 128)
ds.SOPClassUID = meta.MediaStorageSOPClassUID
ds.SOPInstanceUID = meta.MediaStorageSOPInstanceUID
# 在寫入前,新增所選 IOD 要求的所有屬性。
dcmwrite("new.dcm", ds, enforce_file_format=True, overwrite=False)
write_like_original 在 pydicom 3.0 中已被棄用;請使用 enforce_file_format。成功的寫入不等於完整的 PS3.3 IOD 符合性。
UID 和傳輸語法
檔案元資訊傳輸語法 UID 控制資料集編碼和像素壓縮:
ts = ds.file_meta.TransferSyntaxUID
summary = {
"uid": str(ts),
"name": ts.name,
"compressed": ts.is_compressed,
"implicit_vr": ts.is_implicit_VR,
"little_endian": ts.is_little_endian,
}
pydicom 3.0 在傳統資料集標誌之前,從傳輸語法 UID 選擇寫入編碼。在假名化過程中,不要取代結構性 UID(傳輸語法、SOP 類別或編碼方案 UID)。實例/參考 UID 的替換必須是一對一的,並且在完整的宣告範圍內保持一致。
在進行壓縮、解壓縮或封裝之前,請閱讀 references/transfer_syntaxes.md。
像素資料和影格
穩定的 pydicom.pixels API 支援基於路徑、特定影格解碼:
from pydicom.pixels import pixel_array
# 僅讀取來源允許的選定影格。
frame = pixel_array("authorized/image.dcm", index=0, raw=False)
形狀語意:
- 灰階單影格:
(rows, columns) - 灰階多影格:
(frames, rows, columns) - 彩色單影格:
(rows, columns, samples) - 彩色多影格:
(frames, rows, columns, samples)
raw=False 會在可能的情況下將 YCbCr 像素資料轉換為 RGB;raw=True 則在執行必要的極簡處理後保留解碼後的色彩空間。使用 iter_pixels(path, indices=[...]) 進行有界限的多影格迭代。
對於灰階顯示,請按此順序套用轉換:
from pydicom.pixels import apply_modality_lut, apply_voi_lut
modality_values = apply_modality_lut(frame, ds)
display_values = apply_voi_lut(modality_values, ds, index=0)
模態 LUT/重新縮放和 VOI/窗寬窗位會改變顯示/數值語意。MONOCHROME1 可能需要反轉顯示。調色盤色彩需要 apply_color_lut()。表現狀態和 ICC 行為可能需要經過驗證的檢視器。絕不要使用逐影格的最小/最大正規化進行定量分析。
壓縮、解壓縮和封裝
- 存取
pixel_array會視需要進行解碼,但不會改變資料集。 Dataset.decompress()會就地更改像素資料,設定 Explicit VR Little Endian,更新影像元資料,並預設產生一個新的 SOP 實例 UID。Dataset.compress(uid)會就地更改像素資料和傳輸語法,並預設產生一個新的 SOP 實例 UID。- pydicom 3.0 內建/找到的編碼器涵蓋穩定的外掛程式矩陣中記錄的 RLE Lossless、JPEG-LS 和 JPEG 2000 組合。
- 每個壓縮影格會個別編碼,然後進行封裝。對於外部編碼的影格,請使用
encapsulate()或encapsulate_extended()。 - 使用當前的
pydicom.encaps.generate_frames()或get_frame()讀取影格;舊的封裝產生器名稱已在 pydicom 4 中棄用。
始終先檢查能力,限制解碼的位元組/影格,並獨立驗證像素的正確性。有損壓縮的可接受性不在 pydicom 和 DICOM 編碼規範的範圍內。
DICOM JSON 和私有元素
Dataset.to_json()、to_json_dict() 和 Dataset.from_json() 實作了 DICOM JSON 模型,但 pydicom 文件指出 JSON 支援仍處於測試階段。完整的 JSON 可能會內聯二進位資料並暴露每個識別碼和像素酬載。不要將其作為元資料報告發出。BulkDataURI 處理程式會引入單獨的儲存、授權和檢索義務。
私有元素未標準化,可能包含 PHI:
# 遞迴移除,但本身不足以去識別化。
ds.remove_private_tags()
僅在經過審查的明確安全私有政策下保留私有元素。請閱讀 references/common_tags.md 以了解標籤存取、隱私類別和標準指標。
去識別化工作流程
DICOM PS3.15 Annex E 明確指出,保密設定檔無法保證移除所有識別資訊,也無法取代完整的去識別化過程。
- 定義目的、接收者、連結需求、法規、威脅模型和可接受的重新識別風險。
- 選擇基本應用層級保密設定檔和所需的選項(像素、可識別的視覺特徵、圖形、結構化內容、描述子、時間資訊、患者特徵、設備、機構、UID 和安全私有資料)。
- 在受控儲存中保持原始物件不變。
- 遞迴套用每個動作,包括巢狀序列。
- 在完整範圍內一致地替換實例/參考 UID;保留結構性 UID。
- 明確決定日期/時間的處理方式。固定偏移可以保留間隔,但部分日期、時區、獨立時間、閏日、縱向連結和外部事件都需要經過審查的政策。
- 檢查像素、覆蓋圖、圖形、結構化內容和可識別的視覺特徵。不要因為缺少元資料就推斷像素乾淨,也不要在未經驗證的情況下設定
BurnedInAnnotation=NO。 - 重建檔案元資訊和前導碼以防止資訊洩漏。
- 執行技術驗證和去識別化稽核,然後進行專家驗證和記錄的風險審查。
內建腳本會刻意將 PatientIdentityRemoved 設定為 NO,因為它無法確定去識別化是否成功。
輔助 CLI 工具
所有 --help 路徑都是無依賴的。這些工具不執行任何網路存取,也不會發出超出狹義技術允許清單的 DICOM 值。
內建內容包含兩個連結的參考文件、記錄的輔助腳本和合成測試。pydicom 執行時期依賴項是從鎖定的 PyPI 版本安裝的。
# 修訂後的彙總元資料
python scripts/extract_metadata.py authorized/ --recursive
# 僅限元資料的技術清單
python scripts/dicom_inventory.py authorized/ --recursive
# 已安裝的編解碼器/外掛程式能力
python scripts/transfer_syntax_inspector.py --input authorized/image.dcm
# 影格形狀、位元組和轉換計畫
python scripts/pixel_frame_planner.py authorized/image.dcm --frames 0,2-4
# 一個非診斷影格
python scripts/dicom_to_image.py authorized/image.dcm frame.png \
--acknowledge-pixel-phi
# 建立一個密鑰,然後建立一個有範圍的假名化衍生檔及其稽核報告
python scripts/anonymize_dicom.py --generate-uid-key project.key
python scripts/anonymize_dicom.py authorized/in.dcm derived/out.dcm \
--uid-key-file project.key --uid-scope export-v1 \
--audit-report derived/out.audit.json
# 稽核候選元資料;不解壓像素
python scripts/deidentification_audit.py derived/out.dcm
# 驗證一個明確請求的敏感 UID 映射
python scripts/uid_mapping_validator.py derived/uid-map.json \
--uid-key-file project.key --uid-scope export-v1
產生的原始金鑰檔案是一種受控的本機便利功能,並以僅擁有者可讀取的權限建立。對於生產環境,請從批准的機密管理器中將金鑰位元組具體化到一個鎖定的臨時檔案中,限制只有去識別化服務可以存取,並在使用後安全地移除。將任何可選的 UID 映射與衍生檔分開儲存;它直接連結了原始和替代的識別碼。
pydicom 3.0 遷移注意事項
read_file()和write_file()已被移除;請使用dcmread()和dcmwrite()。write_like_original已被棄用;請使用enforce_file_format。pydicom.pixel_data_handlers已被棄用,將在 v4 中移除;請使用pydicom.pixels。Dataset.pixel_array預設使用新的像素後端,並在可能的情況下將 YCbCr 轉換為 RGB。JPEGLossless現在表示 UID1.2.840.10008.1.2.4.57;JPEGLosslessSV1表示.70。Dataset.is_little_endian和is_implicit_VR已在 v4 中棄用。
來源 (驗證日期:2026-07-23)
- pypi 上的 pydicom 3.0.2 — 發佈於 2026-06-09。
- pydicom 官方使用指南
- pydicom 3.0 遷移指南