Pydicom
Overview
Pydicom est un package Python pur pour travailler avec des fichiers DICOM, le format standard pour les données d'imagerie médicale. Cette skill fournit des orientations sur la lecture, l'écriture et la manipulation de fichiers DICOM, y compris le travail avec les données de pixels, les métadonnées et divers formats de compression.
Quand utiliser cette skill
Utilisez cette skill lors du travail avec :
- Des fichiers d'imagerie médicale (TDM, IRM, rayons X, échographie, TEP, etc.)
- Des datasets DICOM nécessitant l'extraction ou la modification de métadonnées
- L'extraction de données de pixels et le traitement d'images à partir de scans médicaux
- L'anonymisation DICOM pour la recherche ou le partage de données
- La conversion de fichiers DICOM en formats d'image standard
- Les données DICOM compressées nécessitant une décompression
- Les séquences DICOM et les rapports structurés
- La reconstruction de volumes multi-coupes
- L'intégration de PACS (Picture Archiving and Communication System)
Installation
Installez pydicom et les dépendances courantes :
uv pip install pydicom
uv pip install pillow # For image format conversion
uv pip install numpy # For pixel array manipulation
uv pip install matplotlib # For visualization
Pour gérer les fichiers DICOM compressés, des packages supplémentaires peuvent être nécessaires :
uv pip install pylibjpeg pylibjpeg-libjpeg pylibjpeg-openjpeg # JPEG compression
uv pip install python-gdcm # Alternative compression handler
Workflows principaux
Lire des fichiers DICOM
Lisez un fichier DICOM en utilisant pydicom.dcmread() :
import pydicom
# Read a DICOM file
ds = pydicom.dcmread('path/to/file.dcm')
# Access metadata
print(f"Patient Name: {ds.PatientName}")
print(f"Study Date: {ds.StudyDate}")
print(f"Modality: {ds.Modality}")
# Display all elements
print(ds)
Points clés :
dcmread()retourne un objetDataset- Accédez aux éléments de données en utilisant la notation d'attribut (p. ex.
ds.PatientName) ou la notation de tag (p. ex.ds[0x0010, 0x0010]) - Utilisez
ds.file_metapour accéder aux métadonnées du fichier comme Transfer Syntax UID - Gérez les attributs manquants avec
getattr(ds, 'AttributeName', default_value)ouhasattr(ds, 'AttributeName')
Travailler avec les données de pixels
Extrayez et manipulez les données d'image à partir de fichiers DICOM :
import pydicom
import numpy as np
import matplotlib.pyplot as plt
# Read DICOM file
ds = pydicom.dcmread('image.dcm')
# Get pixel array (requires numpy)
pixel_array = ds.pixel_array
# Image information
print(f"Shape: {pixel_array.shape}")
print(f"Data type: {pixel_array.dtype}")
print(f"Rows: {ds.Rows}, Columns: {ds.Columns}")
# Apply windowing for display (CT/MRI)
if hasattr(ds, 'WindowCenter') and hasattr(ds, 'WindowWidth'):
from pydicom.pixel_data_handlers.util import apply_voi_lut
windowed_image = apply_voi_lut(pixel_array, ds)
else:
windowed_image = pixel_array
# Display image
plt.imshow(windowed_image, cmap='gray')
plt.title(f"{ds.Modality} - {ds.StudyDescription}")
plt.axis('off')
plt.show()
Travailler avec les images en couleur :
# RGB images have shape (rows, columns, 3)
if ds.PhotometricInterpretation == 'RGB':
rgb_image = ds.pixel_array
plt.imshow(rgb_image)
elif ds.PhotometricInterpretation == 'YBR_FULL':
from pydicom.pixel_data_handlers.util import convert_color_space
rgb_image = convert_color_space(ds.pixel_array, 'YBR_FULL', 'RGB')
plt.imshow(rgb_image)
Images multi-frames (vidéos/séries) :
# For multi-frame DICOM files
if hasattr(ds, 'NumberOfFrames') and ds.NumberOfFrames > 1:
frames = ds.pixel_array # Shape: (num_frames, rows, columns)
print(f"Number of frames: {frames.shape[0]}")
# Display specific frame
plt.imshow(frames[0], cmap='gray')
Convertir DICOM en formats d'image
Utilisez le script dicom_to_image.py fourni ou convertissez manuellement :
from PIL import Image
import pydicom
import numpy as np
ds = pydicom.dcmread('input.dcm')
pixel_array = ds.pixel_array
# Normalize to 0-255 range
if pixel_array.dtype != np.uint8:
pixel_array = ((pixel_array - pixel_array.min()) /
(pixel_array.max() - pixel_array.min()) * 255).astype(np.uint8)
# Save as PNG
image = Image.fromarray(pixel_array)
image.save('output.png')
Utilisez le script : python scripts/dicom_to_image.py input.dcm output.png
Modifier les métadonnées
Modifiez les éléments de données DICOM :
import pydicom
from datetime import datetime
ds = pydicom.dcmread('input.dcm')
# Modify existing elements
ds.PatientName = "Doe^John"
ds.StudyDate = datetime.now().strftime('%Y%m%d')
ds.StudyDescription = "Modified Study"
# Add new elements
ds.SeriesNumber = 1
ds.SeriesDescription = "New Series"
# Remove elements
if hasattr(ds, 'PatientComments'):
delattr(ds, 'PatientComments')
# Or using del
if 'PatientComments' in ds:
del ds.PatientComments
# Save modified file
ds.save_as('modified.dcm')
Anonymiser les fichiers DICOM
Supprimez ou remplacez les informations d'identification personnelles du patient :
import pydicom
from datetime import datetime
ds = pydicom.dcmread('input.dcm')
# Tags commonly containing PHI (Protected Health Information)
tags_to_anonymize = [
'PatientName', 'PatientID', 'PatientBirthDate',
'PatientSex', 'PatientAge', 'PatientAddress',
'InstitutionName', 'InstitutionAddress',
'ReferringPhysicianName', 'PerformingPhysicianName',
'OperatorsName', 'StudyDescription', 'SeriesDescription',
]
# Remove or replace sensitive data
for tag in tags_to_anonymize:
if hasattr(ds, tag):
if tag in ['PatientName', 'PatientID']:
setattr(ds, tag, 'ANONYMOUS')
elif tag == 'PatientBirthDate':
setattr(ds, tag, '19000101')
else:
delattr(ds, tag)
# Update dates to maintain temporal relationships
if hasattr(ds, 'StudyDate'):
# Shift dates by a random offset
ds.StudyDate = '20000101'
# Keep pixel data intact
ds.save_as('anonymized.dcm')
Utilisez le script fourni : python scripts/anonymize_dicom.py input.dcm output.dcm
Écrire des fichiers DICOM
Créez des fichiers DICOM à partir de zéro :
import pydicom
from pydicom.dataset import Dataset, FileDataset
from datetime import datetime
import numpy as np
# Create file meta information
file_meta = Dataset()
file_meta.MediaStorageSOPClassUID = pydicom.uid.generate_uid()
file_meta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid()
file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
# Create the FileDataset instance
ds = FileDataset('new_dicom.dcm', {}, file_meta=file_meta, preamble=b"\0" * 128)
# Add required DICOM elements
ds.PatientName = "Test^Patient"
ds.PatientID = "123456"
ds.Modality = "CT"
ds.StudyDate = datetime.now().strftime('%Y%m%d')
ds.StudyTime = datetime.now().strftime('%H%M%S')
ds.ContentDate = ds.StudyDate
ds.ContentTime = ds.StudyTime
# Add image-specific elements
ds.SamplesPerPixel = 1
ds.PhotometricInterpretation = "MONOCHROME2"
ds.Rows = 512
ds.Columns = 512
ds.BitsAllocated = 16
ds.BitsStored = 16
ds.HighBit = 15
ds.PixelRepresentation = 0
# Create pixel data
pixel_array = np.random.randint(0, 4096, (512, 512), dtype=np.uint16)
ds.PixelData = pixel_array.tobytes()
# Add required UIDs
ds.SOPClassUID = pydicom.uid.CTImageStorage
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
ds.SeriesInstanceUID = pydicom.uid.generate_uid()
ds.StudyInstanceUID = pydicom.uid.generate_uid()
# Save the file
ds.save_as('new_dicom.dcm')
Compression et décompression
Gérez les fichiers DICOM compressés :
import pydicom
# Read compressed DICOM file
ds = pydicom.dcmread('compressed.dcm')
# Check transfer syntax
print(f"Transfer Syntax: {ds.file_meta.TransferSyntaxUID}")
print(f"Transfer Syntax Name: {ds.file_meta.TransferSyntaxUID.name}")
# Decompress and save as uncompressed
ds.decompress()
ds.save_as('uncompressed.dcm', write_like_original=False)
# Or compress when saving (requires appropriate encoder)
ds_uncompressed = pydicom.dcmread('uncompressed.dcm')
ds_uncompressed.compress(pydicom.uid.JPEGBaseline8Bit)
ds_uncompressed.save_as('compressed_jpeg.dcm')
Syntaxes de transfert courantes :
ExplicitVRLittleEndian- Non compressé, le plus courantJPEGBaseline8Bit- Compression JPEG avec perteJPEGLossless- Compression JPEG sans perteJPEG2000Lossless- JPEG 2000 sans perteRLELossless- Codage RLE (Run-Length Encoding) sans perte
Voir references/transfer_syntaxes.md pour la liste complète.
Travailler avec les séquences DICOM
Gérez les structures de données imbriquées :
import pydicom
ds = pydicom.dcmread('file.dcm')
# Access sequences
if 'ReferencedStudySequence' in ds:
for item in ds.ReferencedStudySequence:
print(f"Referenced SOP Instance UID: {item.ReferencedSOPInstanceUID}")
# Create a sequence
from pydicom.sequence import Sequence
sequence_item = Dataset()
sequence_item.ReferencedSOPClassUID = pydicom.uid.CTImageStorage
sequence_item.ReferencedSOPInstanceUID = pydicom.uid.generate_uid()
ds.ReferencedImageSequence = Sequence([sequence_item])
Traiter les séries DICOM
Travaillez avec plusieurs fichiers DICOM connexes :
import pydicom
import numpy as np
from pathlib import Path
# Read all DICOM files in a directory
dicom_dir = Path('dicom_series/')
slices = []
for file_path in dicom_dir.glob('*.dcm'):
ds = pydicom.dcmread(file_path)
slices.append(ds)
# Sort by slice location or instance number
slices.sort(key=lambda x: float(x.ImagePositionPatient[2]))
# Or: slices.sort(key=lambda x: int(x.InstanceNumber))
# Create 3D volume
volume = np.stack([s.pixel_array for s in slices])
print(f"Volume shape: {volume.shape}") # (num_slices, rows, columns)
# Get spacing information for proper scaling
pixel_spacing = slices[0].PixelSpacing # [row_spacing, col_spacing]
slice_thickness = slices[0].SliceThickness
print(f"Voxel size: {pixel_spacing[0]}x{pixel_spacing[1]}x{slice_thickness} mm")
Scripts utilitaires
Cette skill inclut des scripts utilitaires dans le répertoire scripts/ :
anonymize_dicom.py
Anonymisez les fichiers DICOM en supprimant ou remplaçant les informations de santé protégées (PHI).
python scripts/anonymize_dicom.py input.dcm output.dcm
dicom_to_image.py
Convertissez les fichiers DICOM en formats d'image courants (PNG, JPEG, TIFF).
python scripts/dicom_to_image.py input.dcm output.png
python scripts/dicom_to_image.py input.dcm output.jpg --format JPEG
extract_metadata.py
Extrayez et affichez les métadonnées DICOM dans un format lisible.
python scripts/extract_metadata.py file.dcm
python scripts/extract_metadata.py file.dcm --output metadata.txt
Matériel de référence
Des informations de référence détaillées sont disponibles dans le répertoire references/ :
- common_tags.md : Liste complète des tags DICOM couramment utilisés organisée par catégorie (Patient, Study, Series, Image, etc.)
- transfer_syntaxes.md : Référence complète des syntaxes de transfert DICOM et des formats de compression
Problèmes courants et solutions
Problème : « Unable to decode pixel data »
- Solution : Installez les gestionnaires de compression supplémentaires :
uv pip install pylibjpeg pylibjpeg-libjpeg python-gdcm
Problème : « AttributeError » lors de l'accès aux tags
- Solution : Vérifiez l'existence de l'attribut avec
hasattr(ds, 'AttributeName')ou utilisezds.get('AttributeName', default)
Problème : Affichage incorrect de l'image (trop sombre/clair)
- Solution : Appliquez le windowing VOI LUT :
apply_voi_lut(pixel_array, ds)ou ajustez manuellement avecWindowCenteretWindowWidth
Problème : Problèmes de mémoire avec des séries volumineuses
- Solution : Traitez les fichiers itérativement, utilisez des tableaux mappés en mémoire, ou réduisez l'échelle des images
Bonnes pratiques
- Vérifiez toujours les attributs requis avant d'y accéder en utilisant
hasattr()ouget() - Préservez les métadonnées du fichier lors de la modification des fichiers en utilisant
save_as()avecwrite_like_original=True - Utilisez les Transfer Syntax UIDs pour comprendre le format de compression avant de traiter les données de pixels
- Gérez les exceptions lors de la lecture de fichiers provenant de sources non fiables
- Appliquez le windowing approprié (VOI LUT) pour la visualisation d'images médicales
- Maintenez les informations spatiales (espacement des pixels, épaisseur de coupe) lors du traitement des volumes 3D
- Vérifiez l'anonymisation minutieusement avant de partager des données médicales
- Utilisez les UIDs correctement - générez de nouveaux UIDs lors de la création de nouvelles instances, préservez-les lors de la modification
Documentation
Documentation officielle de pydicom : https://pydicom.github.io/pydicom/dev/
- Guide utilisateur : https://pydicom.github.io/pydicom/dev/guides/user/index.html
- Tutoriels : https://pydicom.github.io/pydicom/dev/tutorials/index.html
- Référence API : https://pydicom.github.io/pydicom/dev/reference/index.html
- Exemples : https://pydicom.github.io/pydicom/dev/auto_examples/index.html