pydicom は何をしますか?
pydicomを使用してDICOMデータセットのI/Oとピクセル処理を行います。ここでレビューする安定版リリースはバージョン3.0.2です。このバージョンは、巧妙に作成されたDICOMDIRによるパストラバーサル問題であるCVE-2026-32711を修正しています。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"
デプロイメントに必要な転送構文プラグインのみをインストールします。
# JPEG/JPEG-LS、JPEG 2000/HTJ2K、およびpylibjpegによる高速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"
# プラットフォーム固有のホイールを持つ代替デコーダー
uv pip install "python-gdcm==3.2.6"
プラグインのライセンスとホイールはパッケージ/プラットフォームによって異なります。デプロイ前にレビューしてください。Pillowには文書化されたデコード制限があり、pydicomはプラグインの出力を独立してチェックする必要があると注意しています。
ネイティブコーデックのホイールは、サプライチェーンとメモリ安全性の境界を広げます。管理されたデプロイメントでは、信頼できるビルドホストでこれらの正確なピンを解決し、ホイールのハッシュ/出所をロックして検証し、承認されたアーティファクトを内部的にミラーリングし、それらをスキャンし、実行時にパブリックインデックスから解決するのではなく、ハッシュ適用を有効にしてインストールしてください。
ワークフローの選択
- 集約概要が必要:
scripts/extract_metadata.pyを実行します。 - 限定された技術的チェックが必要:
scripts/dicom_inventory.pyを実行します。 - コーデックデプロイメントの事前チェックが必要:
scripts/transfer_syntax_inspector.pyを実行します。 - フレーム/メモリ計画が必要:
scripts/pixel_frame_planner.pyを実行します。 - 診断目的ではない1フレームのレンダリングが必要:
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 アイテムのリストのように動作します。プライバシーに関するアクションは、トップレベルだけでなく、すべてのシーケンスアイテムを再帰的に処理する必要があります。
ファイルを作成するときは、グループ 0002 に FileMetaDataset を使用し、データセットとファイルメタの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)
Modality 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ロスレス、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値を出力しません。
バンドルコンテンツは、リンクされた2つのリファレンス、文書化されたヘルパースクリプト、および合成テストで構成されています。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
# 診断目的ではない1フレーム
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 確認)
- pydicom 3.0.2 on PyPI — 2026年0月リリース …
[翻訳のため省略]