J'essaie de créer une image DICOM compressée JPEG à l'aide de pydicom . Un bon matériel source sur les images DICOM colorées peut être trouvé ici , mais c'est principalement de la théorie et du C ++. Dans l'exemple de code ci-dessous, je crée des points de suspension bleu pâle à l'intérieur output-raw.dcm
(non compressés) qui ressemblent bien à ceci:
import io
from PIL import Image, ImageDraw
from pydicom.dataset import Dataset
from pydicom.uid import generate_uid, JPEGExtended
from pydicom._storage_sopclass_uids import SecondaryCaptureImageStorage
WIDTH = 100
HEIGHT = 100
def ensure_even(stream):
# Very important for some viewers
if len(stream) % 2:
return stream + b"\x00"
return stream
def bob_ross_magic():
image = Image.new("RGB", (WIDTH, HEIGHT), color="red")
draw = ImageDraw.Draw(image)
draw.rectangle([10, 10, 90, 90], fill="black")
draw.ellipse([30, 20, 70, 80], fill="cyan")
draw.text((11, 11), "Hello", fill=(255, 255, 0))
return image
ds = Dataset()
ds.is_little_endian = True
ds.is_implicit_VR = True
ds.SOPClassUID = SecondaryCaptureImageStorage
ds.SOPInstanceUID = generate_uid()
ds.fix_meta_info()
ds.Modality = "OT"
ds.SamplesPerPixel = 3
ds.BitsAllocated = 8
ds.BitsStored = 8
ds.HighBit = 7
ds.PixelRepresentation = 0
ds.PhotometricInterpretation = "RGB"
ds.Rows = HEIGHT
ds.Columns = WIDTH
image = bob_ross_magic()
ds.PixelData = ensure_even(image.tobytes())
image.save("output.png")
ds.save_as("output-raw.dcm", write_like_original=False) # File is OK
#
# Create compressed image
#
output = io.BytesIO()
image.save(output, format="JPEG")
ds.PixelData = ensure_even(output.getvalue())
ds.PhotometricInterpretation = "YBR_FULL_422"
ds.file_meta.TransferSyntaxUID = JPEGExtended
ds.save_as("output-jpeg.dcm", write_like_original=False) # File is corrupt
À la toute fin, j'essaie de créer des DICOM compressés: j'ai essayé de définir différentes syntaxes de transfert, compressions avec PIL, mais pas de chance. Je crois que le fichier DICOM généré est corrompu. Si je devais convertir le fichier DICOM brut en JPEG compressé avec gdcm-tools:
$ gdcmconv -J output-raw.dcm output-jpeg.dcm
En faisant un dcmdump
sur ce fichier converti, nous pourrions voir une structure intéressante, que je ne sais pas reproduire en utilisant pydicom:
$ dcmdump output-jpeg.dcm
# Dicom-File-Format
# Dicom-Meta-Information-Header
# Used TransferSyntax: Little Endian Explicit
(0002,0000) UL 240 # 4, 1 FileMetaInformationGroupLength
(0002,0001) OB 00\01 # 2, 1 FileMetaInformationVersion
(0002,0002) UI =SecondaryCaptureImageStorage # 26, 1 MediaStorageSOPClassUID
(0002,0003) UI [1.2.826.0.1.3680043.8.498.57577581978474188964358168197934098358] # 64, 1 MediaStorageSOPInstanceUID
(0002,0010) UI =JPEGLossless:Non-hierarchical-1stOrderPrediction # 22, 1 TransferSyntaxUID
(0002,0012) UI [1.2.826.0.1.3680043.2.1143.107.104.103.115.2.8.4] # 48, 1 ImplementationClassUID
(0002,0013) SH [GDCM 2.8.4] # 10, 1 ImplementationVersionName
(0002,0016) AE [gdcmconv] # 8, 1 SourceApplicationEntityTitle
# Dicom-Data-Set
# Used TransferSyntax: JPEG Lossless, Non-hierarchical, 1st Order Prediction
...
... ### How to do the magic below?
...
(7fe0,0010) OB (PixelSequence #=2) # u/l, 1 PixelData
(fffe,e000) pi (no value available) # 0, 1 Item
(fffe,e000) pi ff\d8\ff\ee\00\0e\41\64\6f\62\65\00\64\00\00\00\00\00\ff\c3\00\11... # 4492, 1 Item
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
J'ai essayé d'utiliser le module d' encapsulation de pydicom , mais je pense que c'est principalement pour lire des données, pas pour écrire. Quelqu'un d'autre a des idées sur la façon de traiter ce problème, comment créer / encoder ces PixelSequence
s? J'adorerais créer des DICOM compressés JPEG en Python ordinaire sans exécuter d'outils externes.
Réponses:
DICOM nécessite que les données de pixels compressées soient encapsulées (voir les tableaux en particulier). Une fois que vous avez vos données d'image compressées, vous pouvez utiliser la méthode encaps.encapsulate () pour créer
bytes
une utilisation appropriée avec Pixel Data :la source
encapsulate([frame1, frame2, ...])
Essayer la solution de @scaramallion, avec plus de détails semble fonctionner:
la source