def nearest_acquisition(db, date, patient, **kwargs): tmp = syd.find_one(db['Acquisition'], date=date) if tmp: # if an acquisition already exist no need to find or return tmp else: t = kwargs.get('t', None) modality = kwargs.get('modality', None) content_type = kwargs.get('content_type', None) injection = syd.nearest_injection(db, date, patient) if t == 'Listmode': dicom = syd.find(db['DicomSeries'], injection_id=injection['id']) if dicom != []: for d in dicom: if d['modality'] == modality and d[ 'content_type'] == content_type: acquisition = syd.find_one(db['Acquisition'], id=d['acquisition_id']) return acquisition else: # when no dicom are in the database result = None try: acq = syd.find(db['Acquisition'], injection_id=injection['id']) except: tqdm.write('Cannot find acquisition') if acq != []: minnimum = np.abs(date - acq[0]['date']) for tmp in acq: m = np.abs(date - tmp['date']) if m <= timedelta(1.0 / 24.0 / 60.0 * 1.0): # timedelta usefull for multiple listmode for example tomo + wholebody if m <= minnimum: minnimum = m result = tmp return result elif t == 'Dicom': result = None # try: acq = syd.find(db['Acquisition'], injection_id=injection['id']) # except: # tqdm.write('Cannot find acquisition') if acq: minnimum = np.abs(date - acq[0]['date']) for tmp in acq: m = np.abs(date - tmp['date']) if m <= timedelta(1.0 / 24.0 / 60.0 * 10.0): # timedelta usefull for multiple listmode for example tomo + wholebody if m < minnimum: minnimum = m result = tmp return result
def guess_fov(db, acquisition): same_study = [] same_modality = [] same_date = [] frame_of_reference_study = [] same_for_dicom = [] study = syd.find(db['DicomSeries'], acquisition_id=acquisition['id']) for s in study: # Accessing the frame of reference uid directly from the file for all dicom in the acquisition frame_of_reference_study.append(s['frame_of_reference_uid']) acq = syd.find(db['Acquisition'], injection_id=acquisition['injection_id']) acq = [i for i in acq if (acquisition['id'] != i['id']) ] # Removing the acquisition given in the parameter for a in acq: dicom_series = syd.find_one(db['DicomSeries'], acquisition_id=a['id']) if dicom_series is not None: try: if dicom_series['dicom_study_id'] == study[0][ 'dicom_study_id']: same_study.append(a) except: continue for a in same_study: if acquisition['modality'] == a['modality']: same_modality.append(a) for a in same_modality: if np.abs(acquisition['date'] - a['date']) < timedelta(1.0 / 24.0): same_date.append(a) for a in same_date: dicom_series = syd.find(db['DicomSeries'], acquisition_id=a['id']) for d in dicom_series: if d['frame_of_reference_uid'] in frame_of_reference_study: # taking the FOR from the dico same_for = a same_for_dicom.append(d) break # stoping at the first dicom found for d in same_for_dicom: str = d['series_description'] if str.find('FOV1') != -1 or str.find('FOV 1') != -1: acquisition['fov'] = 2 syd.update_one(db['Acquisition'], acquisition) tqdm.write(f'Update of acquisition :{acquisition}') return {} elif str.find('FOV2') != -1 or str.find('FOV 2') != -1: acquisition['fov'] = 1 syd.update_one(db['Acquisition'], acquisition) tqdm.write(f'Update of acquisition :{acquisition}') return {} elif str.find('MFOV') != -1: print('') else: s = f'Cannot update acquisition {acquisition}' syd.raise_except(s)
def find_series(db, patient_id, grep): # select study from this patient studies = syd.find(db['DicomStudy'], patient_id=patient_id) study_ids = [s.id for s in studies] # series elements = syd.find(db['DicomSeries'], dicom_study_id=study_ids) # select series grep.append('%ignore') elements, s = syd.grep(db, 'DicomSeries', elements, grep=grep) return elements, s
def tabular_add_abs_filename(db, table_name, elements): # only for image, dicomstudy, dicomseries, dicomfile # image -> file_mhd_id file_raw_id => file # study -> NO # series -> => dicomfile => file_id ; several so only first one or all ? if table_name == 'DicomSeries': ids = [e.id for e in elements] dicomfiles = syd.find(db['DicomFile'], dicom_series_id=ids) ids = [df.file_id for df in dicomfiles] files = syd.find(db['File'], id=ids) map_df = {df.dicom_series_id: df for df in dicomfiles} # keep only one map_f = {f.id: f for f in files} # keep only one for e in elements: try: df = map_df[e.id] f = map_f[df.id] e['abs_filename'] = syd.get_file_absolute_filename(db, f) except: e['abs_filename'] = 'file_does_not_exist' # print('warning, cannot find', e.id, df.id) if table_name == 'DicomFile': ids = [e.file_id for e in elements] files = syd.find(db['File'], id=ids) map_f = {f.id: f for f in files} for e in elements: try: f = map_f[e.file_id] e['abs_filename'] = syd.get_file_absolute_filename(db, f) except: e['abs_filename'] = 'file_does_not_exist' # print('warning, cannot find', e.id, df.id) if table_name == 'Image': ids = [e.file_mhd_id for e in elements] files = syd.find(db['File'], id=ids) map_f = {f.id: f for f in files} for e in elements: try: f = map_f[e.file_mhd_id] e['abs_filename'] = syd.get_file_absolute_filename(db, f) except: e['abs_filename'] = 'file_does_not_exist'
def tabular_add_nb_dicom_files(db, table_name, elements): if table_name != 'DicomSeries': return for e in elements: dicomfiles = syd.find(db['DicomFile'], dicom_series_id=e.id) e['nb_dicom_files'] = len(dicomfiles)
def tabular_get_line_format(db, table_name, format_name, element): ''' Retrieve the line format from the format name to build a tabluar ''' table_name = syd.guess_table_name(db, table_name) formats = syd.find(db['PrintFormat'], table_name=table_name) df = None ff = None for f in formats: if f.name == format_name: df = f.format ff = f if df == None and format_name != 'raw': s = "Cannot find the format '" + format_name + "' in table '" + table_name + "' using 'raw'" syd.warning(s) format_name = 'raw' if format_name == 'raw': df = '' for k in element: df += '{' + str(k) + '} ' sorting_key = '' if ff: if 'sorting_key' in ff: sorting_key = ff.sorting_key return df, sorting_key
def search_injection_from_info(db, dicom_study, rad_info): patient_id = dicom_study.patient_id all_rad = syd.find(db['Radionuclide']) rad_names = [n.name for n in all_rad] if len(rad_info.code) != 1: tqdm.write('Error: several radionuclide found. Dont know what to do') return None # look for radionuclide name and date rad_code = rad_info.code[0] rad_date = datetime.strptime(rad_info.date[0], '%Y%m%d%H%M%S') s = [str_match(rad_code, n) for n in rad_names] s = np.array(s) i = np.argmax(s) rad_name = rad_names[i] # search if injections exist for this patient and this rad radionuclide = syd.find_one(db['Radionuclide'], name=rad_name) rad_info.radionuclide_id = radionuclide.id inj_candidates = syd.find(db['Injection'], radionuclide_id=radionuclide.id, patient_id=patient_id) if len(inj_candidates) == 0: return None # check date and activity max_time_days = timedelta( 1.0) # 1 day # FIXME <------------------------ options found = None for ic in inj_candidates: d = ic.date if d > rad_date: t = d - rad_date else: t = rad_date - d if t <= max_time_days: act_diff = np.fabs(ic.activity_in_mbq - rad_info.total_dose) found = ic tqdm.write('Timedelta superior to 10 minutes') if found: tqdm.write(f'Injection found : {found}') return found else: return None
def find_acquisition(db, injection): acquisition = syd.find(db['Acquisition'], injection_id=injection['id']) acquisition = syd.sort_elements(acquisition, 'date') struct = [] elements = [] for tmp in acquisition: listmode = syd.find(db['Listmode'], acquisition_id=tmp['id']) dicom_series = syd.find(db['DicomSeries'], acquisition_id=tmp['id']) for d in dicom_series: dicom_struct = syd.find(db['DicomStruct'], dicom_series_id=d['id']) struct = struct + dicom_struct el = { 'acquisition': tmp, 'listmode': listmode, 'dicom_serie': dicom_series, 'dicom_struct': struct } elements.append(el) return elements
def get_dicom_struct_files(db, struct): """ Return the list of files associated with the struct """ dicom_files = syd.find(db['DicomFile'], dicom_struct_id=struct['id']) # sort by instance_number dicom_files = sorted( dicom_files, key=lambda kv: (kv['instance_number'] is None, kv['instance_number'])) # get all associated id of the files fids = [df['file_id'] for df in dicom_files] # find files res = syd.find(db['File'], id=fids) # FIXME sort res like fids (?) return res
def nearest_injection(db, date, patient): var = syd.find(db['Injection'], patient_id=patient['id']) min = np.abs(date - var[0]['date']) for tmp in var: if not tmp['date']: continue m = np.abs(date - tmp['date']) # if date < tmp['date']: # tqdm.write(f'Injection {tmp["date"]} is after the wanted date {date}') if m <= min: min = m result = tmp return result
def tabular_add_time_from_inj(db, table_name, elements): if table_name != 'DicomSeries' and table_name != 'Image': return ids = [e.injection_id for e in elements] injections = syd.find(db['Injection'], id=ids) map_inj = {inj.id: inj for inj in injections} # keep only one for e in elements: if not e.injection_id in map_inj: continue inj = map_inj[e.injection_id] date1 = inj.date date2 = e.acquisition_date # print(date1, date2) e.time_from_inj = date2 - date1
def get_sub_elements(db, elements, format_info, subelements): # format_info.field_format_name, # study->patient->name # format_info.tables, # DicomStudy Patient # format_info.field_id_names, # study_id patient_id # format_info.field_name) # name # get al subelements current_table = format_info.tables[0] current_field_id_name = format_info.field_id_names[0] ids = [elem[current_field_id_name] for elem in subelements] ## repetition, unique ? FIXME new_subelements = syd.find(current_table, id=ids) if len(format_info.tables) == 1: # correspondance current_id -> new_id subelements_map = {} for s in new_subelements: try: subelements_map[s.id] = s[format_info.field_name] except: subelements_map[s.id] = '?' for elem in elements: index = elem[format_info.field_format_name] if index: # because can be None elem[format_info.field_format_name] = subelements_map[index] else: elem[format_info.field_format_name] = '?' return elements # correspondance current_id -> new_id subelements_map = {} for s in new_subelements: subelements_map[s.id] = s[format_info.field_id_names[1]] # change the id for elem in elements: index = elem[format_info.field_format_name] if index: elem[format_info.field_format_name] = subelements_map[index] # recurse removing the first format_info.tables = format_info.tables[1:] format_info.field_id_names = format_info.field_id_names[1:] return get_sub_elements(db, elements, format_info, new_subelements)
def search_injection(db, ds, dicom_study, dicom_series): patient_id = dicom_study.patient_id inj_candidates = syd.find(db['Injection'], patient_id=patient_id) dicom_date = dicom_series.acquisition_date # check date is before the dicom found = None for ic in inj_candidates: if not ic.date: continue if ic.date < dicom_date: if found: if ic.date > found.date: found = ic # tqdm.write('Several injections may be associated. Ignoring injection') else: found = ic if found: tqdm.write(f'Injection found : {found}') return found else: return None
def insert_listmode_from_file(db, filename, patient): patient_folder = os.path.join(db.absolute_data_folder, patient['name']) e = check_type(filename) ftype, end = e.split('.') if ftype != 'Listmode': tqdm.write('Ignoring {}: it is not a Listmode'.format(filename)) return None if end == 'dat': date = return_date(filename.name) elif end == 'I': ds = pydicom.read_file(str(filename)) try: acquisition_date = ds.AcquisitionDate acquisition_time = ds.AcquisitionTime date = syd.dcm_str_to_date(acquisition_date + acquisition_time) except: date = return_date_str(ds[0x0008, 0x002a].value) else: tqdm.write('Date not found on DICOM') return None try: modality, content_type = syd.guess_content_type(filename) except: s = f'Cannot guess content_type' syd.raise_except(s) # Check if the listmode is already in the file with date and name listmode = syd.find(db['Listmode'], date=date, modality=modality) if listmode is not None: for l in listmode: file = syd.find_one(db['File'], id=l['file_id']) if file['filename'].endswith(filename.name): tqdm.write('Ignoring {} : Listmode already in the db'.format( filename)) return None # Check if the acquisition exists or not res = syd.nearest_acquisition(db, date, patient, t="Listmode", modality=modality, content_type=content_type) if res is not None: # When an acquisition is found a1 = res try: syd.guess_fov(db, a1) except: tqdm.write(f'Cannot guess fov for acquisition : {a1}') else: # Creation of the acquisition if it does not exist d1 = syd.nearest_injection(db, date, patient) a0 = {'injection_id': d1['id'], 'modality': modality, 'date': date} syd.insert_one(db['Acquisition'], a0) a1 = syd.find_one(db['Acquisition'], date=a0['date']) try: syd.guess_fov(db, a1) except: tqdm.write(f'Cannot guess fov for acquisition : {a1}') # Listmode creation then insertion l0 = { 'acquisition_id': a1['id'], 'date': date, 'modality': modality, 'content_type': content_type } syd.insert_one(db['Listmode'], l0) l1 = syd.find(db['Listmode'], acquisition_id=a1['id']) acqui_folder = os.path.join(patient_folder, 'acqui_' + str(a1['id'])) base_filename = 'LM_' + str(l1[len(l1) - 1]['id']) + '_' + str( filename.name) if not os.path.exists(acqui_folder): os.makedirs(acqui_folder) # File creation for the file table afile = Box() afile.folder = os.path.join(patient['name'], 'acqui_' + str(a1['id'])) afile.filename = base_filename syd.insert_one(db['File'], afile) # Update of listmode to account for the file_id f0 = syd.find_one(db['File'], filename=afile.filename) l2 = { 'id': l1[len(l1) - 1]['id'], 'acquisition_id': a1['id'], 'file_id': f0['id'] } syd.update_one(db['Listmode'], l2) # Moving the file copy(filename, acqui_folder) old_filename = os.path.join(acqui_folder, filename.name) new_filename = os.path.join(acqui_folder, base_filename) move(old_filename, new_filename) # return create listmode return l2
def find_images(db, patient_id, grep): elements = syd.find(db['Image'], patient_id=patient_id) elements, s = syd.grep(db, 'Image', elements, grep=grep) return elements, s
def guess_stitch(db, acquisition): if acquisition['fov'] == '1': tmp = syd.find(db['Acquisition'], fov='2') elif acquisition['fov'] == '2': tmp = syd.find(db['Acquisition'], fov='1') else: tqdm.write(f'Cannot determnied the fov of {acquisition}') return {} injection = syd.find_one(db['Injection'], id=acquisition['injection_id']) patient = syd.find_one(db['Patient'], id=injection['patient_id']) dicom1 = syd.find(db['DicomSeries'], acquisition_id=acquisition['id']) res = [] epsilon = 0.1 delta = timedelta(1.0 / 24.0 * 2.0) for t in tmp: diff = np.abs(t['date'] - acquisition['date']) if diff < delta: dicom2 = syd.find(db['DicomSeries'], acquisition_id=t['id']) max = 0.0 for d1 in dicom1: for d2 in dicom2: ratio = difflib.SequenceMatcher( None, d1['series_description'], d2['series_description']).ratio() if max - ratio < epsilon: max = ratio r = [d1, d2] res.append(r) for r in res: image1 = syd.find_one(db['Image'], dicom_series_id=r[0]['id']) file1 = syd.find_one(db['File'], id=image1['file_mhd_id']) image2 = syd.find_one(db['Image'], dicom_series_id=r[1]['id']) file2 = syd.find_one(db['File'], id=image2['file_mhd_id']) path1 = os.path.join(db.absolute_data_folder, os.path.join(file1['folder'], file1['filename'])) path2 = os.path.join(db.absolute_data_folder, os.path.join(file2['folder'], file2['filename'])) im1 = itk.imread(path1) im2 = itk.imread(path2) result = sti.stitch_image(im1, im2, 2, 0) itk.imwrite(result, './tmp.mhd') if acquisition['fov'] == '1': im = { 'patient_id': patient['id'], 'injection_id': injection['id'], 'acquisition_id': acquisition['id'], 'pixel_type': 'float', 'pixel_unit': 'counts', 'modality': acquisition['modality'], 'frame_of_reference_uid': r[0]['frame_of_reference_uid'], 'acquisition_date': acquisition['date'] } else: im = { 'patient_id': patient['id'], 'injection_id': injection['id'], 'acquisition_id': tmp['id'], 'pixel_type': 'float', 'pixel_unit': 'counts', 'modality': tmp['modality'], 'frame_of_reference_uid': r[0]['frame_of_reference_uid'], 'acquisition_date': tmp['date'] } e = syd.insert_write_new_image(db, im, itk.imread('./tmp.mhd')) os.remove('./tmp.mhd') os.remove('./tmp.raw') return res
def insert_roi_from_struct(db, struct, crop): """ Insert an ROI from a DicomStruct file """ roi = Box() res = [] series_id = struct['dicom_series_id'] dicom_series = syd.find_one(db['DicomSeries'], id=series_id) acquisition = syd.find_one(db['Acquisition'], id=dicom_series['acquisition_id']) injection_id = acquisition['injection_id'] acquisition_id = dicom_series['acquisition_id'] injection = syd.find_one(db['Injection'], id=injection_id) patient = syd.find_one(db['Patient'], id=injection['patient_id']) ### Getting the CT image path ### image_ct = syd.find_one(db['Image'], dicom_series_id=series_id) try: file_img = syd.find_one(db['File'], id=image_ct['file_mhd_id']) except: print('Could not find the CT image in the database') filename_img_ct = db.absolute_data_folder + '/' + file_img[ 'folder'] + '/' + file_img['filename'] ### Getting the DicomStruct dicom path ### dicom_file = syd.find_one(db['DicomFile'], dicom_struct_id=struct['id']) file_struct = syd.find_one(db['File'], id=dicom_file['file_id']) filename_struct = db.absolute_data_folder + '/' + file_struct[ 'folder'] + '/' + file_struct['filename'] ### Verifying if the ROI already exists in the table ### e = syd.find(db['Roi'], dicom_struct_id=struct['id']) if e != []: return {} ### Using GateTools to extract the image from the Dicom File ### structset = pydicom.read_file(filename_struct) img_ct = itk.imread(filename_img_ct, itk.F) base_filename, extension = os.path.splitext(filename_img_ct) roi_names = gt.list_roinames(structset) roi_objs = list() npbar = 0 pbar = None for r in roi_names: try: aroi = gt.region_of_interest(structset, r) if not aroi.have_mask(): tqdm.write(f'Mask for {r} not possible') roi_objs.append(aroi) except: tqdm.write(f'Something is wrong with ROI {r}') roi.remove(r) if npbar > 0: pbar = tqdm(total=npbar, leave=False) for roiname, aroi in zip(roi_names, roi_objs): try: mask = aroi.get_mask(img_ct, corrected=False, pbar=pbar) if crop: mask = gt.image_auto_crop(mask, bg=0) output_filename = base_filename + '_' + ''.join( e for e in roiname if e.isalnum()) + '.mhd' im = { 'patient_id': patient['id'], 'injection_id': injection_id, 'acquisition_id': acquisition_id, 'pixel_unit': 'binary', 'pixel_type': 'float', 'frame_of_reference_uid': dicom_series['frame_of_reference_uid'], 'modality': 'RTSTRUCT', 'labels': roiname } im = syd.insert_write_new_image(db, im, mask) roi = { 'dicom_struct_id': struct['id'], 'image_id': im['id'], 'frame_of_reference_uid': struct['frame_of_reference_uid'], 'name': roiname, 'labels': None } roi = syd.insert_one(db['Roi'], roi) im['roi_id'] = roi['id'] res.append(roi) syd.update_one(db['Image'], im) syd.update_roi_characteristics(db, roi) except: tqdm.write(f'Error in {roiname, aroi}') if npbar > 0: pbar.close() return res