def nii2dicom(ni, ds): if len(ni.shape) == 3: I, J, K = ni.shape T = 1 elif len(ni.shape) == 4: I, J, K, T = ni.shape else: raise (Exception(f"tried to convert nifti with shape {ni.shape}")) orientation = ni.affine orientation33 = orientation[:3, :3] image_position0 = orientation[:3, 3] pixel_spacing = list( map(np.linalg.norm, [orientation[:3, 0], orientation[:3, 1]])) slice_spacing = np.linalg.norm(orientation[:3, 2]) slice_thickness = ni.header["pixdim"][3] orientation_rescaled = orientation33 @ np.diag( [1 / pixel_spacing[0], 1 / pixel_spacing[1], 1 / slice_spacing]) orientation_dcm = np.reshape(orientation_rescaled[:2, :], 6) slice_vector = np.cross(orientation_rescaled[0, :], orientation_rescaled[1, :]) scl_slope = 1 if np.isnan( ni.header["scl_slope"]) else ni.header["scl_slope"] scl_inter = 0 if np.isnan( ni.header["scl_inter"]) else ni.header["scl_inter"] raw = ni.get_fdata() minvol = np.min(raw) maxvol = np.max(raw) raw -= minvol scl_inter += minvol * scl_slope raw *= 65536 / (maxvol - minvol) scl_slope *= (maxvol - minvol) / 65536 minval = scl_slope * np.min(raw) + scl_inter maxval = scl_slope * np.max(raw) + scl_inter uintVOL = np.uint16(np.round(raw)) out_dcms = [] for k in range(K): for t in range(T): d = Dataset() for elem in ds: if elem.tag.group in [0x8, 0x10, 0x18, 0x20, 0x28, 0x32, 0x40]: d[elem.tag] = deepcopy(elem) fix_meta_info(d) d.SOPInstanceUID = generate_uid(entropy_srcs=[ d.SeriesInstanceUID, d.SeriesDescription, str(k), str(t), str(uintVOL[:2, :2, k]) ]) d.SeriesInstanceUID = generate_uid( entropy_srcs=[d.SeriesInstanceUID, d.SeriesDescription]) d.PixelSpacing = pixel_spacing d.SeriesNumber += 1000 d.SpacingBetweenSlices = slice_spacing d.SliceThickness = slice_thickness d.ImageOrientationPatient = list(orientation_dcm) d.ImagePositionPatient = list(image_position0 + (k - 1) * slice_vector * slice_spacing) d.SliceLocation = np.dot(d.ImagePositionPatient, slice_vector) d.Rows = J d.Columns = I d.InstanceNumber = k d.AcquisitionNumber = t if len(ni.shape) == 3: d.PixelData = np.flip(uintVOL[:, :, k]).T.copy(order='C').tobytes() else: d.PixelData = np.flip(uintVOL[:, :, k, t]).T.copy(order='C').tobytes() #d.Pixel Data = transpose(uintVOL[end:-1:1,end:-1:1,k,t]) # flip from RAS to LPS d.BitsAllocated = 16 d.BitsStored = 16 d.HighBit = 15 d.PixelRepresentation = 0 d.WindowCenter = (maxval + minval) / 2 d.WindowWidth = (maxval - minval) d.WindowCenterWidthExplanation = "LINEAR" d.RescaleIntercept = scl_inter d.RescaleSlope = scl_slope fix_meta_info(d) out_dcms.append(d) return out_dcms
def make_dataset(query_level='series', **kwargs): if query_level == 'study': d = Dataset() d.QueryRetrieveLevel = 'STUDY' d.StudyDate = '' #Required d.StudyInstanceUID = '' #Optional d.PatientName = '' d.PatientID = '' d.AccessionNumber = '' d.StudyDescription = '' d.StudyID = '' d.StudyTime = '' d.StudyInstanceUID = '' d.NumberOfStudyRelatedSeries = '' d.StationName = '' d.SpecificCharacterSet = '' d.ModalitiesInStudy = '' d.Manufacturer = '' d.ManufacturerModelName = '' d.InstitutionName = '' if query_level == 'series': d = Dataset() d.QueryRetrieveLevel = 'SERIES' d.SeriesDescription = '' d.SeriesNumber = '' d.SeriesInstanceUID = '' d.Modality = '' d.NumberOfSeriesRelatedInstances = '' d.StationName = '' d.SpecificCharacterSet = '' d.SeriesDate = '' d.AccessionNumber = '' d.SeriesTime = '' d.Manufacturer = '' d.ManufacturerModelName = '' d.SOPClassUID = '' if query_level == 'image': d = Dataset() d.QueryRetrieveLevel = "IMAGE" #Required d.SeriesInstanceUID = '' #Optional d.StudyInstanceUID = '' d.SOPInstanceUID = '' d.AccessionNumber = '' d.StationName = '' d.SeriesDate = '' d.SeriesTime = '' d.SOPClassUID = '' d.InstanceNumber = '' d.SpecificCharacterSet = '' d.StudyInstanceUID = '' if query_level == 'patient': #todo find optional tags d = Dataset() d.QueryRetrieveLevel = 'PATIENT' d.PatientName = '' d.PatientSex = '' d.PatientID = '' d.AccessionNumber = '' for k, v in kwargs.items(): try: d = write_tag_by_keyword(d, k, v) except: print(f'could not write tag: "{k}" with value: {v}') return d