Пример #1
0
def unpack_data_from_file(file, fmt, offset=0):
    """Retrieve data from given file and unpack them according to specified format.

    file: The path name of the file or an opened file object
    fmt: Format specification
    offset: Offset from the start of the file from where to start the unpacking operation
    """
    if isinstance(file, str):
        if not os.path.isfile(file):
            raise ValueError('"{}" is not a regular file'.format(file))
    else:
        if not hasattr(file, 'read'):
            raise ValueError('Invalid file object')
        if hasattr(file, 'mode') and file.mode != 'rb':
            raise ValueError('Invalid opening mode')

    if not isinstance(offset, int) or offset < 0:
        raise ValueError('Invalid offset value')

    with fileutil.open_file(file, 'rb') as fp:
        file_len = fileutil.file_size(fp)
        pack_size = struct.calcsize(fmt)

        if file_len <= offset:
            return

        fp.seek(offset, os.SEEK_SET)

        if (file_len - offset) % pack_size == 0:
            if sys.version_info >= (3, 3):
                #return struct.iter_unpack(fmt, fp.read())  # Fix issue #1
                yield from struct.iter_unpack(fmt, fp.read())
            else:
                for unpacked_data in struct.iter_unpack(fmt, fp.read()):
                    yield unpacked_data
        else:
            # The length of the file isn't the multiple of struct.calcsize(fmt), so
            # don't call struct.iter_unpack directly.
            data = fp.read(pack_size)
            while data:
                if len(data) == pack_size:
                    yield struct.unpack(fmt, data)
                else:
                    break
                data = fp.read(pack_size)
Пример #2
0
    def _generate_waveform_sequence(self):
        if self._is_12_lead_ecg:
            maximum_waveform_sequences = 5  # PS3.3 A.34.3.4.3 Waveform Sequence
            maximum_waveform_samples = 16384  # PS3.3 A.34.3.4.5 Number of Waveform Samples
        else:
            maximum_waveform_sequences = 4  # PS3.3 A.34.4.4.2 Waveform Sequence
            maximum_waveform_samples = 2 ** 32 - 1  # NumberOfWaveformSamples's VR is `UL`.

        data_file_len = fileutil.file_size(self._file)
        pack_size = struct.calcsize(self._format)
        data_file_total_samples = data_file_len // pack_size
        saved_samples = maximum_waveform_sequences * maximum_waveform_samples
        if data_file_total_samples > saved_samples:
            warn_msg = (
                'File "{}" is too big. File size: {}, pack size: {}, format string: {}, '
                "total samples: {}, saved samples: {}, saved size: {}.".format(
                    fileutil.file_name(self._file),
                    data_file_len,
                    pack_size,
                    self._format,
                    data_file_total_samples,
                    saved_samples,
                    saved_samples * pack_size,
                )
            )
            if not _frozen:  # Fix issue #7
                warnings.warn(warn_msg)
            logger.warn(warn_msg)
            data_file_total_samples = saved_samples

        waveform_seq = dicom.sequence.Sequence()
        data_unpacker = unpacker.unpack_data_from_file(self._file, self._format)
        target_fmt = "<{}".format("h" * self._channels)
        adjusted_data = map(lambda v: map(self._adjust_callback, v), data_unpacker)
        while data_file_total_samples > 0:
            seq_item = dicom.dataset.Dataset()
            seq_item.WaveformOriginality = "ORIGINAL"  # Type 1

            seq_item.NumberOfWaveformChannels = self._channels  # Type 1.
            if self._is_12_lead_ecg:
                assert 1 <= seq_item.NumberOfWaveformChannels <= 13  # PS3.3 A.34.3.4.4
            else:
                assert 1 <= seq_item.NumberOfWaveformChannels <= 24  # PS3.3 A.34.4.4.3 Number of Waveform Channels

            if data_file_total_samples >= maximum_waveform_samples:
                seq_item.NumberOfWaveformSamples = maximum_waveform_samples  # Type 1. UL.
            else:
                seq_item.NumberOfWaveformSamples = data_file_total_samples  # Type 1. UL.
            data_file_total_samples -= seq_item.NumberOfWaveformSamples

            assert 200 <= self._sampling_frequency <= 1000  # DICOM PS3.3-2015a A.34.3.4.6
            seq_item.SamplingFrequency = "{:d}".format(self._sampling_frequency)  # Type 1. DS.

            seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence()  # Type 1.

            seq_item.WaveformBitsAllocated = (
                16
            )  # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation
            seq_item.WaveformSampleInterpretation = "SS"  # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation

            # The VR of `Waveform Padding Value` may be OB or OW, so:
            # seq_item.WaveformPaddingValue = b'\x00\x00'
            # will not work, instead:
            seq_item.add_new((0x5400, 0x100A), "OW", b"\x00\x80")  # Type 1C. OB or OW.

            data = bytearray()
            for i, d in zip(range(seq_item.NumberOfWaveformSamples), adjusted_data):
                data.extend(struct.pack(target_fmt, *d))
            seq_item.add_new((0x5400, 0x1010), "OW", bytes(data))  # WaveformData. Type 1. OB or OW.

            waveform_seq.append(seq_item)

        return waveform_seq
Пример #3
0
    def _generate_waveform_sequence(self):
        if self._is_12_lead_ecg:
            maximum_waveform_sequences = 5  # PS3.3 A.34.3.4.3 Waveform Sequence
            maximum_waveform_samples = 16384  # PS3.3 A.34.3.4.5 Number of Waveform Samples
        else:
            maximum_waveform_sequences = 4  # PS3.3 A.34.4.4.2 Waveform Sequence
            maximum_waveform_samples = 2**32 - 1  # NumberOfWaveformSamples's VR is `UL`.

        data_file_len = fileutil.file_size(self._file)
        pack_size = struct.calcsize(self._format)
        data_file_total_samples = data_file_len // pack_size
        saved_samples = maximum_waveform_sequences * maximum_waveform_samples
        if data_file_total_samples > saved_samples:
            warn_msg = 'File "{}" is too big. File size: {}, pack size: {}, format string: {}, ' \
                       'total samples: {}, saved samples: {}, saved size: {}.'.format(
                           fileutil.file_name(self._file), data_file_len, pack_size, self._format,
                           data_file_total_samples, saved_samples, saved_samples * pack_size)
            if not _frozen:  # Fix issue #7
                warnings.warn(warn_msg)
            logger.warn(warn_msg)
            data_file_total_samples = saved_samples

        waveform_seq = dicom.sequence.Sequence()
        data_unpacker = unpacker.unpack_data_from_file(self._file,
                                                       self._format)
        target_fmt = '<{}'.format('h' * self._channels)
        adjusted_data = map(lambda v: map(self._adjust_callback, v),
                            data_unpacker)
        while data_file_total_samples > 0:
            seq_item = dicom.dataset.Dataset()
            seq_item.WaveformOriginality = 'ORIGINAL'  # Type 1

            seq_item.NumberOfWaveformChannels = self._channels  # Type 1.
            if self._is_12_lead_ecg:
                assert 1 <= seq_item.NumberOfWaveformChannels <= 13  # PS3.3 A.34.3.4.4
            else:
                assert 1 <= seq_item.NumberOfWaveformChannels <= 24  # PS3.3 A.34.4.4.3 Number of Waveform Channels

            if data_file_total_samples >= maximum_waveform_samples:
                seq_item.NumberOfWaveformSamples = maximum_waveform_samples  # Type 1. UL.
            else:
                seq_item.NumberOfWaveformSamples = data_file_total_samples  # Type 1. UL.
            data_file_total_samples -= seq_item.NumberOfWaveformSamples

            assert 200 <= self._sampling_frequency <= 1000  # DICOM PS3.3-2015a A.34.3.4.6
            seq_item.SamplingFrequency = '{:d}'.format(
                self._sampling_frequency)  # Type 1. DS.

            seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence(
            )  # Type 1.

            seq_item.WaveformBitsAllocated = 16  # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation
            seq_item.WaveformSampleInterpretation = 'SS'  # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation

            # The VR of `Waveform Padding Value` may be OB or OW, so:
            #seq_item.WaveformPaddingValue = b'\x00\x00'
            # will not work, instead:
            seq_item.add_new((0x5400, 0x100A), 'OW',
                             b'\x00\x80')  # Type 1C. OB or OW.

            data = bytearray()
            for i, d in zip(range(seq_item.NumberOfWaveformSamples),
                            adjusted_data):
                data.extend(struct.pack(target_fmt, *d))
            seq_item.add_new((0x5400, 0x1010), 'OW',
                             bytes(data))  # WaveformData. Type 1. OB or OW.

            waveform_seq.append(seq_item)

        return waveform_seq
Пример #4
0
    def _generate_waveform_sequence(self):
        if self._is_12_lead_ecg:
            maximum_waveform_sequences = 5  # PS3.3 A.34.3.4.3 Waveform Sequence
            maximum_waveform_samples = 16384  # PS3.3 A.34.3.4.5 Number of Waveform Samples
        else:
            maximum_waveform_sequences = 4  # PS3.3 A.34.4.4.2 Waveform Sequence
            maximum_waveform_samples = 2 ** 32 - 1  # NumberOfWaveformSamples's VR is `UL`.
        
        data_file_len = fileutil.file_size(self._file)
        pack_size = struct.calcsize(self._format)
        data_file_total_samples = data_file_len // pack_size
        saved_samples = maximum_waveform_sequences * maximum_waveform_samples
        if data_file_total_samples > saved_samples:
            data_file_total_samples = saved_samples

        self._channel_labels = list(self._channel_labels)
        channel_cnt = len(self._channel_labels)
        
        waveform_seq = dicom.sequence.Sequence()
        data_unpacker = unpacker.unpack_data_from_file(self._file, self._format)
        target_fmt = '<{}'.format('h' * channel_cnt)
        
        if self._adjust_callback and hasattr(self._adjust_callback, '__call__'):
            adjusted_data = map(lambda v: map(self._adjust_callback, v), data_unpacker)
        else:
            adjusted_data = data_unpacker

        if self._is_12_lead_ecg:
            assert 1 <= channel_cnt <= 13  # PS3.3 A.34.3.4.4
        else:
            assert 1 <= channel_cnt <= 24  # PS3.3 A.34.4.4.3 Number of Waveform Channels

        assert 200 <= self._sampling_frequency <= 1000 # DICOM PS3.3-2015a A.34.3.4.6
                
        while data_file_total_samples > 0:
            seq_item = dicom.dataset.Dataset()
            seq_item.WaveformOriginality = 'ORIGINAL'  # Type 1
            
            seq_item.NumberOfWaveformChannels = channel_cnt  # Type 1.

            if data_file_total_samples >= maximum_waveform_samples:
                seq_item.NumberOfWaveformSamples = maximum_waveform_samples  # Type 1. UL.
            else:
                seq_item.NumberOfWaveformSamples = data_file_total_samples  # Type 1. UL.
            data_file_total_samples -= seq_item.NumberOfWaveformSamples

            seq_item.SamplingFrequency = '{:d}'.format(self._sampling_frequency)  # Type 1. DS.

            seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence()  # Type 1.

            seq_item.WaveformBitsAllocated = 16  # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation
            seq_item.WaveformSampleInterpretation = 'SS'  # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation

            # The VR of `Waveform Padding Value` may be OB or OW, so:
            #seq_item.WaveformPaddingValue = b'\x00\x00'
            # will not work, instead:
            seq_item.add_new((0x5400, 0x100A), 'OW', b'\x00\x80')  # Type 1C. OB or OW.

            data = bytearray()
            for i, d in zip(range(seq_item.NumberOfWaveformSamples), adjusted_data):
                data.extend(struct.pack(target_fmt, *d))
            seq_item.add_new((0x5400, 0x1010), 'OW', bytes(data)) # WaveformData. Type 1. OB or OW.

            waveform_seq.append(seq_item)
        
        return waveform_seq