Exemple #1
0
def convert_npy_to_dicom(npy_array, fname=None,
                         slice_thickness=None,
                         pixel_spacing=None,
                         spacing_between_slices=None,
                         single_file_mode=True
                         ):
    """
    convert npy array to dicom
    :param npy_array: npy array
    :param fname: file name
    :param slice_thickness: slice thickness
    :param spacing_between_slices: spacing between slices
    :param pixel_spacing: pixel spacing
    :param single_file_mode: if False, slice by slice dicom files are generated
    :return:  dcm
    """
    uint16_img = np.array(npy_array).astype(float)
    uint16_img = (
            (uint16_img - uint16_img.min()) /
            (uint16_img.max() - uint16_img.min()) * (2 ** 16 - 1)
    ).astype(np.uint16)
    dim = len(uint16_img.shape)
    if dim == 1:
        raise Exception('Cannot convert 1D array to dicom')
    elif dim == 2:
        uint16_img = uint16_img[np.newaxis, :, :]
    elif dim > 3:
        raise Exception('{}D array is not supported.'.format(dim))
    x_min = float(npy_array.min())
    x_max = float(npy_array.max())
    x_max_min = x_max - x_min
    t_max = (2 ** 16) - 1
    slope = x_max_min / t_max
    intercept = x_min
    now = datetime.now().timestamp()

    file_meta = Dataset()
    file_meta.MediaStorageSOPClassUID = '1.2.840.100008.5.1.4.1.1.20'

    file_meta.MediaStorageSOPInstanceUID = f'333.333.0.0.0.333.333333333.{now}'
    file_meta.ImplementationClassUID = '0.0.0.0'
    file_meta.FileMetaInformationGroupLength = 140
    dcm = FileDataset(fname, {}, file_meta=file_meta, preamble=b'\0' * 128)

    dcm.Modality = 'OT'
    if single_file_mode:
        dcm.ImageType = ["DERIVED", "PRIMARY", "RECON TOMO", "EMISSION"]
    else:
        dcm.ImageType = ["DERIVED", "SECONDARY"]

    dcm.ContentDate = datetime.now().strftime('%Y%m%d')
    dcm.ContentTime = datetime.now().strftime('%H%M%S')
    dcm.InstanceCreationDate = datetime.now().strftime('%Y%m%d')
    dcm.InstanceCreationTime = datetime.now().strftime('%H%M%S')
    dcm.SeriesDate = datetime.now().strftime('%Y%m%d')
    dcm.SeriesTime = datetime.now().strftime('%H%M%S')
    dcm.AcquisitionTime = datetime.now().strftime('%H%M%S')
    dcm.PatientName = os.path.basename(fname)
    dcm.PatientBirthDate = datetime.now().strftime('%Y%m%d')
    dcm.PatientAge = '000Y'
    dcm.PatientSize = 1
    dcm.PatientWeight = 1
    dcm.PatientID = os.path.basename(fname)
    dcm.PatientSex = 'O'
    dcm.StudyDescription = os.path.basename(fname)
    dcm.StudyDate = datetime.now().strftime('%Y%m%d')
    dcm.StudyTime = datetime.now().strftime('%H%M%S')
    dcm.StudyID = os.path.basename(fname)
    dcm.SeriesDescription = os.path.basename(fname)
    dcm.SamplesPerPixel = 1
    dcm.PhotometricInterpretation = 'MONOCHROME2'
    dcm.PixelRepresentation = 0  # unsigned 0, signed 1
    dcm.HighBit = 16
    dcm.BitsStored = 16
    dcm.BitsAllocated = 16
    dcm.Columns = uint16_img.shape[2]
    dcm.Rows = uint16_img.shape[1]
    if single_file_mode:
        dcm.NumberOfFrames = uint16_img.shape[0]
        dcm.ImagesInAquisition = uint16_img.shape[0]
        dcm.SliceVector = (np.arange(uint16_img.shape[0]) + 1).tolist()
        dcm.FrameIncrementPointer = [(0x0054, 0x0080)]
    else:
        dcm.NumberOfTimeSlices = 1
        dcm.FrameReferenceTime = 0.
    dcm.ImageOrientationPatient = [1., 0., 0., 0., -1., 0.]
    dcm.SeriesNumber = 0
    dcm.NumberOfSlices = uint16_img.shape[0]
    dcm.RescaleIntercept = intercept
    dcm.RescaleSlope = slope
    dcm.Units = "NONE"
    dcm.DecayCorrection = "NONE"
    dcm.InstanceCreatorUID = '333.333.0.0.0'
    dcm.SOPClassUID = '1.2.840.10008.5.1.4.1.1.20'
    dcm.SliceThickness = 1 if slice_thickness is None else slice_thickness
    if spacing_between_slices is None:
        dcm.SpacingBetweenSlices = 1 if slice_thickness is None else slice_thickness
    else:
        dcm.SpacingBetweenSlices = spacing_between_slices
    ps = 1 if pixel_spacing is None else pixel_spacing
    if isinstance(ps, list) or isinstance(ps, np.ndarray):
        dcm.PixelSpacing = [ps[0], ps[1]]
    else:
        dcm.PixelSpacing = [ps, ps]

    if single_file_mode:
        dcm.PixelData = uint16_img.tostring()
        dcm.StudyInstanceUID = f'333.333.0.0.0.{now}'
        dcm.SeriesInstanceUID = f'333.333.0.0.0.{now}.3333'
        dcm.FrameOfReferenceUID = dcm.StudyInstanceUID
        dcm.SeriesNumber = 0
        dcm.InstanceNumber = 0
        dcm.BodyPartExamined = 'UNKNOWN'
        dcm.Manufacturer = 'DicomConversionUtils'
        dcm.DeviceSerialNumber = ''
        dcm.AcquisitionTerminationCondition = 'MANU'
        dcm.SoftwareVersions = f'{pydicom_ext_version}'
        dcm.AccessionNumber = '{:13d}'.format(random.randint(0, 1e13))
        dcm.InstitutionName = 'DicomConversionUtils'
        dcm.ImagePositionPatient = [0, 0, 0]
        if fname is not None:
            dcm.save_as(fname, write_like_original=False)
        return dcm
    else:
        dcms = []
        for slice_idx in range(uint16_img.shape[0]):
            dcm.SOPInstanceUID = f'333.333.0.0.0.{now}.{slice_idx:06d}'
            dcm.PixelData = uint16_img[slice_idx].tostring()
            dcm.StudyInstanceUID = f'333.333.0.0.0.{now}'
            dcm.SeriesInstanceUID = f'333.333.0.0.0.{now}.3333'
            dcm.FrameOfReferenceUID = dcm.StudyInstanceUID
            dcm.InstanceNumber = slice_idx
            dcm.BodyPartExamined = 'UNKNOWN'
            dcm.Manufacturer = 'DicomConversionUtils'
            dcm.DeviceSerialNumber = ''
            dcm.AcquisitionTerminationCondition = 'MANU'
            dcm.SoftwareVersions = f'{pydicom_ext_version}'
            dcm.AccessionNumber = '{:13d}'.format(random.randint(0, 1e13))
            dcm.InstitutionName = 'DicomConversionUtils'
            dcm.ImageIndex = slice_idx
            if spacing_between_slices is None:
                if slice_thickness is None:
                    dcm.ImagePositionPatient = [0, 0, slice_idx]
                    dcm.SliceLocation = slice_idx
                else:
                    dcm.ImagePositionPatient = [0, 0, slice_idx * slice_thickness]
                    dcm.SliceLocation = slice_idx * slice_thickness
            else:
                dcm.ImagePositionPatient = [0, 0, slice_idx * spacing_between_slices]
                dcm.SliceLocation = slice_idx * spacing_between_slices

            dcms.append(dcm)
            if fname is not None:
                f = copy.copy(fname)
                if ".dcm" in f:
                    f = f.replace(".dcm", f"_{slice_idx:06d}.dcm")
                else:
                    f += f"_{slice_idx:06d}.dcm"
                dcm.save_as(f, write_like_original=False)
        return dcms
Exemple #2
0
def convert_npy_to_dicom(fname,
                         npy_array,
                         slice_thickness=None,
                         pixel_spacing=None):
    """
    convert npy array to dicom
    :param fname: file name
    :param npy_array: npy array
    :param slice_thickness: slice thickness
    :param pixel_spacing: pixel spacing
    :return:  dcm
    """

    uint16_img = np.array(npy_array)
    uint16_img = ((uint16_img - uint16_img.min()) /
                  (uint16_img.max() - uint16_img.min()) * (2**16 - 1)).astype(
                      np.uint16)
    dim = len(uint16_img.shape)
    if dim == 1:
        raise Exception('Cannot convert 1D array to dicom')
    elif dim == 2:
        uint16_img = uint16_img[np.newaxis, :, :]
    elif dim > 3:
        raise Exception('{}D array is not supported.'.format(dim))
    x_min = npy_array.min()
    x_max = npy_array.max()
    x_max_min = x_max - x_min
    t_max = (2**16) - 1
    slope = x_max_min / t_max
    intercept = x_min

    file_meta = Dataset()
    file_meta.MediaStorageSOPClassUID = '0.0.000.000000.0.0.0.0.0.00'
    file_meta.MediaStorageSOPInstanceUID = \
        '333.333.0.0.0.333.333333333.{}'.format(
            datetime.now().timestamp())
    file_meta.ImplementationClassUID = '0.0.0.0'
    dcm = FileDataset(fname, {}, file_meta=file_meta, preamble=b'\0' * 128)

    dcm.Modality = 'OT'
    dcm.ImageType = ['ORIGINAL', 'PRIMARY']

    dcm.ContentDate = datetime.now().strftime('%Y%m%d')
    dcm.ContentTime = datetime.now().strftime('%H%M%S')
    dcm.InstanceCreationDate = datetime.now().strftime('%Y%m%d')
    dcm.InstanceCreationTime = datetime.now().strftime('%H%M%S')
    dcm.SeriesDate = datetime.now().strftime('%Y%m%d')
    dcm.SeriesTime = datetime.now().strftime('%H%M%S')
    dcm.AcquisitionTime = datetime.now().strftime('%H%M%S')
    dcm.PatientName = os.path.basename(fname)
    dcm.PatientBirthDate = datetime.now().strftime('%Y%m%d')
    dcm.PatientAge = '000Y'
    dcm.PatientSize = 1
    dcm.PatientWeight = 1
    dcm.PatientID = os.path.basename(fname)
    dcm.PatientSex = 'O'
    dcm.StudyDescription = os.path.basename(fname)
    dcm.StudyDate = datetime.now().strftime('%Y%m%d')
    dcm.StudyTime = datetime.now().strftime('%H%M%S')
    dcm.StudyID = os.path.basename(fname)
    dcm.SeriesDescription = os.path.basename(fname)
    dcm.SamplesPerPixel = 1
    dcm.PhotometricInterpretation = 'MONOCHROME1'
    dcm.PixelRepresentation = 0  # unsigned 0, signed 1
    dcm.HighBit = 16
    dcm.BitsStored = 16
    dcm.BitsAllocated = 16
    dcm.SmallestImagePixelValue = uint16_img.min()
    dcm.LargestImagePixelValue = uint16_img.max()
    dcm.Columns = uint16_img.shape[2]
    dcm.Rows = uint16_img.shape[1]
    dcm.NumberOfFrames = uint16_img.shape[0]
    dcm.NumberOfSlices = uint16_img.shape[0]
    dcm.ImagesInAquisition = uint16_img.shape[0]
    dcm.RescaleIntercept = intercept
    dcm.RescaleSlope = slope
    dcm.SliceVector = (np.arange(uint16_img.shape[0]) + 1).tolist()
    dcm.FrameIncrementPointer = [(0x0054, 0x0080)]

    dcm.PixelData = uint16_img.tostring()
    dcm.SliceThickness = 1 if slice_thickness is None else slice_thickness
    ps = 1 if pixel_spacing is None else pixel_spacing
    if isinstance(ps, list) or isinstance(ps, np.ndarray):
        dcm.PixelSpacing = [ps[0], ps[1]]
    else:
        dcm.PixelSpacing = [ps, ps]
    dcm.InstanceCreatorUID = '333.333.0.0.0'
    dcm.SOPClassUID = '0.0.000.00000.0.0.0.0.0.00'
    dcm.SOPInstanceUID = '333.333.0.0.0.{}'.format(datetime.now().timestamp())
    dcm.StudyInstanceUID = '333.333.0.0.0.{}'.format(
        datetime.now().timestamp())
    dcm.SeriesInstanceUID = '333.333.0.0.0.{}.3333'.format(
        datetime.now().timestamp())
    dcm.FrameOfReferenceUID = dcm.StudyInstanceUID
    dcm.SeriesNumber = 0
    dcm.InstanceNumber = 0
    dcm.BodyPartExamined = 'UNKNOWN'
    dcm.Manufacturer = 'DicomConversionUtils'
    dcm.DeviceSerialNumber = ''
    dcm.AcquisitionTerminationCondition = 'MANU'
    dcm.SoftwareVersions = 'UNKNOWN'
    dcm.AccessionNumber = '{:13d}'.format(random.randint(0, 1e13))
    dcm.InstitutionName = 'DicomConversionUtils'

    dcm.save_as(fname)
    return dcm