Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions src/highdicom/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
)
from pydicom.uid import UID, DeflatedExplicitVRLittleEndian

from highdicom.enum import PixelDataKeywords
from highdicom.frame import decode_frame
from highdicom.color import ColorManager
from highdicom.uid import UID as hd_UID
Expand All @@ -41,6 +42,11 @@
_FLOAT_PIXEL_DATA_TAGS = {0x7FE00008, 0x7FE00009, }
_UINT_PIXEL_DATA_TAGS = {0x7FE00010, }
_PIXEL_DATA_TAGS = _FLOAT_PIXEL_DATA_TAGS.union(_UINT_PIXEL_DATA_TAGS)
_PIXEL_DATA_KEYWORDS = {
0x7FE00008: PixelDataKeywords.FLOAT_PIXEL_DATA,
0x7FE00009: PixelDataKeywords.DOUBLE_FLOAT_PIXEL_DATA,
0x7FE00010: PixelDataKeywords.PIXEL_DATA,
}

_JPEG_SOI_MARKER = b'\xFF\xD8' # also JPEG-LS
_JPEG_EOI_MARKER = b'\xFF\xD9' # also JPEG-LS
Expand Down Expand Up @@ -545,9 +551,7 @@ def _read_metadata(self) -> None:
raise ValueError(
'Dataset does not represent an image information entity.'
)
self._as_float = False
if int(tag) in _FLOAT_PIXEL_DATA_TAGS:
self._as_float = True
self._pixel_keyword = _PIXEL_DATA_KEYWORDS[int(tag)]

# Reset the file pointer to the beginning of the Pixel Data element
self._fp.seek(self._pixel_data_offset, 0)
Expand Down Expand Up @@ -759,20 +763,28 @@ def read_frame(self, index: int, correct_color: bool = True) -> np.ndarray:

logger.debug(f'decode frame #{index}')

if self._pixel_keyword == PixelDataKeywords.PIXEL_DATA:
bits_stored = self.metadata.BitsStored
pixel_representation = self.metadata.PixelRepresentation
else:
bits_stored = self.metadata.BitsAllocated
pixel_representation = None

frame_array = decode_frame(
frame_data,
rows=self.metadata.Rows,
columns=self.metadata.Columns,
samples_per_pixel=self.metadata.SamplesPerPixel,
transfer_syntax_uid=self.transfer_syntax_uid,
bits_allocated=self.metadata.BitsAllocated,
bits_stored=self.metadata.BitsStored,
bits_stored=bits_stored,
photometric_interpretation=self.metadata.PhotometricInterpretation,
pixel_representation=self.metadata.PixelRepresentation,
pixel_representation=pixel_representation,
planar_configuration=getattr(
self.metadata, 'PlanarConfiguration', None
),
index=index,
pixel_keyword=self._pixel_keyword,
)

# We don't use the color_correct_frame() function here, since we cache
Expand Down
55 changes: 55 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
import numpy as np
from pydicom import dcmread
from pydicom.data import get_testdata_file
from pydicom.dataset import FileDataset, FileMetaDataset
from pydicom.filebase import DicomBytesIO, DicomFileLike, DicomFile
from pydicom.uid import (
ExplicitVRLittleEndian,
ParametricMapStorage,
generate_uid,
)
import pytest

from highdicom.io import ImageFileReader
Expand Down Expand Up @@ -39,6 +45,55 @@ def test_read_single_frame_ct_image_native(self):
)
np.testing.assert_array_equal(frame, pixel_array)

def test_read_float_pixel_data(self):
cases = [
(np.float32, 'FloatPixelData', 32),
(np.float64, 'DoubleFloatPixelData', 64),
]
with TemporaryDirectory() as temp_dir:
for dtype, pixel_keyword, bits_allocated in cases:
filename = Path(temp_dir) / f"{pixel_keyword}.dcm"
file_meta = FileMetaDataset()
file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
file_meta.MediaStorageSOPClassUID = ParametricMapStorage
file_meta.MediaStorageSOPInstanceUID = generate_uid()
file_meta.ImplementationClassUID = generate_uid()
dataset = FileDataset(
filename,
{},
file_meta=file_meta,
preamble=b"\0" * 128,
)
dataset.SOPClassUID = file_meta.MediaStorageSOPClassUID
dataset.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
dataset.Rows = 3
dataset.Columns = 4
dataset.SamplesPerPixel = 1
dataset.PhotometricInterpretation = 'MONOCHROME2'
dataset.NumberOfFrames = 2
dataset.BitsAllocated = bits_allocated
pixel_array = np.linspace(
-3.5,
2.25,
num=24,
dtype=dtype,
).reshape(2, 3, 4)
setattr(dataset, pixel_keyword, pixel_array.tobytes())
dataset.save_as(
filename,
implicit_vr=False,
little_endian=True,
)

with ImageFileReader(filename) as reader:
for frame_index in range(2):
frame = reader.read_frame(frame_index)
assert frame.dtype == dtype
np.testing.assert_array_equal(
frame,
pixel_array[frame_index],
)

def test_read_multi_frame_ct_image_native(self):
filename = str(get_testdata_file('eCT_Supplemental.dcm'))
dataset = dcmread(filename)
Expand Down