def create_image(dicom_dataset, data_element): """Create a gdcm.Image from a FileDataset and a gdcm.DataElement containing PixelData (0x7fe0, 0x0010) Parameters ---------- dicom_dataset : FileDataset data_element : gdcm.DataElement DataElement containing PixelData Returns ------- gdcm.Image """ image = gdcm.Image() number_of_frames = getattr(dicom_dataset, 'NumberOfFrames', 1) image.SetNumberOfDimensions(2 if number_of_frames == 1 else 3) image.SetDimensions( (dicom_dataset.Columns, dicom_dataset.Rows, number_of_frames)) image.SetDataElement(data_element) pi_type = gdcm.PhotometricInterpretation.GetPIType( dicom_dataset.PhotometricInterpretation) image.SetPhotometricInterpretation(gdcm.PhotometricInterpretation(pi_type)) ts_type = gdcm.TransferSyntax.GetTSType( str.__str__(dicom_dataset.file_meta.TransferSyntaxUID)) image.SetTransferSyntax(gdcm.TransferSyntax(ts_type)) pixel_format = gdcm.PixelFormat(dicom_dataset.SamplesPerPixel, dicom_dataset.BitsAllocated, dicom_dataset.BitsStored, dicom_dataset.HighBit, dicom_dataset.PixelRepresentation) image.SetPixelFormat(pixel_format) if 'PlanarConfiguration' in dicom_dataset: image.SetPlanarConfiguration(dicom_dataset.PlanarConfiguration) return image
def create_image(ds: "Dataset", data_element: "DataElement") -> "gdcm.Image": """Return a ``gdcm.Image``. Parameters ---------- ds : dataset.Dataset The :class:`~pydicom.dataset.Dataset` containing the Image Pixel module. data_element : gdcm.DataElement The ``gdcm.DataElement`` *Pixel Data* element. Returns ------- gdcm.Image """ image = gdcm.Image() number_of_frames = getattr(ds, 'NumberOfFrames', 1) image.SetNumberOfDimensions(2 if number_of_frames == 1 else 3) image.SetDimensions((ds.Columns, ds.Rows, number_of_frames)) image.SetDataElement(data_element) pi_type = gdcm.PhotometricInterpretation.GetPIType( ds.PhotometricInterpretation) image.SetPhotometricInterpretation(gdcm.PhotometricInterpretation(pi_type)) ts_type = gdcm.TransferSyntax.GetTSType( str.__str__(ds.file_meta.TransferSyntaxUID)) image.SetTransferSyntax(gdcm.TransferSyntax(ts_type)) pixel_format = gdcm.PixelFormat(ds.SamplesPerPixel, ds.BitsAllocated, ds.BitsStored, ds.HighBit, ds.PixelRepresentation) image.SetPixelFormat(pixel_format) if 'PlanarConfiguration' in ds: image.SetPlanarConfiguration(ds.PlanarConfiguration) return image
def _create_gdcm_image(src: bytes, **kwargs: Any) -> "gdcm.Image": """Return a gdcm.Image from the `src`. Parameters ---------- src : bytes The raw image frame data to be encoded. **kwargs Required parameters: * `rows`: int * `columns`: int * `samples_per_pixel`: int * `number_of_frames`: int * `bits_allocated`: int * `bits_stored`: int * `pixel_representation`: int * `photometric_interpretation`: str Returns ------- gdcm.Image An Image containing the `src` as a single uncompressed frame. """ rows = kwargs['rows'] columns = kwargs['columns'] samples_per_pixel = kwargs['samples_per_pixel'] number_of_frames = kwargs['number_of_frames'] pixel_representation = kwargs['pixel_representation'] bits_allocated = kwargs['bits_allocated'] bits_stored = kwargs['bits_stored'] photometric_interpretation = kwargs['photometric_interpretation'] pi = gdcm.PhotometricInterpretation.GetPIType(photometric_interpretation) # GDCM's null photometric interpretation gets used for invalid values if pi == gdcm.PhotometricInterpretation.PI_END: raise ValueError( "An error occurred with the 'gdcm' plugin: invalid photometric " f"interpretation '{photometric_interpretation}'") # `src` uses little-endian byte ordering ts = gdcm.TransferSyntax.ImplicitVRLittleEndian image = gdcm.Image() image.SetNumberOfDimensions(2) image.SetDimensions((columns, rows, 1)) image.SetPhotometricInterpretation(gdcm.PhotometricInterpretation(pi)) image.SetTransferSyntax(gdcm.TransferSyntax(ts)) pixel_format = gdcm.PixelFormat(samples_per_pixel, bits_allocated, bits_stored, bits_stored - 1, pixel_representation) image.SetPixelFormat(pixel_format) if samples_per_pixel > 1: # Default `src` is planar configuration 0 (i.e. R1 G1 B1 R2 G2 B2) image.SetPlanarConfiguration(0) # Add the Pixel Data element and set the value to `src` elem = gdcm.DataElement(gdcm.Tag(0x7FE0, 0x0010)) elem.SetByteStringValue(src) image.SetDataElement(elem) return cast("gdcm.Image", image)
def _rle_encode(src: bytes, **kwargs: Any) -> bytes: """Return RLE encoded image data from `src`. Parameters ---------- src : bytes The raw image frame data to be encoded. **kwargs Required parameters: * `rows`: int * `columns`: int * `samples_per_pixel`: int * `number_of_frames`: int * `bits_allocated`: int * `bits_stored`: int * `pixel_representation`: int * `photometric_interpretation`: str Returns ------- bytes The encoded image data. """ # Check the parameters are valid for RLE encoding with GDCM rows = kwargs['rows'] columns = kwargs['columns'] samples_per_pixel = kwargs['samples_per_pixel'] number_of_frames = kwargs['number_of_frames'] pixel_representation = kwargs['pixel_representation'] bits_allocated = kwargs['bits_allocated'] bits_stored = kwargs['bits_stored'] photometric_interpretation = kwargs['photometric_interpretation'] # Bug up to v3.0.9 (Apr 2021) in handling 32-bit, 3 sample/px data gdcm_version = [int(c) for c in gdcm.Version.GetVersion().split('.')] if gdcm_version < [3, 0, 10]: if bits_allocated == 32 and samples_per_pixel == 3: raise RuntimeError( "The 'gdcm' plugin is unable to RLE encode 32-bit, 3 " "samples/px data with GDCM v3.0.9 or older" ) if bits_allocated > 32: raise ValueError( f"The 'gdcm' plugin is unable to encode {bits_allocated}-bit data" ) # Create a gdcm.Image with the uncompressed `src` data pi = gdcm.PhotometricInterpretation.GetPIType( photometric_interpretation ) # GDCM's null photometric interpretation gets used for invalid values if pi == gdcm.PhotometricInterpretation.PI_END: raise ValueError( "An error occurred with the 'gdcm' plugin: invalid photometric " f"interpretation '{photometric_interpretation}'" ) # `src` uses little-endian byte ordering ts = gdcm.TransferSyntax.ImplicitVRLittleEndian # Must use ImageWriter().GetImage() to create a gdcmImage # also have to make sure `writer` doesn't go out of scope writer = gdcm.ImageWriter() image = writer.GetImage() image.SetNumberOfDimensions(2) image.SetDimensions((columns, rows, 1)) image.SetPhotometricInterpretation( gdcm.PhotometricInterpretation(pi) ) image.SetTransferSyntax(gdcm.TransferSyntax(ts)) pixel_format = gdcm.PixelFormat( samples_per_pixel, bits_allocated, bits_stored, bits_stored - 1, pixel_representation ) image.SetPixelFormat(pixel_format) if samples_per_pixel > 1: # Default `src` is planar configuration 0 (i.e. R1 G1 B1 R2 G2 B2) image.SetPlanarConfiguration(0) # Add the Pixel Data element and set the value to `src` elem = gdcm.DataElement(gdcm.Tag(0x7FE0, 0x0010)) elem.SetByteStringValue(src) image.SetDataElement(elem) # Converts an image to match the set transfer syntax converter = gdcm.ImageChangeTransferSyntax() # Set up the converter with the intended transfer syntax... rle = gdcm.TransferSyntax.GetTSType(kwargs['transfer_syntax_uid']) converter.SetTransferSyntax(gdcm.TransferSyntax(rle)) # ...and image to be converted converter.SetInput(image) # Perform the conversion, returns bool # 'PALETTE COLOR' and a lossy transfer syntax will return False result = converter.Change() if not result: raise RuntimeError( "An error occurred with the 'gdcm' plugin: " "ImageChangeTransferSyntax.Change() returned a failure result" ) # A new gdcmImage with the converted pixel data element image = converter.GetOutput() # The element's value is the encapsulated encoded pixel data seq = image.GetDataElement().GetSequenceOfFragments() # RLECodec::Code() uses only 1 fragment per frame if seq is None or seq.GetNumberOfFragments() != 1: # Covers both no sequence and unexpected number of fragments raise RuntimeError( "An error occurred with the 'gdcm' plugin: unexpected number of " "fragments found in the 'Pixel Data'" ) fragment = seq.GetFragment(0).GetByteValue().GetBuffer() return cast(bytes, fragment.encode("utf-8", "surrogateescape"))