Beispiel #1
0
 def test_multi_frame_three_to_one(self):
     """Test a multi-frame image where each frame is three fragments"""
     # 2 frames, each 3 fragments long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x20\x00\x00\x00' \
                  b'\x40\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     assert next(frames) == (b'\x02\x00\x00\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     assert next(frames) == (b'\x03\x00\x00\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     pytest.raises(StopIteration, next, frames)
Beispiel #2
0
 def test_multi_frame_varied_ratio(self):
     """Test a multi-frame image where each frames is random fragments"""
     # 3 frames, 1st is 1 fragment, 2nd is 3 fragments, 3rd is 2 fragments
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x0E\x00\x00\x00' \
                  b'\x32\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x06\x00\x00\x00\x01\x00\x00\x00\x00\x01' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x02\x00\x00\x00\x02\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x06\x00\x00\x00\x03\x00\x00\x00\x00\x02' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x02\x00\x00\x00\x02\x04'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00\x00\x01', )
     assert next(frames) == (b'\x02\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00\x00\x02')
     assert next(frames) == (b'\x03\x00\x00\x00', b'\x02\x04')
     pytest.raises(StopIteration, next, frames)
Beispiel #3
0
 def test_multi_frame_varied_ratio(self):
     """Test a multi-frame image where each frames is random fragments"""
     # 3 frames, 1st is 1 fragment, 2nd is 3 fragments, 3rd is 2 fragments
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x0E\x00\x00\x00' \
                  b'\x32\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x06\x00\x00\x00\x01\x00\x00\x00\x00\x01' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x02\x00\x00\x00\x02\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x06\x00\x00\x00\x03\x00\x00\x00\x00\x02' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x02\x00\x00\x00\x02\x04'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00\x00\x01', )
     assert next(frames) == (b'\x02\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00\x00\x02')
     assert next(frames) == (b'\x03\x00\x00\x00', b'\x02\x04')
     pytest.raises(StopIteration, next, frames)
Beispiel #4
0
 def test_multi_frame_three_to_one(self):
     """Test a multi-frame image where each frame is three fragments"""
     # 2 frames, each 3 fragments long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x20\x00\x00\x00' \
                  b'\x40\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00',
                             b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     assert next(frames) == (b'\x02\x00\x00\x00',
                             b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     assert next(frames) == (b'\x03\x00\x00\x00',
                             b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     pytest.raises(StopIteration, next, frames)
Beispiel #5
0
 def test_empty_bot_single_fragment(self):
     """Test a single-frame image where the frame is one fragments"""
     # 1 frame, 1 fragment long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x00\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00', )
     pytest.raises(StopIteration, next, frames)
Beispiel #6
0
 def test_empty_bot_single_fragment(self):
     """Test a single-frame image where the frame is one fragments"""
     # 1 frame, 1 fragment long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x00\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00', )
     pytest.raises(StopIteration, next, frames)
Beispiel #7
0
    def test_empty_bot_multi_fragments_per_frame(self):
        """Test parsing with multiple fragments per frame."""
        # 4 frames in 6 fragments with JPEG EOI marker
        bytestream = (b'\xFE\xFF\x00\xE0\x00\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\xFF\xD9'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00')

        frames = generate_pixel_data(bytestream, 4)
        for ii in range(4):
            next(frames)

        with pytest.raises(StopIteration):
            next(frames)
Beispiel #8
0
 def test_empty_bot_triple_fragment_single_frame(self):
     """Test a single-frame image where the frame is three fragments"""
     # 1 frame, 3 fragments long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x00\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream, 1)
     assert next(frames) == (b'\x01\x00\x00\x00', b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     pytest.raises(StopIteration, next, frames)
Beispiel #9
0
 def test_empty_bot_no_nr_frames_raises(self):
     """Test parsing raises if not BOT and no nr_frames."""
     # 1 frame, 3 fragments long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x00\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x03\x00\x00\x00'
     msg = (r"Unable to determine the frame boundaries for the "
            r"encapsulated pixel data as the Basic Offset Table is empty "
            r"and `nr_frames` parameter is None")
     with pytest.raises(ValueError, match=msg):
         next(generate_pixel_data(bytestream))
Beispiel #10
0
 def test_bot_triple_fragment_single_frame(self):
     """Test a single-frame image where the frame is three fragments"""
     # 1 frame, 3 fragments long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00',
                             b'\x02\x00\x00\x00',
                             b'\x03\x00\x00\x00')
     pytest.raises(StopIteration, next, frames)
Beispiel #11
0
    def test_empty_bot_missing_marker(self):
        """Test parsing not BOT and missing marker with multi fragments."""
        # 4 frames in 6 fragments with JPEG EOI marker (1 missing EOI)
        bytestream = (b'\xFE\xFF\x00\xE0\x00\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xFF\xD9'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00')

        msg = (r"The end of the encapsulated pixel data has been "
               r"reached but one or more frame boundaries may have "
               r"been missed; please confirm that the generated frame "
               r"data is correct")
        with pytest.warns(UserWarning, match=msg):
            ii = 0
            for frames in generate_pixel_data(bytestream, 4):
                ii += 1

        assert 3 == ii
Beispiel #12
0
 def test_multi_frame_one_to_one(self):
     """Test a multi-frame image where each frame is one fragment"""
     # 3 frames, each 1 fragment long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x0C\x00\x00\x00' \
                  b'\x18\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00', )
     assert next(frames) == (b'\x02\x00\x00\x00', )
     assert next(frames) == (b'\x03\x00\x00\x00', )
     pytest.raises(StopIteration, next, frames)
Beispiel #13
0
 def test_multi_frame_one_to_one(self):
     """Test a multi-frame image where each frame is one fragment"""
     # 3 frames, each 1 fragment long
     bytestream = b'\xFE\xFF\x00\xE0' \
                  b'\x0C\x00\x00\x00' \
                  b'\x00\x00\x00\x00' \
                  b'\x0C\x00\x00\x00' \
                  b'\x18\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x01\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x02\x00\x00\x00' \
                  b'\xFE\xFF\x00\xE0' \
                  b'\x04\x00\x00\x00' \
                  b'\x03\x00\x00\x00'
     frames = generate_pixel_data(bytestream)
     assert next(frames) == (b'\x01\x00\x00\x00', )
     assert next(frames) == (b'\x02\x00\x00\x00', )
     assert next(frames) == (b'\x03\x00\x00\x00', )
     pytest.raises(StopIteration, next, frames)
Beispiel #14
0
    def test_empty_bot_no_marker(self):
        """Test parsing not BOT and no final marker with multi fragments."""
        # 4 frames in 6 fragments with JPEG EOI marker (1 missing EOI)
        bytestream = (b'\xFE\xFF\x00\xE0\x00\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\x00\x00\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xD9\x00'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\xFF\xD9'
                      b'\xFE\xFF\x00\xE0\x04\x00\x00\x00\x01\xFF\x00\x00')

        frames = generate_pixel_data(bytestream, 4)
        for ii in range(3):
            next(frames)

        msg = (r"The end of the encapsulated pixel data has been "
               r"reached but one or more frame boundaries may have "
               r"been missed; please confirm that the generated frame "
               r"data is correct")
        with pytest.warns(UserWarning, match=msg):
            next(frames)

        with pytest.raises(StopIteration):
            next(frames)
Beispiel #15
0
def get_pixeldata(ds: "Dataset") -> "numpy.ndarray":
    """Use the GDCM package to decode *Pixel Data*.

    Returns
    -------
    numpy.ndarray
        A correctly sized (but not shaped) array of the entire data volume

    Raises
    ------
    ImportError
        If the required packages are not available.
    TypeError
        If the image could not be read by GDCM or if the *Pixel Data* type is
        unsupported.
    AttributeError
        If the decoded amount of data does not match the expected amount.
    """
    if not HAVE_GDCM:
        raise ImportError("The GDCM handler requires both gdcm and numpy")

    if HAVE_GDCM_IN_MEMORY_SUPPORT:
        gdcm_data_element = create_data_element(ds)
        gdcm_image = create_image(ds, gdcm_data_element)
    else:
        gdcm_image_reader = create_image_reader(ds)
        if not gdcm_image_reader.Read():
            raise TypeError("GDCM could not read DICOM image")
        gdcm_image = gdcm_image_reader.GetImage()

    # GDCM returns char* as type str. Python 3 decodes this to
    # unicode strings by default.
    # The SWIG docs mention that they always decode byte streams
    # as utf-8 strings for Python 3, with the `surrogateescape`
    # error handler configured.
    # Therefore, we can encode them back to their original bytearray
    # representation on Python 3 by using the same parameters.

    pixel_bytearray = gdcm_image.GetBuffer().encode("utf-8", "surrogateescape")

    # Here we need to be careful because in some cases, GDCM reads a
    # buffer that is too large, so we need to make sure we only include
    # the first n_rows * n_columns * dtype_size bytes.
    expected_length_bytes = get_expected_length(ds)
    if ds.PhotometricInterpretation == 'YBR_FULL_422':
        # GDCM has already resampled the pixel data, see PS3.3 C.7.6.3.1.2
        expected_length_bytes = expected_length_bytes // 2 * 3

    if len(pixel_bytearray) > expected_length_bytes:
        # We make sure that all the bytes after are in fact zeros
        padding = pixel_bytearray[expected_length_bytes:]
        if numpy.any(numpy.frombuffer(padding, numpy.byte)):
            pixel_bytearray = pixel_bytearray[:expected_length_bytes]
        else:
            # We revert to the old behavior which should then result
            #   in a Numpy error later on.
            pass

    numpy_dtype = pixel_dtype(ds)
    arr = numpy.frombuffer(pixel_bytearray, dtype=numpy_dtype)

    expected_length_pixels = get_expected_length(ds, 'pixels')
    if arr.size != expected_length_pixels:
        raise AttributeError(
            f"Amount of pixel data {arr.size} does not match the "
            f"expected data {expected_length_pixels}"
        )

    file_meta: "FileMetaDataset" = ds.file_meta  # type: ignore[has-type]
    tsyntax = cast(UID, file_meta.TransferSyntaxUID)
    if (
        config.APPLY_J2K_CORRECTIONS
        and tsyntax in [JPEG2000, JPEG2000Lossless]
    ):
        nr_frames = getattr(ds, 'NumberOfFrames', 1)
        codestream = next(generate_pixel_data(ds.PixelData, nr_frames))[0]

        params = get_j2k_parameters(codestream)
        j2k_precision = cast(
            int, params.setdefault("precision", ds.BitsStored)
        )
        j2k_sign = params.setdefault("is_signed", None)

        if not j2k_sign and ds.PixelRepresentation == 1:
            # Convert unsigned J2K data to 2's complement
            shift = cast(int, ds.BitsAllocated) - j2k_precision
            pixel_module = ds.group_dataset(0x0028)
            pixel_module.PixelRepresentation = 0
            dtype = pixel_dtype(pixel_module)
            arr = (arr.astype(dtype) << shift).astype(numpy_dtype) >> shift

    if should_change_PhotometricInterpretation_to_RGB(ds):
        ds.PhotometricInterpretation = "RGB"

    return arr.copy()