Pydicom kullanarak JPEG sıkıştırılmış DICOM veri kümesi nasıl oluşturulur?


14

Pydicom kullanarak bir JPEG sıkıştırılmış DICOM görüntü oluşturmaya çalışıyorum . Renkli DICOM görüntüleri hakkında güzel bir kaynak materyal burada bulunabilir , ancak çoğunlukla teori ve C ++. Aşağıdaki kod örneğinde, output-raw.dcm(iyi sıkıştırılmış) içinde soluk mavi üç nokta oluşturuyorum ki bu böyle iyi görünüyor:

Örnek DICOM görüntüsü

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

En sonunda sıkıştırılmış DICOM oluşturmaya çalışıyorum: Çeşitli aktarım sözdizimlerini, PIL ile sıkıştırmaları ayarlamayı denedim, ama şansım yok. Oluşturulan DICOM dosyasının bozuk olduğuna inanıyorum. Ham DICOM dosyasını gdcm-tools ile sıkıştırılmış JPEG'e dönüştürürsem:

$ gdcmconv -J output-raw.dcm output-jpeg.dcm

dcmdumpBu dönüştürülmüş dosya üzerinde bir yaparak , pydicom kullanarak nasıl çoğaltılacağını bilmiyorum ilginç bir yapı görebiliyordu:

$ 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

Pydicom'un encaps modülünü kullanmaya çalıştım , ama bence çoğunlukla veri okumak için, yazmak için değil. Herkes bu sorunu nasıl başa çıkacağına dair herhangi bir fikre sahip, bu PixelSequences nasıl oluşturulur / kodlanır ? Harici araçları çalıştırmadan düz Python'da JPEG sıkıştırılmış DICOM'lar oluşturmak isterim.


JPEG sıkıştırılmış görüntüyü PyDicom aracılığıyla okuyabilir misiniz?
norok2

Evet elbette açabilirim ve okuyabilirim. Tabii ki, birkaç ekstra kütüphaneye ihtiyacınız var, olası kombinasyonlar burada: pydicom.github.io/pydicom/stable/image_data_handlers.html
mseimys

Bu kullanım durumu her biri çözüldü mü? Bununla ilgili bazı belgeleri görmek isterim.
Steven Hart

Yanıtlar:


4

DICOM sıkıştırılmış gerektirir Piksel veri olarak kapsüllenmiş (özellikle tablolara bakınız). Sıkıştırılmış görüntü verilerinizi aldıktan sonra , Pixel Verileri ile kullanıma uygun oluşturmak için encaps.encapsulate () yöntemini byteskullanabilirsiniz :

from pydicom.encaps import encapsulate

# encapsulate() requires a list of bytes, one item per frame
ds.PixelData = encapsulate([ensure_even(output.getvalue())])
# Need to set this flag to indicate the Pixel Data is compressed
ds['PixelData'].is_undefined_length = True
ds.PhotometricInterpretation = "YBR_FULL_422"
ds.file_meta.TransferSyntaxUID = JPEGExtended

ds.save_as("output-jpeg.dcm", write_like_original=False)

Bu çalışır, ancak sadece tek kare jpeg için. Herkes çok çerçeveli jpeg kodlamak nasıl biliyor?
Steven Hart

Her karenin ayrı ayrı kodlanması ve ardından tüm karelerin kapsüllenmesi gerekirencapsulate([frame1, frame2, ...])
scaramallion

1

@Scaramallion'dan gelen çözümü denemek, daha fazla ayrıntıyla çalışmak için görünüyor:

import numpy as np
from PIL import Image
import io

# set some parameters
num_frames = 4
img_size = 10

# Create a fake RGB dataset
random_image_array = (np.random.random((num_frames, img_size, img_size, 3))*255).astype('uint8')
# Convert to PIL
imlist = []
for i in range(num_frames):   # convert the multiframe image into RGB of single frames (Required for compression)
    imlist.append(Image.fromarray(tmp))

# Save the multipage tiff with jpeg compression
f = io.BytesIO()
        imlist[0].save(f, format='tiff', append_images=imlist[1:], save_all=True, compression='jpeg')
# The BytesIO object cursor is at the end of the object, so I need to tell it to go back to the front
f.seek(0)
img = Image.open(f)

# Get each one of the frames converted to even numbered bytes
img_byte_list = []
for i in range(num_frames):
    try:
        img.seek(i)
        with io.BytesIO() as output:
            img.save(output, format='jpeg')
            img_byte_list.append(output.getvalue())
    except EOFError:
         # Not enough frames in img
         break

ds.PixelData = encapsulate([x for x in img_byte_list])
ds['PixelData'].is_undefined_length = True
ds.is_implicit_VR = False
ds.LossyImageCompression = '01'
ds.LossyImageCompressionRatio = 10 # default jpeg
ds.LossyImageCompressionMethod = 'ISO_10918_1'
ds.file_meta.TransferSyntaxUID = '1.2.840.10008.1.2.4.51'

ds.save_as("output-jpeg.dcm", write_like_original=False)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.