Que fait pydicom ?
Utilisez pydicom pour les entrées/sorties de jeux de données DICOM et le traitement des pixels. La version 3.0.2 est la version stable actuelle examinée ici. Elle corrige CVE-2026-32711, un problème de traversée de chemin dans DICOMDIR. pydicom 3.0.2 déclare Python >=3.10 ; son dictionnaire DICOM intégré est 2024c, tandis que le standard DICOM actuel peut être plus récent.
Limite de sécurité obligatoire
- Travaillez uniquement avec des données locales que l'utilisateur est autorisé à consulter.
- Les métadonnées DICOM, noms de fichiers, éléments privés, superpositions, contenu structuré et pixels peuvent contenir des informations de santé protégées (PHI).
- N'imprimez jamais un
Dataset, n'exportez pas de métadonnées/JSON complètes, et ne journalisez pas les valeurs d'éléments par défaut. Utilisez une liste blanche documentée et une sortie agrégée. - pydicom est un framework DICOM général, pas un visualiseur diagnostique. Les sorties de pixels, la validation, la conversion et la disponibilité des plugins ne sont pas des revendications diagnostiques.
- La désidentification est spécifique au profil, à l'objectif, au destinataire, à la juridiction et au contexte de menace. Elle nécessite une vérification par un expert en confidentialité/DICOM.
- Ne prétendez jamais qu'un script de suppression de balises est conforme à DICOM PS3.15, HIPAA, GDPR ou autre réglementation. Conservez les originaux et auditez les sorties dérivées.
- Traitez les clés de pseudonymisation déterministes et les mappages d'UID comme des secrets de ré-identification : utilisez le moindre privilège et un stockage de secrets chiffré/géré, ne les validez, ne les synchronisez, ne les journalisez et ne les partagez jamais avec des dérivés, et définissez des procédures de sauvegarde, rotation, révocation et destruction. Une clé divulguée invalide la séparation prévue ; la rotation change également les mappages déterministes.
- Définissez des limites explicites de fichier d'entrée, nombre de fichiers, nombre de trames, d'octets décodés et de sortie avant d'analyser des jeux de données non fiables ou inhabituellement volumineux.
Installation
Créez ou activez un environnement isolé, puis installez la version exacte examinée :
uv pip install "pydicom==3.0.2"
Tableaux de pixels non compressés et rendu d'image :
uv pip install "pydicom==3.0.2" "numpy==2.5.1" "Pillow==12.3.0"
Installez uniquement les plugins de syntaxe de transfert requis par le déploiement :
# JPEG/JPEG-LS, JPEG 2000/HTJ2K, et RLE plus rapide via pylibjpeg
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"
# Encodeur/décodeur JPEG-LS
uv pip install "numpy==2.5.1" "pyjpegls==1.5.1"
# Décodeur alternatif avec wheels spécifiques à la plateforme
uv pip install "python-gdcm==3.2.6"
Les licences des plugins et les wheels diffèrent selon le paquet/la plateforme ; examinez-les avant le déploiement. Pillow a des limitations de décodage documentées et pydicom avertit que la sortie du plugin doit être vérifiée indépendamment.
Les wheels de codecs natifs élargissent la chaîne d'approvisionnement et la limite de sécurité mémoire. Pour un déploiement contrôlé, résolvez ces versions exactes sur un hôte de build de confiance, verrouillez et vérifiez les hachages/provenances des wheels, mettez en miroir les artefacts approuvés en interne, scannez-les et installez avec validation de hachage plutôt que de résoudre à partir de l'index public à l'exécution.
Choisissez le flux de travail
- Besoin d'un aperçu agrégé : exécutez
scripts/extract_metadata.py. - Besoin de vérifications techniques encadrées : exécutez
scripts/dicom_inventory.py. - Besoin d'une pré-vérification de déploiement de codec : exécutez
scripts/transfer_syntax_inspector.py. - Besoin d'une planification de trame/mémoire : exécutez
scripts/pixel_frame_planner.py. - Besoin d'une trame rendue non diagnostique : exécutez
scripts/dicom_to_image.py. - Besoin d'un dérivé pseudonymisé : lisez la section sur la désidentification, créez un profil d'action examiné par le site, puis exécutez
scripts/anonymize_dicom.pyetscripts/deidentification_audit.py. - Besoin de vérifier un mappage d'UID sensible : exécutez
scripts/uid_mapping_validator.py.
Lire les jeux de données en toute sécurité
dcmread() renvoie un FileDataset, une sous-classe de Dataset avec l'état du Format de fichier tel que file_meta, le préambule et l'encodage d'origine.
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"),
}
Utilisez :
stop_before_pixels=Truepour un travail uniquement sur les métadonnées.specific_tags=[...]pour une liste blanche minimale.defer_size="1 MiB"lorsqu'une écriture ultérieure doit préserver les grandes valeurs.force=False(par défaut).force=Truecontourne uniquement la vérification de l'en-tête du Format de fichier ; cela ne prouve pas que les octets sont un DICOM valide.
N'appelez pas print(ds), repr(ds) et n'itérez pas les valeurs dans les journaux sur des données cliniques.
Dataset, DataElement et séquences
Accédez aux éléments standards par mot-clé et vérifiez leur absence :
modality = ds.get("Modality", "UNSPECIFIED")
if "ReferencedImageSequence" in ds:
for item in ds.ReferencedImageSequence:
referenced_class = item.get("ReferencedSOPClassUID")
L'accès par balise, par exemple ds[0x0010, 0x0010], renvoie un DataElement ; sa valeur .value est distincte. Sequence se comporte comme une liste d'éléments Dataset imbriqués. Les actions de confidentialité doivent parcourir chaque élément de séquence, pas seulement le niveau supérieur.
Lors de la création d'un fichier, utilisez FileMetaDataset pour le groupe 0002, maintenez la cohérence des UID SOP du dataset et du fichier-méta, définissez un UID de syntaxe de transfert et écrivez dans un Format de fichier imposé :
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
# Ajoutez tous les attributs requis par l'IOD sélectionnée avant l'écriture.
dcmwrite("new.dcm", ds, enforce_file_format=True, overwrite=False)
write_like_original est obsolète dans pydicom 3.0 ; utilisez enforce_file_format. Une écriture réussie ne constitue pas une conformité complète à l'IOD PS3.3.
UIDs et syntaxe de transfert
L'UID de syntaxe de transfert des Informations méta du fichier contrôle l'encodage du jeu de données et la compression des pixels :
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 choisit l'encodage d'écriture à partir de l'UID de syntaxe de transfert avant les indicateurs de dataset hérités. Ne remplacez pas les UIDs structurels (Syntaxe de transfert, Classe SOP ou UIDs de système de codage) lors de la pseudonymisation. Le remplacement des UIDs d'instance/référence doit être un-à-un et cohérent sur l'ensemble du périmètre déclaré.
Lisez references/transfer_syntaxes.md avant la compression, la décompression ou l'encapsulation.
Données pixels et trames
L'API stable pydicom.pixels prend en charge le décodage basé sur le chemin et spécifique à la trame :
from pydicom.pixels import pixel_array
# Lit uniquement la trame sélectionnée là où la source le permet.
frame = pixel_array("authorized/image.dcm", index=0, raw=False)
Sémantique de forme :
- une seule trame en niveaux de gris :
(rows, columns) - plusieurs trames en niveaux de gris :
(frames, rows, columns) - une seule trame couleur :
(rows, columns, samples) - plusieurs trames couleur :
(frames, rows, columns, samples)
raw=False convertit les pixels YCbCr en RVB lorsque c'est possible ; raw=True conserve l'espace colorimétrique décodé après un traitement minimal obligatoire. Utilisez iter_pixels(path, indices=[...]) pour une itération limitée sur plusieurs trames.
Pour l'affichage en niveaux de gris, appliquez les transformations dans cet ordre :
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)
La LUT/reescalade de modalité et la LUT/fenêtrage VOI modifient la sémantique d'affichage/de valeur. MONOCHROME1 peut nécessiter une inversion de présentation. La palette de couleurs nécessite apply_color_lut(). Les états de présentation et le comportement ICC peuvent nécessiter un visualiseur validé. N'utilisez jamais la normalisation min/max par trame pour une analyse quantitative.
Compression, décompression et encapsulation
- L'accès à
pixel_arraydécode si nécessaire mais ne modifie pas le jeu de données. Dataset.decompress()modifie les données pixels sur place, définit Explicit VR Little Endian, met à jour les métadonnées d'image et génère un nouvel UID d'instance SOP par défaut.Dataset.compress(uid)modifie les données pixels et la syntaxe de transfert sur place et génère un nouvel UID d'instance SOP par défaut.- Les codeurs intégrés/trouvés de pydicom 3.0 couvrent les combinaisons RLE Lossless, JPEG-LS et JPEG 2000 documentées dans la matrice de plugins stable.
- Chaque trame compressée est encodée séparément puis encapsulée. Utilisez
encapsulate()ouencapsulate_extended()pour les trames encodées en externe. - Lisez les trames avec
pydicom.encaps.generate_frames()ouget_frame()actuel ; les noms de générateurs d'encapsulation hérités sont obsolètes pour pydicom 4.
Inspectez toujours les capacités en premier, limitez les octets/trames décodés et vérifiez l'exactitude des pixels indépendamment. L'acceptabilité de la compression avec perte est en dehors de la spécification pydicom et DICOM.
JSON DICOM et éléments privés
Dataset.to_json(), to_json_dict() et Dataset.from_json() implémentent le modèle JSON DICOM, mais pydicom documente le support JSON comme étant en version bêta. Le JSON complet peut intégrer des données binaires et exposer chaque identifiant et charge utile de pixels. Ne l'émettez pas comme rapport de métadonnées. Un gestionnaire BulkDataURI introduit des obligations distinctes de stockage, d'autorisation et de récupération.
Les éléments privés ne sont pas standardisés et peuvent contenir des PHI :
# Suppression récursive, mais pas une désidentification suffisante en soi.
ds.remove_private_tags()
Conservez les éléments privés uniquement sous une politique explicite de données privées sûres et examinée. Lisez references/common_tags.md pour l'accès aux balises, les classes de confidentialité et les pointeurs standards.
Flux de travail de désidentification
L'annexe E de DICOM PS3.15 indique explicitement que les profils de confidentialité ne garantissent pas la suppression de toutes les informations d'identification et ne remplacent pas un processus de désidentification complet.
- Définissez l'objectif, les destinataires, les besoins de liaison, les réglementations, le modèle de menace et le risque de ré-identification acceptable.
- Sélectionnez le profil de confidentialité de base au niveau de l'application et les options nécessaires (pixels, caractéristiques visuelles reconnaissables, graphiques, contenu structuré, descripteurs, informations temporelles, caractéristiques du patient, dispositifs, institutions, UIDs et données privées sûres).
- Conservez les objets source inchangés dans un stockage contrôlé.
- Appliquez chaque action de manière récursive, y compris les séquences imbriquées.
- Remplacez les UIDs d'instance/référence de manière cohérente sur l'ensemble du périmètre ; préservez les UIDs structurels.
- Décidez explicitement du traitement de la date/heure. Un décalage fixe peut préserver les intervalles, mais les dates partielles, les fuseaux horaires, les heures isolées, les jours bissextiles, la liaison longitudinale et les événements externes nécessitent une politique examinée.
- Inspectez les pixels, superpositions, graphiques, contenu structuré et caractéristiques visuelles reconnaissables. N'inférez pas de pixels propres à partir de métadonnées manquantes et ne définissez pas
BurnedInAnnotation=NOsans vérification. - Reconstruisez les Informations méta du fichier et le préambule pour éviter les fuites.
- Effectuez une validation technique et un audit de désidentification, puis une vérification par un expert et une revue des risques documentée.
Le script fourni définit intentionnellement PatientIdentityRemoved à NO car il ne peut pas établir une désidentification réussie.
CLI d'aide
Tous les chemins --help sont sans dépendances. Les outils n'effectuent aucun accès réseau et n'émettent aucune valeur DICOM au-delà de listes blanches techniques étroites.
Le contenu fourni se compose des deux références liées, des scripts d'aide documentés et des tests synthétiques. La dépendance d'exécution pydicom est installée à partir de la version PyPI épinglée.
# Métadonnées agrégées expurgées
python scripts/extract_metadata.py authorized/ --recursive
# Inventaire technique uniquement sur les métadonnées
python scripts/dicom_inventory.py authorized/ --recursive
# Capacités du codec/plugin installé
python scripts/transfer_syntax_inspector.py --input authorized/image.dcm
# Plan de forme, d'octets et de transformation de trame
python scripts/pixel_frame_planner.py authorized/image.dcm --frames 0,2-4
# Une trame non diagnostique
python scripts/dicom_to_image.py authorized/image.dcm frame.png \
--acknowledge-pixel-phi
# Créez une clé secrète, puis un dérivé pseudonymisé limité plus un audit
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
# Auditez les métadonnées candidates ; aucune décompression de pixels
python scripts/deidentification_audit.py derived/out.dcm
# Validez un mappage d'UID sensible explicitement demandé
python scripts/uid_mapping_validator.py derived/uid-map.json \
--uid-key-file project.key --uid-scope export-v1
Le fichier de clé brute généré est une commodité locale contrôlée et est créé avec des permissions propriétaire uniquement. En production, matérialisez les octets de clé à partir d'un gestionnaire de secrets approuvé dans un fichier éphémère verrouillé, limitez l'accès au service de désidentification et supprimez-le en toute sécurité après utilisation. Stockez tout mappage d'UID optionnel séparément des dérivés ; il lie directement les identifiants d'origine et de remplacement.
Notes de migration pydicom 3.0
read_file()etwrite_file()ont été supprimés ; utilisezdcmread()etdcmwrite().write_like_originalest obsolète ; utilisezenforce_file_format.pydicom.pixel_data_handlersest obsolète et sera supprimé dans v4 ; utilisezpydicom.pixels.Dataset.pixel_arrayutilise le nouveau backend de pixels par défaut et convertit YCbCr en RVB lorsque c'est possible.JPEGLosslesssignifie désormais UID1.2.840.10008.1.2.4.57;JPEGLosslessSV1est.70.Dataset.is_little_endianetis_implicit_VRsont obsolètes pour v4.
Sources (vérifié le 2026-07-23)
- pydicom 3.0.2 sur PyPI — publié le 2026-07-23.
…
[truncated for translation]