예제 #1
0
 def test_non_array_input(self):
     """Test non 1D input raises exception."""
     with pytest.raises(ValueError, match='Only 1D arrays are supported'):
         pack_bits(
             np.asarray(
                 [[0, 0, 0, 0, 0, 0, 0, 0],
                  [1, 0, 1, 0, 1, 0, 1, 0]]
             )
         )
예제 #2
0
 def test_non_array_input(self):
     """Test non 1D input raises exception."""
     with pytest.raises(ValueError, match='Only 1D arrays are supported'):
         pack_bits(
             np.asarray(
                 [[0, 0, 0, 0, 0, 0, 0, 0],
                  [1, 0, 1, 0, 1, 0, 1, 0]]
             )
         )
예제 #3
0
    def _encode_pixels(self, planes: np.ndarray) -> bytes:
        """Encodes pixel planes.

        Parameters
        ----------
        planes: numpy.ndarray
            Array representing one or more segmentation image planes.
            For encapsulated transfer syntaxes, only a single frame may be
            processed. For other transfer syntaxes, multiple planes in a 3D
            array may be processed.

        Returns
        -------
        bytes
            Encoded pixels

        Raises
        ------
        ValueError
            If multiple frames are passed when using an encapsulated
            transfer syntax.

        """
        if self.file_meta.TransferSyntaxUID.is_encapsulated:
            # Check that only a single plane was passed
            if planes.ndim == 3:
                if planes.shape[0] == 1:
                    planes = planes[0, ...]
                else:
                    raise ValueError(
                        'Only single frame can be encoded at at time '
                        'in case of encapsulated format encoding.')
            return encode_frame(
                planes,
                transfer_syntax_uid=self.file_meta.TransferSyntaxUID,
                bits_allocated=self.BitsAllocated,
                bits_stored=self.BitsStored,
                photometric_interpretation=self.PhotometricInterpretation,
                pixel_representation=self.PixelRepresentation)
        else:
            # The array may represent more than one frame item.
            if self.SegmentationType == SegmentationTypeValues.BINARY.value:
                return pack_bits(planes.flatten())
            else:
                return planes.flatten().tobytes()
예제 #4
0
파일: sop.py 프로젝트: aashish24/highdicom
    def _encode_pixels(self, planes: np.ndarray) -> bytes:
        """Encodes pixel planes.

        Parameters
        ----------
        planes: numpy.ndarray
            Array representing one or more segmentation image planes

        Returns
        -------
        bytes
            Encoded pixels

        """
        # TODO: compress depending on transfer syntax UID
        if self.SegmentationType == SegmentationTypeValues.BINARY.value:
            return pack_bits(planes.flatten())
        else:
            return planes.flatten().tobytes()
예제 #5
0
 def test_functional(self):
     """Test against a real dataset."""
     ds = dcmread(EXPL_1_1_3F)
     arr = ds.pixel_array
     arr = arr.ravel()
     assert ds.PixelData == pack_bits(arr)
예제 #6
0
 def test_pack_partial(self, input, output):
     """Test packing data that isn't a full byte long."""
     assert output == pack_bits(np.asarray(input))
예제 #7
0
 def test_non_binary_input(self):
     """Test non-binary input raises exception."""
     with pytest.raises(ValueError,
                        match=r"Only binary arrays \(containing ones or"):
         pack_bits(np.asarray([0, 0, 2, 0, 0, 0, 0, 0]))
예제 #8
0
 def test_pack(self, input, output):
     """Test packing data."""
     assert output == pack_bits(np.asarray(input))
예제 #9
0
 def test_functional(self):
     """Test against a real dataset."""
     ds = dcmread(EXPL_1_1_3F)
     arr = ds.pixel_array
     arr = arr.ravel()
     assert ds.PixelData == pack_bits(arr)
예제 #10
0
 def test_pack_partial(self, input, output):
     """Test packing data that isn't a full byte long."""
     assert output == pack_bits(np.asarray(input))
예제 #11
0
 def test_non_binary_input(self):
     """Test non-binary input raises exception."""
     with pytest.raises(ValueError,
                        match=r"Only binary arrays \(containing ones or"):
         pack_bits(np.asarray([0, 0, 2, 0, 0, 0, 0, 0]))
예제 #12
0
 def test_pack(self, input, output):
     """Test packing data."""
     assert output == pack_bits(np.asarray(input))
예제 #13
0
파일: frame.py 프로젝트: fedorov/highdicom
def encode_frame(
    array: np.ndarray,
    transfer_syntax_uid: str,
    bits_allocated: int,
    bits_stored: int,
    photometric_interpretation: Union[PhotometricInterpretationValues, str],
    pixel_representation: Union[PixelRepresentationValues, int] = 0,
    planar_configuration: Optional[Union[PlanarConfigurationValues,
                                         int]] = None
) -> bytes:
    """Encodes pixel data of an individual frame.

    Parameters
    ----------
    array: numpy.ndarray
        Pixel data in form of an array with dimensions
        (Rows x Columns x SamplesPerPixel) in case of a color image and
        (Rows x Columns) in case of a monochrome image
    transfer_syntax_uid: int
        Transfer Syntax UID
    bits_allocated: int
        Number of bits that need to be allocated per pixel sample
    bits_stored: int
        Number of bits that are required to store a pixel sample
    photometric_interpretation: int
        Photometric interpretation
    pixel_representation: int, optional
        Whether pixel samples are represented as unsigned integers or
        2's complements
    planar_configuration: int, optional
        Whether color samples are conded by pixel (`R1G1B1R2G2B2...`) or
        by plane (`R1R2...G1G2...B1B2...`).

    Returns
    -------
    bytes
        Pixel data (potentially compressed in case of encapsulated format
        encoding, depending on the transfer snytax)

    Raises
    ------
    ValueError
        When `transfer_syntax_uid` is not supported or when
        `planar_configuration` is missing in case of a color image frame.

    """
    rows = array.shape[0]
    cols = array.shape[1]
    if array.ndim > 2:
        if planar_configuration is None:
            raise ValueError(
                'Planar configuration needs to be specified for encoding of '
                'color image frames.')
        planar_configuration = PlanarConfigurationValues(
            planar_configuration).value
        samples_per_pixel = array.shape[2]
    else:
        samples_per_pixel = 1

    pixel_representation = PixelRepresentationValues(
        pixel_representation).value
    photometric_interpretation = PhotometricInterpretationValues(
        photometric_interpretation).value

    uncompressed_transfer_syntaxes = {
        ExplicitVRLittleEndian,
        ImplicitVRLittleEndian,
    }
    compressed_transfer_syntaxes = {
        JPEGBaseline,
        JPEG2000Lossless,
        RLELossless,
    }
    supported_transfer_syntaxes = uncompressed_transfer_syntaxes.union(
        compressed_transfer_syntaxes)
    if transfer_syntax_uid not in supported_transfer_syntaxes:
        raise ValueError(
            f'Transfer Syntax "{transfer_syntax_uid}" is not supported. '
            'Only the following are supported: "{}"'.format(
                '", "'.join(supported_transfer_syntaxes)))
    if transfer_syntax_uid in uncompressed_transfer_syntaxes:
        if bits_allocated == 1:
            if (rows * cols * samples_per_pixel) % 8 != 0:
                raise ValueError(
                    'Frame cannot be bit packed because its size is not a '
                    'multiple of 8.')
            return pack_bits(array.flatten())
        else:
            return array.flatten().tobytes()

    else:
        compression_lut = {
            JPEGBaseline: (
                'jpeg',
                {
                    'quality': 95
                },
            ),
            JPEG2000Lossless: (
                'jpeg2000',
                {
                    'tile_size': None,
                    'num_resolutions': 1,
                    'irreversible': False,
                },
            ),
        }

        if transfer_syntax_uid == JPEGBaseline:
            if samples_per_pixel == 1:
                if planar_configuration is not None:
                    raise ValueError(
                        'Planar configuration must be absent for encoding of '
                        'monochrome image frames with JPEG Baseline codec.')
                if photometric_interpretation not in ('MONOCHROME1',
                                                      'MONOCHROME2'):
                    raise ValueError(
                        'Photometric intpretation must be either "MONOCHROME1" '
                        'or "MONOCHROME2" for encoding of monochrome image '
                        'frames with JPEG Baseline codec.')
            elif samples_per_pixel == 3:
                if photometric_interpretation != 'YBR_FULL_422':
                    raise ValueError(
                        'Photometric intpretation must be "YBR_FULL_422" for '
                        'encoding of color image frames with '
                        'JPEG Baseline codec.')
                if planar_configuration != 0:
                    raise ValueError(
                        'Planar configuration must be 0 for encoding of '
                        'color image frames with JPEG Baseline codec.')
            else:
                raise ValueError(
                    'Samples per pixel must be 1 or 3 for '
                    'encoding of image frames with JPEG Baseline codec.')
            if bits_allocated != 8 or bits_stored != 8:
                raise ValueError(
                    'Bits allocated and bits stored must be 8 for '
                    'encoding of image frames with JPEG Baseline codec.')
            if pixel_representation != 0:
                raise ValueError(
                    'Pixel representation must be 0 for '
                    'encoding of image frames with JPEG Baseline codec.')

        if transfer_syntax_uid == JPEG2000Lossless:
            if samples_per_pixel == 1:
                if planar_configuration is not None:
                    raise ValueError(
                        'Planar configuration must be absent for encoding of '
                        'monochrome image frames with Lossless JPEG2000 codec.'
                    )
                if photometric_interpretation not in ('MONOCHROME1',
                                                      'MONOCHROME2'):
                    raise ValueError(
                        'Photometric intpretation must be either "MONOCHROME1" '
                        'or "MONOCHROME2" for encoding of monochrome image '
                        'frames with Lossless JPEG2000 codec.')
            elif samples_per_pixel == 3:
                if photometric_interpretation != 'YBR_FULL':
                    raise ValueError(
                        'Photometric interpretation must be "YBR_FULL" for '
                        'encoding of color image frames with '
                        'Lossless JPEG2000 codec.')
                if planar_configuration != 0:
                    raise ValueError(
                        'Planar configuration must be 0 for encoding of '
                        'color image frames with Lossless JPEG2000 codec.')
            else:
                raise ValueError(
                    'Samples per pixel must be 1 or 3 for '
                    'encoding of image frames with Lossless JPEG2000 codec.')
            if pixel_representation != 0:
                raise ValueError(
                    'Pixel representation must be 0 for '
                    'encoding of image frames with Lossless JPEG2000 codec.')

        if transfer_syntax_uid in compression_lut.keys():
            image_format, kwargs = compression_lut[transfer_syntax_uid]
            image = Image.fromarray(array)
            with BytesIO() as buf:
                image.save(buf, format=image_format, **kwargs)
                data = buf.getvalue()
        elif transfer_syntax_uid == RLELossless:
            data = rle_encode_frame(array)
        else:
            raise ValueError(
                f'Transfer Syntax "{transfer_syntax_uid}" is not supported.')
    return data
예제 #14
0
 def time_pack(self):
     """Time packing."""
     for ii in range(self.no_runs):
         pack_bits(self.unpacked)