init commit
This commit is contained in:
parent
dcbe9d85c2
commit
e774e4df7c
5 changed files with 2143 additions and 0 deletions
297
accuray.py
Normal file
297
accuray.py
Normal file
|
@ -0,0 +1,297 @@
|
|||
|
||||
import base64
|
||||
import difflib
|
||||
import hashlib
|
||||
import os
|
||||
import shelve
|
||||
import shutil
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
from platipy.dicom.io.rtdose_to_nifti import convert_rtdose
|
||||
from platipy.dicom.io.rtstruct_to_nifti import convert_rtstruct
|
||||
|
||||
import lxml.etree
|
||||
import lxml.objectify
|
||||
import pydicom
|
||||
import SimpleITK as sitk
|
||||
|
||||
PATIENTS_ROOT='/mnt/SRS/NTUH/accuray/database/patients/'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/G4'
|
||||
SHELVE = os.path.join(OUT_ROOT, 'shelve')
|
||||
|
||||
def hashptid(mrn, hosp='NTUH'):
|
||||
|
||||
ptsalt = (mrn+hosp).upper().encode()
|
||||
hash_in_bytes = hashlib.md5(ptsalt)
|
||||
|
||||
md5 = hash_in_bytes.hexdigest()
|
||||
hash = base64.b32encode(hash_in_bytes.digest())[:8].decode()
|
||||
|
||||
|
||||
# hash32 = base64.b32encode(hash_in_bytes)[:8].decode()
|
||||
# hash10 = str(int(hashlib.md5(ptsalt).hexdigest(), 16))[-8:]
|
||||
|
||||
return md5, hash
|
||||
|
||||
|
||||
def check(epath):
|
||||
|
||||
# Check CT or MR or others
|
||||
|
||||
ds = None
|
||||
FrameOfReferenceUID = {}
|
||||
|
||||
for root, dirs, files in os.walk(os.path.join(epath, 'ct/patient')):
|
||||
dirs.sort()
|
||||
for f in sorted(files):
|
||||
if f.startswith('RT'):
|
||||
continue
|
||||
if f.startswith('SR'):
|
||||
continue
|
||||
if f=='DICOMDIR':
|
||||
continue
|
||||
print(root, f)
|
||||
dcm_file = os.path.join(root, f)
|
||||
ds = pydicom.dcmread(dcm_file, force=True)
|
||||
# print(dir(ds))
|
||||
# exit()
|
||||
|
||||
if 'PatientID' not in ds:
|
||||
continue
|
||||
# print(ds, file=open('%s.txt'%f, 'w'))
|
||||
# exit()
|
||||
# print(ds.PatientID)
|
||||
# exit()
|
||||
md5, hash = hashptid(ds.PatientID)
|
||||
output = os.path.join(OUT_ROOT, hash, ds.StudyDate, ds.Modality)
|
||||
os.makedirs(output, exist_ok=True)
|
||||
subprocess.run([
|
||||
"dcm2niix",
|
||||
"-f", '%p_%t_%s',
|
||||
"-o", output,
|
||||
"-w", "0",
|
||||
"-z", "y",
|
||||
root,
|
||||
# epath,
|
||||
])
|
||||
|
||||
|
||||
if 'FrameOfReferenceUID' in ds:
|
||||
frame = {
|
||||
'files': len(files),
|
||||
'FrameOfReferenceUID': ds.FrameOfReferenceUID,
|
||||
'root': root,
|
||||
}
|
||||
# print(frame)
|
||||
if (ds.FrameOfReferenceUID not in FrameOfReferenceUID) or (FrameOfReferenceUID[ds.FrameOfReferenceUID]['files'] < len(files)):
|
||||
FrameOfReferenceUID[ds.FrameOfReferenceUID] = frame
|
||||
|
||||
break
|
||||
# if ds is not None:
|
||||
# break
|
||||
|
||||
# print(FrameOfReferenceUID)
|
||||
# exit()
|
||||
|
||||
|
||||
### Check RT
|
||||
VOI = {}
|
||||
PLAN_DIRS = []
|
||||
for root, dirs, files in os.walk(os.path.join(epath, 'tps')):
|
||||
dirs.sort()
|
||||
for f in sorted(files):
|
||||
if f.endswith('xml'):
|
||||
fileobject = os.path.join(root, f)
|
||||
print(fileobject)
|
||||
# shutil.copy(os.path.join(root, f), 'test.xml')
|
||||
|
||||
# tree = lxml.objectify.parse(fileobject)
|
||||
try:
|
||||
tree = lxml.objectify.parse(fileobject)
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
continue
|
||||
|
||||
# parser = lxml.etree.XMLParser(recover=True)
|
||||
# tree = lxml.objectify.parse(fileobject, parser=parser)
|
||||
|
||||
plan = tree.getroot()
|
||||
# print(plan.PLAN_PROFILE)
|
||||
# print(dir(plan))
|
||||
# print(plan.keys())
|
||||
# print(dir(plan.VOISET))
|
||||
# print(plan.VOISET.VOI[0].NAME)
|
||||
# print(plan.VOISET.VOI[1].NAME)
|
||||
# exit()
|
||||
|
||||
PLAN_STATE = 0
|
||||
if hasattr(plan, 'PLAN_PROFILE'): # 1 DELIVERABLE
|
||||
if hasattr(plan.PLAN_PROFILE, 'PLAN_STATE'):
|
||||
PLAN_STATE = int(plan.PLAN_PROFILE.PLAN_STATE)
|
||||
else:
|
||||
PLAN_STATE = int(plan.PLAN_PROFILE.DELIVERABLE_PLAN)
|
||||
if PLAN_STATE == 0:
|
||||
continue
|
||||
|
||||
# print(PLAN_STATE, f, root)
|
||||
PLAN_DIRS.append(root)
|
||||
if hasattr(plan, 'VOISET'):
|
||||
for v in plan.VOISET.VOI: # 0 TV, 1 ORGAN
|
||||
VOI[str(v.NAME)] = v.TYPE
|
||||
# print(v.TYPE, v.NAME, type(v.NAME))
|
||||
# exit()
|
||||
# print(PLAN_DIRS)
|
||||
# print(VOI)
|
||||
# exit()
|
||||
|
||||
for d in PLAN_DIRS:
|
||||
RT={}
|
||||
for root, dirs, files in os.walk(d):
|
||||
dirs.sort()
|
||||
for f in sorted(files):
|
||||
if f.endswith('dcm'):
|
||||
|
||||
dcm_rt_file = os.path.join(root, f)
|
||||
ds = pydicom.dcmread(dcm_rt_file)
|
||||
RT['PatientID'] = ds.PatientID
|
||||
RT['StudyDate'] = ds.StudyDate
|
||||
md5, hash = hashptid(RT['PatientID'])
|
||||
RT['output_dir'] = os.path.join(OUT_ROOT, hash, ds.StudyDate)
|
||||
output_dir = os.path.join(RT['output_dir'], 'RT')
|
||||
print(ds.Modality, dcm_rt_file, output_dir)
|
||||
|
||||
match ds.Modality:
|
||||
# if f.endswith('rtdose.dcm'):
|
||||
case 'RTDOSE': #RTDOSE
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
RT['dose'] = convert_rtdose(dcm_rt_file, force=False, dose_output_path=os.path.join(output_dir, 'dose-%s.nii.gz'%ds.SOPInstanceUID))
|
||||
# elif f.endswith('rtss.dcm'):
|
||||
case 'RTSTRUCT': #RTSS
|
||||
|
||||
RT['StructureSetDate'] = ds.StructureSetDate
|
||||
|
||||
# print(ds)
|
||||
|
||||
ROIbyNumber={}
|
||||
ROIbyName={}
|
||||
|
||||
# print(ds, file=open('%s.txt'%f, 'w'))
|
||||
|
||||
if 'StructureSetROISequence' not in ds:
|
||||
continue
|
||||
|
||||
for ds2 in ds.StructureSetROISequence:
|
||||
if 'ROINumber' in ds2:
|
||||
seq = {
|
||||
'ROINumber': ds2.ROINumber,
|
||||
'ReferencedFrameOfReferenceUID': ds2.ReferencedFrameOfReferenceUID,
|
||||
'ROIName': ds2.ROIName,
|
||||
'ROIGenerationAlgorithm': ds2.ROIGenerationAlgorithm,
|
||||
}
|
||||
# print(seq)
|
||||
ROIbyName[ds2.ROIName] = seq
|
||||
ROIbyNumber[ds2.ROINumber] = seq
|
||||
|
||||
for ds2 in ds.RTROIObservationsSequence:
|
||||
if 'ObservationNumber' in ds2:
|
||||
seq = {
|
||||
'ObservationNumber': ds2.ObservationNumber,
|
||||
'ReferencedROINumber': ds2.ReferencedROINumber,
|
||||
# 'ROIObservationLabel': ds2.ROIObservationLabel,
|
||||
'RTROIInterpretedType': ds2.RTROIInterpretedType,
|
||||
'ROIInterpreter': ds2.ROIInterpreter,
|
||||
}
|
||||
ROIName = ROIbyNumber[ds2.ReferencedROINumber]['ROIName']
|
||||
ROIbyName[ROIName].update(seq)
|
||||
|
||||
ROINames = ROIbyName.keys()
|
||||
# ROINames = VOI.keys()
|
||||
|
||||
prefix = 'Struct_'
|
||||
ct_image = 'ct_image.nii.gz'
|
||||
|
||||
# print(dir(ds.ReferencedFrameOfReferenceSequence[0]))
|
||||
|
||||
if ds.ReferencedFrameOfReferenceSequence[0].FrameOfReferenceUID not in FrameOfReferenceUID:
|
||||
continue
|
||||
|
||||
dcm_img = FrameOfReferenceUID[ds.ReferencedFrameOfReferenceSequence[0].FrameOfReferenceUID]['root']
|
||||
# dcm_img = FrameOfReferenceUID[ds.FrameOfReferenceUID]
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
print(dcm_img, dcm_rt_file)
|
||||
try:
|
||||
convert_rtstruct(dcm_img, dcm_rt_file, prefix=prefix, output_dir=output_dir, output_img=ct_image, spacing=None, replace_slashes_with='')
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
continue
|
||||
RT['structures'] = {}
|
||||
TV = None
|
||||
for e in sorted(os.scandir(output_dir), key=lambda e: e.name):
|
||||
if e.name.startswith(prefix):
|
||||
s = e.name[len(prefix):-len('.nii.gz')]
|
||||
# print(e.name, s, ROINames)
|
||||
# print(difflib.get_close_matches(s, ROINames))
|
||||
ROIName = difflib.get_close_matches(s, ROINames)[0]
|
||||
RTROIInterpretedType = ROIbyName[ROIName]['RTROIInterpretedType']
|
||||
|
||||
if 'TV' in RTROIInterpretedType:
|
||||
dst = os.path.join(output_dir, 'TV')
|
||||
if TV is None:
|
||||
TV = sitk.ReadImage(e.path)
|
||||
else:
|
||||
TV = sitk.Maximum(TV, sitk.ReadImage(e.path))
|
||||
else:
|
||||
dst = os.path.join(output_dir, RTROIInterpretedType)
|
||||
|
||||
# if VOI[ROIName] == 0:
|
||||
# dst = os.path.join(output_dir, 'TV')
|
||||
# if TV is None:
|
||||
# TV = sitk.ReadImage(e.path)
|
||||
# else:
|
||||
# TV = sitk.Maximum(TV, sitk.ReadImage(e.path))
|
||||
# else:
|
||||
# dst = os.path.join(output_dir, 'ORGAN')
|
||||
|
||||
os.makedirs(dst, exist_ok=True)
|
||||
shutil.move(e.path, os.path.join(dst, e.name))
|
||||
|
||||
|
||||
# RT['structures'][s] = sitk.ReadImage(e.path)
|
||||
if e.name == ct_image:
|
||||
RT['ct_image'] = sitk.ReadImage(e.path)
|
||||
|
||||
if TV is not None:
|
||||
RT['TV'] = TV
|
||||
if 'TV' in RT:
|
||||
sitk.WriteImage(RT['TV'], os.path.join(output_dir, 'TV-%s.nii.gz'%ds.SOPInstanceUID))
|
||||
|
||||
# exit()
|
||||
return ds
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# check('/mnt/SRS/NTUH/accuray/database/patients/Chain_6135805')
|
||||
# check('/mnt/SRS/NTUH/accuray/database/patients/HUSS_3777579')
|
||||
# check('/mnt/SRS/NTUH/accuray/database/patients/Hong_2265585')
|
||||
# check('/mnt/SRS/NTUH/accuray/database/patients/Hong_3444549')
|
||||
# exit()
|
||||
|
||||
os.makedirs(OUT_ROOT, exist_ok=True)
|
||||
d = shelve.open(SHELVE) # open -- file may get suffix added by low-level
|
||||
|
||||
for e in sorted(os.scandir(PATIENTS_ROOT), key=lambda e: e.name):
|
||||
if e.is_dir():
|
||||
if e.name in d:
|
||||
print('skip', e.name)
|
||||
continue
|
||||
ret = check(e.path)
|
||||
d[e.name] = ret
|
||||
d.sync()
|
||||
# exit()
|
||||
d.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
370
g4register.py
Normal file
370
g4register.py
Normal file
|
@ -0,0 +1,370 @@
|
|||
|
||||
'''
|
||||
metric > -0.27 is bad registration
|
||||
'''
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
# import pathlib
|
||||
import shelve
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import ants
|
||||
import filelock
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import SimpleITK as sitk
|
||||
# import skimage
|
||||
|
||||
PATIENTS_ROOT = '/mnt/1220/Public/dataset2/G4'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/H4'
|
||||
SHELVE = os.path.join(OUT_ROOT, '0shelve')
|
||||
|
||||
MAX_Y = 256
|
||||
|
||||
SIZE_X = 249
|
||||
SIZE_Y = 249
|
||||
SIZE_Z = 192
|
||||
# SIZE_Z = 256
|
||||
|
||||
MIN_OVERLAP = 0.50
|
||||
MIN_METRIC = -0.50
|
||||
|
||||
# def resize_with_crop_or_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
def resize_with_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
sx, sy, sz = image.GetSize()
|
||||
l = [(tx-sx)//2,
|
||||
(ty-sy)//2,
|
||||
(tz-sz)//2,]
|
||||
u = [tx-sx-l[0],
|
||||
ty-sy-l[1],
|
||||
tz-sz-l[2],
|
||||
]
|
||||
# print (l, u)
|
||||
return sitk.ConstantPad(image, l, u)
|
||||
|
||||
|
||||
def draw_sitk(image, d, post):
|
||||
a = sitk.GetArrayFromImage(image)
|
||||
s = a.shape
|
||||
|
||||
fig, axs = plt.subplots(1, 3)
|
||||
# fig.suptitle('%dx%dx%d'%(s[2], s[1], s[0]))
|
||||
axs.flat[0].imshow(a[s[0]//2,:,:], cmap='gray')
|
||||
axs.flat[1].imshow(a[:,s[1]//2,:], cmap='gray')
|
||||
axs.flat[2].imshow(a[:,:,s[2]//2], cmap='gray')
|
||||
axs.flat[0].axis('off')
|
||||
axs.flat[1].axis('off')
|
||||
axs.flat[2].axis('off')
|
||||
axs.flat[1].invert_yaxis()
|
||||
axs.flat[2].invert_yaxis()
|
||||
plt.tight_layout()
|
||||
os.makedirs(d, exist_ok=True)
|
||||
plt.savefig(os.path.join(d, '%dx%dx%d-%s'%(s[2],s[1],s[0],post)))
|
||||
plt.close()
|
||||
# exit()
|
||||
|
||||
def bbox2_3D(img):
|
||||
|
||||
r = np.any(img, axis=(1, 2))
|
||||
c = np.any(img, axis=(0, 2))
|
||||
z = np.any(img, axis=(0, 1))
|
||||
|
||||
if not np.any(r):
|
||||
return -1, -1, -1, -1, -1, -1
|
||||
|
||||
rmin, rmax = np.where(r)[0][[0, -1]]
|
||||
cmin, cmax = np.where(c)[0][[0, -1]]
|
||||
zmin, zmax = np.where(z)[0][[0, -1]]
|
||||
|
||||
return rmin, rmax, cmin, cmax, zmin, zmax
|
||||
|
||||
|
||||
def registration(ct0, ct1, mr):
|
||||
|
||||
ct0n = ct0.numpy()
|
||||
mrn = mr.numpy()
|
||||
|
||||
if np.array_equal(ct0n, mrn):
|
||||
print('EQUAL')
|
||||
return {
|
||||
'fwdtransforms': [],
|
||||
'warpedfixout': ct0,
|
||||
'warpedmovout': ct0,
|
||||
'ct': 0,
|
||||
'type': 'Identity',
|
||||
'metric': -2,
|
||||
'ratio': 1,
|
||||
}
|
||||
|
||||
if ct0n.shape == mrn.shape:
|
||||
print('SAME SHAPE')
|
||||
CTS = (ct0, ct1)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
)
|
||||
else:
|
||||
print('others', mrn.shape)
|
||||
if min(mrn.shape) < 4:
|
||||
print('skip')
|
||||
return None
|
||||
CTS = (ct0, ct1)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
)
|
||||
|
||||
TX = []
|
||||
start = time.time()
|
||||
for m in range(len(CTS)):
|
||||
for typ in TYPES:
|
||||
ct = CTS[m]
|
||||
print(typ)
|
||||
|
||||
mytx = ants.registration(ct, mr, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
)
|
||||
|
||||
mytx['metric0M'] = ants.create_ants_metric(ct0,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric1M'] = ants.create_ants_metric(ct1,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metricMM'] = ants.create_ants_metric(mr,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
).get_value()
|
||||
mytx['metric'] = min([mytx['metric0M'], mytx['metric1M'], mytx['metricMM']])
|
||||
mytx['ct'] = m
|
||||
mytx['type'] = (typ, 'fwd')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedmovout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metric0M'], mytx['metric1M'], mytx['metricMM'])
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(mr, ct, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
whichtoinvert=[True],
|
||||
)
|
||||
|
||||
mytx['metricMM'] = ants.create_ants_metric(mr,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
).get_value()
|
||||
mytx['metric0M'] = ants.create_ants_metric(ct0,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric1M'] = ants.create_ants_metric(ct1,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric'] = min([mytx['metricMM'], mytx['metric0M'], mytx['metric1M']])
|
||||
mytx['ct'] = m
|
||||
mytx['type'] = (typ, 'inv')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedfixout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricMM'], mytx['metric0M'], mytx['metric1M'])
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
print(time.time()-start, 'seconds')
|
||||
|
||||
# exit()
|
||||
|
||||
tx = {
|
||||
'metric': 0,
|
||||
}
|
||||
|
||||
for t in TX:
|
||||
if t['metric'] < tx['metric']:
|
||||
tx = t
|
||||
|
||||
tx['ratio'] = tx['mask'].numpy().sum() / np.prod(ct0.numpy().shape)
|
||||
|
||||
return tx
|
||||
|
||||
def check(epath):
|
||||
registered = 0
|
||||
for root, dirs, files in os.walk(epath):
|
||||
dirs.sort()
|
||||
|
||||
RT_DIR = os.path.join(root, 'RT')
|
||||
|
||||
ORGAN_DIR = os.path.join(RT_DIR, 'ORGAN')
|
||||
if not os.path.isdir(ORGAN_DIR):
|
||||
continue
|
||||
|
||||
# if there is no eye, it's no a brain image
|
||||
eye = None
|
||||
organs = sorted(os.scandir(ORGAN_DIR), key=lambda e: e.name)
|
||||
for o in organs:
|
||||
if 'eye' in o.name.lower():
|
||||
eye = o
|
||||
if eye is None:
|
||||
print('no eye... skip', root)
|
||||
# exit()
|
||||
return None
|
||||
|
||||
ct_image = os.path.join(RT_DIR, 'ct_image.nii.gz')
|
||||
ct0 = sitk.ReadImage(ct_image)
|
||||
ct1 = sitk.Clamp(ct0, sitk.sitkUInt8, 0, 80)
|
||||
print(ct_image, ct0.GetSize())
|
||||
|
||||
outdir = os.path.join(OUT_ROOT, os.path.relpath(root, PATIENTS_ROOT))
|
||||
print(outdir)
|
||||
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
ct0_nii = os.path.join(outdir, 'ct0.nii.gz')
|
||||
ct1_nii = os.path.join(outdir, 'ct1.nii.gz')
|
||||
shutil.copy(ct_image, ct0_nii)
|
||||
sitk.WriteImage(ct1, ct1_nii)
|
||||
# sitk.WriteImage(sitk.DICOMOrient(ct0), ct0_nii)
|
||||
# sitk.WriteImage(sitk.DICOMOrient(ct1), ct1_nii)
|
||||
|
||||
ct0 = ants.image_read(ct0_nii, reorient=True)
|
||||
ct1 = ants.image_read(ct1_nii, reorient=True)
|
||||
|
||||
|
||||
for root2, dirs2, files2 in os.walk(root):
|
||||
dirs2.sort()
|
||||
skip = (root2==root) or ('RT' in root2.split('/'))
|
||||
if skip:
|
||||
continue
|
||||
if root2.endswith('CT'):
|
||||
modality = 'CT'
|
||||
# continue
|
||||
else:
|
||||
modality = 'other'
|
||||
print(skip, root2, modality)
|
||||
outdir = os.path.join(OUT_ROOT, os.path.relpath(root2, PATIENTS_ROOT))
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
for e in sorted(os.scandir(root2), key=lambda e: e.name):
|
||||
if not e.name.endswith('.nii.gz'):
|
||||
continue
|
||||
if '_RTDOSE_' in e.name:
|
||||
continue
|
||||
if '_DTI_' in e.name:
|
||||
continue
|
||||
if '_ROI1.' in e.name:
|
||||
continue
|
||||
|
||||
OUT_IMG = os.path.join(outdir, e.name)
|
||||
if os.path.isfile(OUT_IMG):
|
||||
print('skip', OUT_IMG)
|
||||
continue
|
||||
|
||||
print(e.name, e.path)
|
||||
|
||||
fix = ants.image_read(e.path, reorient=True)
|
||||
mytx = registration(ct0, ct1, fix)
|
||||
if mytx is None:
|
||||
continue
|
||||
print(mytx['ratio'], mytx['metric'])
|
||||
|
||||
registered += 1
|
||||
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
OUT_WARP = OUT_IMG.replace('.nii.gz', '.warp.nii.gz')
|
||||
OUT_MSK = OUT_IMG.replace('.nii.gz', '.mask.nii.gz')
|
||||
OUT_JSON = OUT_IMG.replace('.nii.gz', '.json')
|
||||
OUT_MAT = OUT_IMG.replace('.nii.gz', '.mat')
|
||||
|
||||
jj = {
|
||||
'ct' : mytx['ct'],
|
||||
'type' : mytx['type'],
|
||||
'metric': mytx['metric'],
|
||||
'ratio' : mytx['ratio'],
|
||||
}
|
||||
|
||||
with open(OUT_JSON, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
if mytx['fwdtransforms']:
|
||||
shutil.copy(mytx['fwdtransforms'][0], OUT_MAT)
|
||||
ants.image_write(mytx['mask'], OUT_MSK)
|
||||
ants.image_write(mytx['warpedout'], OUT_WARP)
|
||||
|
||||
metric = mytx['metric']
|
||||
metric_dir = os.path.join(OUT_ROOT, "1")
|
||||
OUT_TXT = os.path.join(metric_dir, '%f-%s'%(metric, e.name.replace('.nii.gz', '.txt')))
|
||||
jj['dir'] = outdir
|
||||
os.makedirs(metric_dir, exist_ok=True)
|
||||
with open(OUT_TXT, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
shutil.copy(e.path, OUT_IMG)
|
||||
|
||||
|
||||
return registered
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# check('/mnt/1220/Public/dataset2/G4/3L6LOEER') # bad registration
|
||||
# exit()
|
||||
|
||||
EXCLUDE = (
|
||||
# 'LLUQJUY4', #cervical
|
||||
)
|
||||
|
||||
os.makedirs(OUT_ROOT, exist_ok=True)
|
||||
|
||||
LOCK_DIR = os.path.join(OUT_ROOT, '0lock')
|
||||
os.makedirs(LOCK_DIR, exist_ok=True)
|
||||
for e in sorted(os.scandir(PATIENTS_ROOT), key=lambda e: e.name):
|
||||
if e.is_dir():
|
||||
d = shelve.open(SHELVE)
|
||||
if e.name in d or e.name in EXCLUDE:
|
||||
print('skip', e.name)
|
||||
d.close()
|
||||
continue
|
||||
d.close()
|
||||
lock_path = os.path.join(LOCK_DIR, '%s.lock'%e.name)
|
||||
lock = filelock.FileLock(lock_path, timeout=1)
|
||||
try:
|
||||
lock.acquire()
|
||||
except:
|
||||
print(lock_path, 'locked')
|
||||
continue
|
||||
ret = check(e.path)
|
||||
lock.release()
|
||||
# exit()
|
||||
d = shelve.open(SHELVE)
|
||||
d[e.name] = ret
|
||||
d.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
552
g4resample.py
Normal file
552
g4resample.py
Normal file
|
@ -0,0 +1,552 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import shelve
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import ants
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import SimpleITK as sitk
|
||||
|
||||
PATIENTS_ROOT = '/mnt/1220/Public/dataset2/G4'
|
||||
OUT_ROOT = '/home/xfr/git9/Taipei-1/0'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/G5'
|
||||
SHELVE = os.path.join(OUT_ROOT, '0shelve')
|
||||
|
||||
MAX_Y = 256
|
||||
|
||||
SIZE_X = 249
|
||||
SIZE_Y = 249
|
||||
SIZE_Z = 192
|
||||
# SIZE_Z = 256
|
||||
|
||||
MIN_OVERLAP = 0.50
|
||||
MIN_METRIC = -0.50
|
||||
|
||||
# def resize_with_crop_or_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
def resize_with_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
sx, sy, sz = image.GetSize()
|
||||
l = [(tx-sx)//2,
|
||||
(ty-sy)//2,
|
||||
(tz-sz)//2,]
|
||||
u = [tx-sx-l[0],
|
||||
ty-sy-l[1],
|
||||
tz-sz-l[2],
|
||||
]
|
||||
# print (l, u)
|
||||
return sitk.ConstantPad(image, l, u)
|
||||
|
||||
|
||||
def draw_sitk(image, d, post):
|
||||
a = sitk.GetArrayFromImage(image)
|
||||
s = a.shape
|
||||
|
||||
fig, axs = plt.subplots(1, 3)
|
||||
# fig.suptitle('%dx%dx%d'%(s[2], s[1], s[0]))
|
||||
axs.flat[0].imshow(a[s[0]//2,:,:], cmap='gray')
|
||||
axs.flat[1].imshow(a[:,s[1]//2,:], cmap='gray')
|
||||
axs.flat[2].imshow(a[:,:,s[2]//2], cmap='gray')
|
||||
axs.flat[0].axis('off')
|
||||
axs.flat[1].axis('off')
|
||||
axs.flat[2].axis('off')
|
||||
axs.flat[1].invert_yaxis()
|
||||
axs.flat[2].invert_yaxis()
|
||||
plt.tight_layout()
|
||||
os.makedirs(d, exist_ok=True)
|
||||
plt.savefig(os.path.join(d, '%dx%dx%d-%s'%(s[2],s[1],s[0],post)))
|
||||
plt.close()
|
||||
# exit()
|
||||
|
||||
def bbox2_3D(img):
|
||||
|
||||
r = np.any(img, axis=(1, 2))
|
||||
c = np.any(img, axis=(0, 2))
|
||||
z = np.any(img, axis=(0, 1))
|
||||
|
||||
if not np.any(r):
|
||||
return -1, -1, -1, -1, -1, -1
|
||||
|
||||
rmin, rmax = np.where(r)[0][[0, -1]]
|
||||
cmin, cmax = np.where(c)[0][[0, -1]]
|
||||
zmin, zmax = np.where(z)[0][[0, -1]]
|
||||
|
||||
return rmin, rmax, cmin, cmax, zmin, zmax
|
||||
|
||||
def physical_size(a):
|
||||
A = a.numpy().shape
|
||||
B = a.spacing
|
||||
C = (
|
||||
A[0]*B[0],
|
||||
A[1]*B[1],
|
||||
A[2]*B[2],
|
||||
)
|
||||
|
||||
print(A,B,C)
|
||||
|
||||
return C
|
||||
|
||||
def registration(ct0, ct1, mr, modality = 'CT'):
|
||||
# print(
|
||||
# physical_size(ct0),
|
||||
# physical_size(moving)
|
||||
# )
|
||||
TX = []
|
||||
|
||||
FIXS = (ct0, ct1)
|
||||
# FIXS = (ct1,)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
|
||||
# 'Similarity',
|
||||
# 'Affine',
|
||||
# 'AffineFast',
|
||||
# 'BOLDAffine',
|
||||
# 'TRSAA',
|
||||
|
||||
)
|
||||
|
||||
if modality == 'CT':
|
||||
FIXS = (ct1, ct0)
|
||||
# TYPES = (
|
||||
# # 'Translation',
|
||||
# 'Rigid',
|
||||
# )
|
||||
|
||||
start = time.time()
|
||||
for ff in range(len(FIXS)):
|
||||
for typ in TYPES:
|
||||
ct = FIXS[ff]
|
||||
|
||||
print(typ)
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(ct, mr, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
)
|
||||
|
||||
am = ants.create_ants_metric(ct,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
)
|
||||
mytx['metricFM'] = am.get_value()
|
||||
am = ants.create_ants_metric(mr,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation')
|
||||
mytx['metricMM'] = am.get_value()
|
||||
mytx['metric'] = min([mytx['metricFM'], mytx['metricMM']])
|
||||
mytx['ct'] = ff
|
||||
mytx['type'] = (typ, 'fwd')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedmovout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricFM'], mytx['metricMM'])
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(mr, ct, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
whichtoinvert=[True],
|
||||
)
|
||||
|
||||
am = ants.create_ants_metric(mr,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation')
|
||||
mytx['metricFM'] = am.get_value()
|
||||
am = ants.create_ants_metric(ct,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
)
|
||||
mytx['metricMM'] = am.get_value()
|
||||
mytx['metric'] = min([mytx['metricFM'], mytx['metricMM']])
|
||||
mytx['ct'] = ff
|
||||
mytx['type'] = (typ, 'inv')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedfixout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricFM'], mytx['metricMM'])
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
print(time.time()-start, 'seconds')
|
||||
|
||||
tx = {
|
||||
'metric': 0,
|
||||
}
|
||||
|
||||
for t in TX:
|
||||
if t['metric'] < tx['metric']:
|
||||
tx = t
|
||||
|
||||
tx['ratio'] = tx['mask'].numpy().sum() / np.prod(ct0.numpy().shape)
|
||||
|
||||
return tx
|
||||
|
||||
def check(epath):
|
||||
roi=None
|
||||
for root, dirs, files in os.walk(epath):
|
||||
dirs.sort()
|
||||
RT_DIR = os.path.join(root, 'RT')
|
||||
EXTERNAL_DIR = os.path.join(RT_DIR, 'EXTERNAL')
|
||||
if not os.path.isdir(EXTERNAL_DIR):
|
||||
continue
|
||||
|
||||
ORGAN_DIR = os.path.join(RT_DIR, 'ORGAN')
|
||||
if not os.path.isdir(ORGAN_DIR):
|
||||
continue
|
||||
|
||||
# if there is no eye, it's no a brain image
|
||||
eye = None
|
||||
organs = sorted(os.scandir(ORGAN_DIR), key=lambda e: e.name)
|
||||
for o in organs:
|
||||
if 'eye' in o.name.lower():
|
||||
eye = o
|
||||
if eye is None:
|
||||
print('no eye... skip', root)
|
||||
# exit()
|
||||
return None
|
||||
|
||||
|
||||
CT_IMAGE = os.path.join(RT_DIR, 'ct_image.nii.gz')
|
||||
|
||||
externals = sorted(os.scandir(EXTERNAL_DIR), key=lambda e: -e.stat().st_size)
|
||||
# for e in externals:
|
||||
# print(e.name, e.stat().st_size)
|
||||
|
||||
print(externals[0].path)
|
||||
|
||||
external = sitk.ReadImage(externals[0].path)
|
||||
# print(external.GetSize())
|
||||
# print(external.GetSpacing())
|
||||
|
||||
sz = external.GetSize()
|
||||
sp = external.GetSpacing()
|
||||
|
||||
outputSize = (
|
||||
round(sz[0]*sp[0]),
|
||||
round(sz[1]*sp[1]),
|
||||
round(sz[2]*sp[2]),
|
||||
)
|
||||
|
||||
outputOrigin = external.GetOrigin()
|
||||
outputSpacing = (1., 1., 1.)
|
||||
outputDirection = external.GetDirection()
|
||||
|
||||
|
||||
mask = sitk.Resample(external, outputSize, sitk.Transform(), sitk.sitkNearestNeighbor, outputOrigin, outputSpacing, outputDirection)
|
||||
# sitk.WriteImage(mask, '0mask.nii.gz')
|
||||
# print(mask.GetSize())
|
||||
# print(mask.GetSpacing())
|
||||
|
||||
|
||||
lsif = sitk.LabelShapeStatisticsImageFilter()
|
||||
lsif.Execute(mask)
|
||||
|
||||
if 1 not in lsif.GetLabels():
|
||||
print('strange mask... skip', root)
|
||||
return None
|
||||
|
||||
|
||||
boundingBox = lsif.GetBoundingBox(1)
|
||||
print(boundingBox)
|
||||
ix, iy, iz, sx, sy, sz = boundingBox
|
||||
|
||||
sy = min(sy, MAX_Y)
|
||||
|
||||
sz0 = min(sz, SIZE_Z-2) # will pad later
|
||||
iz0 = iz+sz-sz0
|
||||
|
||||
roi = sitk.RegionOfInterest(mask, (sx, sy, sz0), (ix, iy, iz0))
|
||||
|
||||
# remove frame
|
||||
|
||||
ER = 10
|
||||
ER = 29
|
||||
ER = 44
|
||||
ER = 40 # remove most of it
|
||||
ER = 37 # remove most of it
|
||||
|
||||
roi = sitk.BinaryErode(roi, (ER,ER,ER))
|
||||
roi2 = sitk.BinaryDilate(roi, (ER,ER,ER))
|
||||
# sitk.WriteImage(roi, '0roi.nii.gz')
|
||||
# exit()
|
||||
|
||||
# print(external.GetSize())
|
||||
# print(roi.GetSize())
|
||||
|
||||
#Now no shoulder, get BB again
|
||||
lsif.Execute(roi2)
|
||||
|
||||
# Something wrong? 6L63PXNV
|
||||
# print(lsif.GetLabels())
|
||||
if 1 not in lsif.GetLabels():
|
||||
return None
|
||||
|
||||
boundingBox = lsif.GetBoundingBox(1)
|
||||
print(boundingBox)
|
||||
|
||||
ix2, iy2, iz2, sx2, sy2, sz2 = boundingBox
|
||||
# sy2 = sy
|
||||
iy2 = 0
|
||||
# iy2 = min(iy2, roi2.GetSize()[1]-sy2)
|
||||
sy2 = (sy+sy2)//2
|
||||
|
||||
print((sx2, sy2, sz2), (ix2, iy2, iz2))
|
||||
roi = sitk.RegionOfInterest(roi2, (sx2, sy2, sz0), (ix2, iy2, 0))
|
||||
|
||||
# roi = resize_with_pad(roi)
|
||||
# roi = sitk.FFTPad(roi)
|
||||
ypad = min(2, (SIZE_Y-sy2)//2)
|
||||
roi = sitk.ConstantPad(roi, (1,ypad,1), (1,ypad,1))
|
||||
# roi = sitk.ConstantPad(roi, (0,0,0), (0,SIZE_Y-sy2,0))
|
||||
|
||||
print(external.GetSize())
|
||||
print(roi.GetSize())
|
||||
|
||||
|
||||
# sitk.WriteImage(external, '0external.nii.gz')
|
||||
# sitk.WriteImage(roi, '0roi.nii.gz')
|
||||
|
||||
# exit()
|
||||
|
||||
ct = sitk.ReadImage(CT_IMAGE,
|
||||
# sitk.sitkFloat32
|
||||
)
|
||||
CTresampled = sitk.Resample(ct, roi,
|
||||
# sitk.Transform(),
|
||||
# sitk.sitkBSpline,
|
||||
)
|
||||
|
||||
rescaled = sitk.RescaleIntensity(sitk.Clamp(CTresampled,
|
||||
sitk.sitkUInt8,
|
||||
# sitk.sitkFloat32,
|
||||
0, 80))
|
||||
|
||||
TV = None
|
||||
for e in sorted(os.scandir(RT_DIR), key=lambda e: e.name):
|
||||
if not e.name.startswith('TV-'):
|
||||
continue
|
||||
tv = sitk.ReadImage(e.path)
|
||||
TVresampled = sitk.Resample(tv, roi,
|
||||
sitk.Transform(),
|
||||
sitk.sitkNearestNeighbor,
|
||||
)
|
||||
if TV is None:
|
||||
TV = TVresampled
|
||||
else:
|
||||
TV = sitk.Maximum(TV, TVresampled)
|
||||
|
||||
if TV is None:
|
||||
continue
|
||||
|
||||
EXresampled = sitk.Resample(external, roi,
|
||||
sitk.Transform(),
|
||||
sitk.sitkNearestNeighbor,
|
||||
)
|
||||
|
||||
relpath = os.path.relpath(root, PATIENTS_ROOT)
|
||||
OUT_DIR = os.path.join(OUT_ROOT, relpath)
|
||||
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
CT0 = os.path.join(OUT_DIR, 'ct0.nii.gz')
|
||||
CT1 = os.path.join(OUT_DIR, 'ct1.nii.gz')
|
||||
print(CT0)
|
||||
sitk.WriteImage(CTresampled, CT0)
|
||||
sitk.WriteImage(rescaled, CT1)
|
||||
sitk.WriteImage(TV+EXresampled, os.path.join(OUT_DIR, 'label.nii.gz'))
|
||||
|
||||
draw_sitk(rescaled, os.path.join(OUT_ROOT, '0'), '%s.png'%relpath.replace('/', '-'))
|
||||
# exit()
|
||||
|
||||
if max(roi.GetSize()) >= SIZE_X+64: #BODY
|
||||
continue
|
||||
|
||||
if max(roi.GetSize()) > SIZE_X:
|
||||
exit()
|
||||
|
||||
# exit()
|
||||
# continue # skip registration first
|
||||
|
||||
ct0 = ants.image_read(CT0)
|
||||
ct1 = ants.image_read(CT1)
|
||||
# fixed = ants.image_read(CT0)
|
||||
for root2, dirs2, files2 in os.walk(root):
|
||||
dirs2.sort()
|
||||
skip = (root2==root) or ('RT' in root2.split('/'))
|
||||
if skip:
|
||||
continue
|
||||
if root2.endswith('CT'):
|
||||
modality = 'CT'
|
||||
fixed=ct1
|
||||
else:
|
||||
modality = 'other'
|
||||
fixed=ct1
|
||||
print(skip, root2, modality)
|
||||
relpath = os.path.relpath(root2, PATIENTS_ROOT)
|
||||
out_dir = os.path.join(OUT_ROOT, relpath)
|
||||
for mv in sorted(os.scandir(root2), key=lambda e: e.name):
|
||||
|
||||
if not mv.name.endswith('nii.gz'):
|
||||
continue
|
||||
if mv.name.startswith('dose'):
|
||||
continue
|
||||
if '_DTI_' in mv.name:
|
||||
continue
|
||||
if '_RTDOSE_' in mv.name:
|
||||
continue
|
||||
if '_ROI1.' in mv.name:
|
||||
continue
|
||||
# if '_swi_' in mv.name:
|
||||
# continue
|
||||
# if '_ph.' in mv.name:
|
||||
# continue
|
||||
# if '_Doses_' in mv.name:
|
||||
# continue
|
||||
# if '_phMag.' in mv.name:
|
||||
# continue
|
||||
|
||||
OUT_IMG = os.path.join(out_dir, mv.name)
|
||||
if os.path.isfile(OUT_IMG):
|
||||
print('skip', OUT_IMG)
|
||||
continue
|
||||
|
||||
split = mv.name[:-7].split('_')
|
||||
series = None
|
||||
pos = -1
|
||||
while series is None:
|
||||
try:
|
||||
series = int(split[pos])
|
||||
except:
|
||||
pos -= 1
|
||||
print(mv.name, series)
|
||||
# if series > 99:
|
||||
# continue
|
||||
|
||||
moving = ants.image_read(mv.path)
|
||||
|
||||
# skip thin images
|
||||
_, _, _, _, zmin, zmax = bbox2_3D(moving.numpy())
|
||||
mv_height = moving.spacing[2] * (zmax-zmin)
|
||||
z_ratio = mv_height / SIZE_Z
|
||||
if z_ratio < MIN_OVERLAP:
|
||||
print("skip", mv.name, mv_height, z_ratio)
|
||||
continue
|
||||
|
||||
print(mv.path, moving.view().shape, mv_height, z_ratio)
|
||||
|
||||
if moving.max() == 0.0:
|
||||
print('Total Mass of the image was zero. Aborting here to prevent division by zero later on.')
|
||||
continue
|
||||
|
||||
mytx = registration(ct0, ct1, moving, modality)
|
||||
print(mytx['ratio'], mytx['metric'])
|
||||
# if (mytx['metric'] < MIN_METRIC) and (mytx['ratio'] < MIN_OVERLAP):
|
||||
# print("skip", mv.name, mytx['ratio'])
|
||||
# continue
|
||||
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
OUT_MSK = OUT_IMG.replace('.nii.gz', '.mask.nii.gz')
|
||||
OUT_JSON = OUT_IMG.replace('.nii.gz', '.json')
|
||||
OUT_MAT = OUT_IMG.replace('.nii.gz', '.mat')
|
||||
|
||||
jj = {
|
||||
'ct' : mytx['ct'],
|
||||
'type' : mytx['type'],
|
||||
'metric': mytx['metric'],
|
||||
'ratio' : mytx['ratio'],
|
||||
}
|
||||
|
||||
with open(OUT_JSON, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
shutil.copy(mytx['fwdtransforms'][0], OUT_MAT)
|
||||
ants.image_write(mytx['mask'], OUT_MSK)
|
||||
ants.image_write(mytx['warpedout'], OUT_IMG)
|
||||
|
||||
metric = mytx['metric']
|
||||
|
||||
metric_dir = os.path.join(OUT_ROOT, "1")
|
||||
OUT_TXT = os.path.join(metric_dir, '%f-%s'%(metric, mv.name.replace('.nii.gz', '.txt')))
|
||||
|
||||
jj['dir'] = out_dir
|
||||
|
||||
os.makedirs(metric_dir, exist_ok=True)
|
||||
with open(OUT_TXT, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
|
||||
# exit()
|
||||
|
||||
# exit()
|
||||
if roi is None:
|
||||
return None
|
||||
return roi.GetSize()
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# check('/mnt/1220/Public/dataset2/G4/2UK7274S')
|
||||
# check('/mnt/1220/Public/dataset2/G4/6L63PXNV') # Took MR for base image...:(
|
||||
# check('/mnt/1220/Public/dataset2/G4/5IJBRZ4K') # Large frame ... Need erode 29 ?
|
||||
# check('/mnt/1220/Public/dataset2/G4/7RC7JOLL') # Large frame ... Need erode 44 ?
|
||||
# check('/mnt/1220/Public/dataset2/G4/O7IOGTPD') # Large frame ... Need erode 37 ?
|
||||
# check('/mnt/1220/Public/dataset2/G4/2FHZOOLU') # Poor registration
|
||||
# check('/mnt/1220/Public/dataset2/G4/3N6JVTD4') # Poor registration
|
||||
# check('/mnt/1220/Public/dataset2/G4/3L6LOEER') # Poor registration, metric = 1.058
|
||||
# check('/mnt/1220/Public/dataset2/G4/IUS424GK') # MASK zero after resample
|
||||
# check('/mnt/1220/Public/dataset2/G4/MCVGFTEI') # CTA as based image :( still need to read base image from XML
|
||||
# exit()
|
||||
|
||||
EXCLUDE = (
|
||||
'2FHZOOLU', # CT0 is cervical
|
||||
# '2KCGE3UG', #cervical, but acceptable
|
||||
'53JAUWVU', #cervical
|
||||
'7PS3CJUR', #cervical
|
||||
'ED4NQNMK', #cervical
|
||||
'IUS424GK', #strange mask
|
||||
'MCVGFTEI', #CTA as base image :(
|
||||
)
|
||||
|
||||
EXCLUDE = (
|
||||
)
|
||||
|
||||
os.makedirs(OUT_ROOT, exist_ok=True)
|
||||
d = shelve.open(SHELVE) # open -- file may get suffix added by low-level
|
||||
|
||||
for e in sorted(os.scandir(PATIENTS_ROOT), key=lambda e: e.name):
|
||||
if e.is_dir():
|
||||
# print(e.name)
|
||||
if e.name in d or e.name in EXCLUDE:
|
||||
print('skip', e.name)
|
||||
continue
|
||||
ret = check(e.path)
|
||||
d[e.name] = ret
|
||||
d.sync()
|
||||
# exit()
|
||||
d.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
380
m6register.py
Normal file
380
m6register.py
Normal file
|
@ -0,0 +1,380 @@
|
|||
|
||||
'''
|
||||
metric > -0.27 is bad registration
|
||||
'''
|
||||
|
||||
import json
|
||||
import os
|
||||
# import pathlib
|
||||
import shelve
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import ants
|
||||
import filelock
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import SimpleITK as sitk
|
||||
# import skimage
|
||||
|
||||
PATIENTS_ROOT = '/mnt/1220/Public/dataset2/M6'
|
||||
PATIENTS_ROOT = '/mnt/1220/Public/dataset2/M6_24Q3/nii/'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/N6'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/N6_24Q3.1'
|
||||
SHELVE = os.path.join(OUT_ROOT, '0shelve')
|
||||
|
||||
MAX_Y = 256
|
||||
|
||||
SIZE_X = 249
|
||||
SIZE_Y = 249
|
||||
SIZE_Z = 192
|
||||
# SIZE_Z = 256
|
||||
|
||||
MIN_OVERLAP = 0.50
|
||||
MIN_METRIC = -0.50
|
||||
|
||||
# def resize_with_crop_or_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
def resize_with_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
sx, sy, sz = image.GetSize()
|
||||
l = [(tx-sx)//2,
|
||||
(ty-sy)//2,
|
||||
(tz-sz)//2,]
|
||||
u = [tx-sx-l[0],
|
||||
ty-sy-l[1],
|
||||
tz-sz-l[2],
|
||||
]
|
||||
# print (l, u)
|
||||
return sitk.ConstantPad(image, l, u)
|
||||
|
||||
|
||||
def draw_sitk(image, d, post):
|
||||
a = sitk.GetArrayFromImage(image)
|
||||
s = a.shape
|
||||
|
||||
fig, axs = plt.subplots(1, 3)
|
||||
# fig.suptitle('%dx%dx%d'%(s[2], s[1], s[0]))
|
||||
axs.flat[0].imshow(a[s[0]//2,:,:], cmap='gray')
|
||||
axs.flat[1].imshow(a[:,s[1]//2,:], cmap='gray')
|
||||
axs.flat[2].imshow(a[:,:,s[2]//2], cmap='gray')
|
||||
axs.flat[0].axis('off')
|
||||
axs.flat[1].axis('off')
|
||||
axs.flat[2].axis('off')
|
||||
axs.flat[1].invert_yaxis()
|
||||
axs.flat[2].invert_yaxis()
|
||||
plt.tight_layout()
|
||||
os.makedirs(d, exist_ok=True)
|
||||
plt.savefig(os.path.join(d, '%dx%dx%d-%s'%(s[2],s[1],s[0],post)))
|
||||
plt.close()
|
||||
# exit()
|
||||
|
||||
def bbox2_3D(img):
|
||||
|
||||
r = np.any(img, axis=(1, 2))
|
||||
c = np.any(img, axis=(0, 2))
|
||||
z = np.any(img, axis=(0, 1))
|
||||
|
||||
if not np.any(r):
|
||||
return -1, -1, -1, -1, -1, -1
|
||||
|
||||
rmin, rmax = np.where(r)[0][[0, -1]]
|
||||
cmin, cmax = np.where(c)[0][[0, -1]]
|
||||
zmin, zmax = np.where(z)[0][[0, -1]]
|
||||
|
||||
return rmin, rmax, cmin, cmax, zmin, zmax
|
||||
|
||||
|
||||
def registration(ct0, ct1, mr):
|
||||
|
||||
ct0n = ct0.numpy()
|
||||
mrn = mr.numpy()
|
||||
|
||||
if np.array_equal(ct0n, mrn):
|
||||
print('EQUAL')
|
||||
return {
|
||||
'fwdtransforms': [],
|
||||
'warpedfixout': ct0,
|
||||
'warpedmovout': ct0,
|
||||
'ct': 0,
|
||||
'type': 'Identity',
|
||||
'metric': -2,
|
||||
'ratio': 1,
|
||||
}
|
||||
|
||||
if ct0n.shape == mrn.shape:
|
||||
print('SAME SHAPE')
|
||||
CTS = (ct0, ct1)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
)
|
||||
else:
|
||||
print('others', mrn.shape)
|
||||
if min(mrn.shape) < 4:
|
||||
print('skip')
|
||||
return None
|
||||
CTS = (ct0, ct1)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
)
|
||||
|
||||
TX = []
|
||||
start = time.time()
|
||||
for m in range(len(CTS)):
|
||||
for typ in TYPES:
|
||||
ct = CTS[m]
|
||||
print(typ)
|
||||
|
||||
mytx = ants.registration(ct, mr, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
)
|
||||
|
||||
mytx['metric0M'] = ants.create_ants_metric(ct0,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric1M'] = ants.create_ants_metric(ct1,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metricMM'] = ants.create_ants_metric(mr,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
).get_value()
|
||||
mytx['metric'] = min([mytx['metric0M'], mytx['metric1M'], mytx['metricMM']])
|
||||
mytx['ct'] = m
|
||||
mytx['type'] = (typ, 'fwd')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedmovout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metric0M'], mytx['metric1M'], mytx['metricMM'])
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(mr, ct, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
whichtoinvert=[True],
|
||||
)
|
||||
|
||||
mytx['metricMM'] = ants.create_ants_metric(mr,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
).get_value()
|
||||
mytx['metric0M'] = ants.create_ants_metric(ct0,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric1M'] = ants.create_ants_metric(ct1,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
).get_value()
|
||||
mytx['metric'] = min([mytx['metricMM'], mytx['metric0M'], mytx['metric1M']])
|
||||
mytx['ct'] = m
|
||||
mytx['type'] = (typ, 'inv')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedfixout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricMM'], mytx['metric0M'], mytx['metric1M'])
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
print(time.time()-start, 'seconds')
|
||||
|
||||
# exit()
|
||||
|
||||
tx = {
|
||||
'metric': 0,
|
||||
}
|
||||
|
||||
for t in TX:
|
||||
if t['metric'] < tx['metric']:
|
||||
tx = t
|
||||
|
||||
tx['ratio'] = tx['mask'].numpy().sum() / np.prod(ct0.numpy().shape)
|
||||
|
||||
return tx
|
||||
|
||||
def check(epath):
|
||||
registered = 0
|
||||
for root, dirs, files in os.walk(epath):
|
||||
dirs.sort()
|
||||
|
||||
RT_DIR = os.path.join(root, 'RT')
|
||||
|
||||
ORGAN_DIR = os.path.join(RT_DIR, 'ORGAN')
|
||||
if not os.path.isdir(ORGAN_DIR):
|
||||
continue
|
||||
|
||||
# if there is no eye, it's no a brain image
|
||||
eye = None
|
||||
organs = sorted(os.scandir(ORGAN_DIR), key=lambda e: e.name)
|
||||
for o in organs:
|
||||
if 'eye' in o.name.lower():
|
||||
eye = o
|
||||
if eye is None:
|
||||
print('no eye... skip', root)
|
||||
# exit()
|
||||
return None
|
||||
|
||||
ct_image = os.path.join(RT_DIR, 'ct_image.nii.gz')
|
||||
ct0 = sitk.ReadImage(ct_image)
|
||||
ct1 = sitk.Clamp(ct0, sitk.sitkUInt8, 0, 80)
|
||||
print(ct_image, ct0.GetSize())
|
||||
|
||||
outdir = os.path.join(OUT_ROOT, os.path.relpath(root, PATIENTS_ROOT))
|
||||
print(outdir)
|
||||
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
ct0_nii = os.path.join(outdir, 'ct0.nii.gz')
|
||||
ct1_nii = os.path.join(outdir, 'ct1.nii.gz')
|
||||
shutil.copy(ct_image, ct0_nii)
|
||||
sitk.WriteImage(ct1, ct1_nii)
|
||||
# sitk.WriteImage(sitk.DICOMOrient(ct0), ct0_nii)
|
||||
# sitk.WriteImage(sitk.DICOMOrient(ct1), ct1_nii)
|
||||
|
||||
ct0 = ants.image_read(ct0_nii, reorient=True)
|
||||
ct1 = ants.image_read(ct1_nii, reorient=True)
|
||||
|
||||
|
||||
for root2, dirs2, files2 in os.walk(root):
|
||||
dirs2.sort()
|
||||
skip = (root2==root) or ('RT' in root2.split('/'))
|
||||
if skip:
|
||||
continue
|
||||
if root2.endswith('CT'):
|
||||
modality = 'CT'
|
||||
# continue
|
||||
else:
|
||||
modality = 'other'
|
||||
print(skip, root2, modality)
|
||||
outdir = os.path.join(OUT_ROOT, os.path.relpath(root2, PATIENTS_ROOT))
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
for e in sorted(os.scandir(root2), key=lambda e: e.name):
|
||||
if not e.name.endswith('.nii.gz'):
|
||||
continue
|
||||
if '_RTDOSE_' in e.name:
|
||||
continue
|
||||
if '_DTI_' in e.name:
|
||||
continue
|
||||
if '_ROI1.' in e.name:
|
||||
continue
|
||||
|
||||
OUT_IMG = os.path.join(outdir, e.name)
|
||||
if os.path.isfile(OUT_IMG):
|
||||
print('skip', OUT_IMG)
|
||||
continue
|
||||
|
||||
print(e.name, e.path)
|
||||
|
||||
fix = ants.image_read(e.path, reorient=True)
|
||||
mytx = registration(ct0, ct1, fix)
|
||||
if mytx is None:
|
||||
continue
|
||||
print(mytx['ratio'], mytx['metric'])
|
||||
|
||||
registered += 1
|
||||
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
OUT_WARP = OUT_IMG.replace('.nii.gz', '.warp.nii.gz')
|
||||
OUT_MSK = OUT_IMG.replace('.nii.gz', '.mask.nii.gz')
|
||||
OUT_JSON = OUT_IMG.replace('.nii.gz', '.json')
|
||||
OUT_MAT = OUT_IMG.replace('.nii.gz', '.mat')
|
||||
|
||||
jj = {
|
||||
'ct' : mytx['ct'],
|
||||
'type' : mytx['type'],
|
||||
'metric': mytx['metric'],
|
||||
'ratio' : mytx['ratio'],
|
||||
}
|
||||
|
||||
with open(OUT_JSON, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
if mytx['fwdtransforms']:
|
||||
shutil.copy(mytx['fwdtransforms'][0], OUT_MAT)
|
||||
ants.image_write(mytx['mask'], OUT_MSK)
|
||||
ants.image_write(mytx['warpedout'], OUT_WARP)
|
||||
|
||||
metric = mytx['metric']
|
||||
metric_dir = os.path.join(OUT_ROOT, "1")
|
||||
OUT_TXT = os.path.join(metric_dir, '%f-%s'%(metric, e.name.replace('.nii.gz', '.txt')))
|
||||
jj['dir'] = outdir
|
||||
os.makedirs(metric_dir, exist_ok=True)
|
||||
with open(OUT_TXT, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
shutil.copy(e.path, OUT_IMG)
|
||||
|
||||
|
||||
return registered
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# check('/mnt/1220/Public/dataset2/M6/QT6QVY34') # Lung
|
||||
# check('/mnt/1220/Public/dataset2/M6/24V62QQM') # index limit
|
||||
# check('/mnt/1220/Public/dataset2/M6/WD34XIQO') # index limit
|
||||
# check('/mnt/1220/Public/dataset2/M6/26TYQI3C') # bad registration, need DenseRigid for 1 CT only
|
||||
# check('/mnt/1220/Public/dataset2/M6/5BXKANST') # low score
|
||||
# check('/mnt/1220/Public/dataset2/M6/BQ773ST6') # bbox problem
|
||||
# check('/mnt/1220/Public/dataset2/M6/OJVMKLLO') # series naming conventions
|
||||
# check('/mnt/1220/Public/dataset2/M6/PBH6IPXE') # TOF
|
||||
# check('/mnt/1220/Public/dataset2/M6/SYPFKLU4') # strange frame, eclipse doses
|
||||
# check('/mnt/1220/Public/dataset2/M6/TCZXFBY3') # bad registration
|
||||
# exit()
|
||||
|
||||
EXCLUDE = (
|
||||
# 'LLUQJUY4', #cervical
|
||||
)
|
||||
|
||||
os.makedirs(OUT_ROOT, exist_ok=True)
|
||||
|
||||
LOCK_DIR = os.path.join(OUT_ROOT, '0lock')
|
||||
os.makedirs(LOCK_DIR, exist_ok=True)
|
||||
for e in sorted(os.scandir(PATIENTS_ROOT), key=lambda e: e.name):
|
||||
if e.is_dir():
|
||||
d = shelve.open(SHELVE)
|
||||
if e.name in d or e.name in EXCLUDE:
|
||||
print('skip', e.name)
|
||||
d.close()
|
||||
continue
|
||||
d.close()
|
||||
lock_path = os.path.join(LOCK_DIR, '%s.lock'%e.name)
|
||||
lock = filelock.FileLock(lock_path, timeout=1)
|
||||
try:
|
||||
lock.acquire()
|
||||
except:
|
||||
print(lock_path, 'locked')
|
||||
continue
|
||||
ret = check(e.path)
|
||||
lock.release()
|
||||
# exit()
|
||||
d = shelve.open(SHELVE)
|
||||
d[e.name] = ret
|
||||
d.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
544
m6resample.py
Normal file
544
m6resample.py
Normal file
|
@ -0,0 +1,544 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import shelve
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import ants
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import SimpleITK as sitk
|
||||
|
||||
PATIENTS_ROOT = '/mnt/1220/Public/dataset2/M6'
|
||||
OUT_ROOT = '/home/xfr/git9/Taipei-1/0'
|
||||
OUT_ROOT = '/mnt/1220/Public/dataset2/M7'
|
||||
SHELVE = os.path.join(OUT_ROOT, '0shelve')
|
||||
|
||||
MAX_Y = 256
|
||||
|
||||
SIZE_X = 249
|
||||
SIZE_Y = 249
|
||||
SIZE_Z = 192
|
||||
# SIZE_Z = 256
|
||||
|
||||
MIN_OVERLAP = 0.50
|
||||
MIN_METRIC = -0.50
|
||||
|
||||
# def resize_with_crop_or_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
def resize_with_pad(image, tx = SIZE_X, ty = SIZE_Y, tz = SIZE_Z):
|
||||
sx, sy, sz = image.GetSize()
|
||||
l = [(tx-sx)//2,
|
||||
(ty-sy)//2,
|
||||
(tz-sz)//2,]
|
||||
u = [tx-sx-l[0],
|
||||
ty-sy-l[1],
|
||||
tz-sz-l[2],
|
||||
]
|
||||
# print (l, u)
|
||||
return sitk.ConstantPad(image, l, u)
|
||||
|
||||
|
||||
def draw_sitk(image, d, post):
|
||||
a = sitk.GetArrayFromImage(image)
|
||||
s = a.shape
|
||||
|
||||
fig, axs = plt.subplots(1, 3)
|
||||
# fig.suptitle('%dx%dx%d'%(s[2], s[1], s[0]))
|
||||
axs.flat[0].imshow(a[s[0]//2,:,:], cmap='gray')
|
||||
axs.flat[1].imshow(a[:,s[1]//2,:], cmap='gray')
|
||||
axs.flat[2].imshow(a[:,:,s[2]//2], cmap='gray')
|
||||
axs.flat[0].axis('off')
|
||||
axs.flat[1].axis('off')
|
||||
axs.flat[2].axis('off')
|
||||
axs.flat[1].invert_yaxis()
|
||||
axs.flat[2].invert_yaxis()
|
||||
plt.tight_layout()
|
||||
os.makedirs(d, exist_ok=True)
|
||||
plt.savefig(os.path.join(d, '%dx%dx%d-%s'%(s[2],s[1],s[0],post)))
|
||||
plt.close()
|
||||
# exit()
|
||||
|
||||
def bbox2_3D(img):
|
||||
|
||||
r = np.any(img, axis=(1, 2))
|
||||
c = np.any(img, axis=(0, 2))
|
||||
z = np.any(img, axis=(0, 1))
|
||||
|
||||
if not np.any(r):
|
||||
return -1, -1, -1, -1, -1, -1
|
||||
|
||||
rmin, rmax = np.where(r)[0][[0, -1]]
|
||||
cmin, cmax = np.where(c)[0][[0, -1]]
|
||||
zmin, zmax = np.where(z)[0][[0, -1]]
|
||||
|
||||
return rmin, rmax, cmin, cmax, zmin, zmax
|
||||
|
||||
def physical_size(a):
|
||||
A = a.numpy().shape
|
||||
B = a.spacing
|
||||
C = (
|
||||
A[0]*B[0],
|
||||
A[1]*B[1],
|
||||
A[2]*B[2],
|
||||
)
|
||||
|
||||
print(A,B,C)
|
||||
|
||||
return C
|
||||
|
||||
def registration(ct0, ct1, mr, modality = 'CT'):
|
||||
# print(
|
||||
# physical_size(ct0),
|
||||
# physical_size(moving)
|
||||
# )
|
||||
TX = []
|
||||
|
||||
FIXS = (ct0, ct1)
|
||||
# FIXS = (ct1,)
|
||||
TYPES = (
|
||||
# 'Translation',
|
||||
|
||||
'Rigid',
|
||||
'QuickRigid',
|
||||
'DenseRigid',
|
||||
'BOLDRigid',
|
||||
|
||||
# 'Similarity',
|
||||
# 'Affine',
|
||||
# 'AffineFast',
|
||||
# 'BOLDAffine',
|
||||
# 'TRSAA',
|
||||
|
||||
)
|
||||
|
||||
if modality == 'CT':
|
||||
FIXS = (ct1, ct0)
|
||||
# TYPES = (
|
||||
# # 'Translation',
|
||||
# 'Rigid',
|
||||
# )
|
||||
|
||||
start = time.time()
|
||||
for ff in range(len(FIXS)):
|
||||
for typ in TYPES:
|
||||
ct = FIXS[ff]
|
||||
|
||||
print(typ)
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(ct, mr, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
)
|
||||
|
||||
am = ants.create_ants_metric(ct,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
moving_mask = mytx['mask'],
|
||||
)
|
||||
mytx['metricFM'] = am.get_value()
|
||||
am = ants.create_ants_metric(mr,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation')
|
||||
mytx['metricMM'] = am.get_value()
|
||||
mytx['metric'] = min([mytx['metricFM'], mytx['metricMM']])
|
||||
mytx['ct'] = ff
|
||||
mytx['type'] = (typ, 'fwd')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedmovout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricFM'], mytx['metricMM'])
|
||||
|
||||
# '''
|
||||
|
||||
mytx = ants.registration(mr, ct, typ)
|
||||
|
||||
ones = np.ones(mr.numpy().shape)
|
||||
mask1 = mr.new_image_like(ones)
|
||||
mytx['mask'] = ants.apply_transforms(ct0, mask1, mytx['fwdtransforms'],
|
||||
interpolator='genericLabel',
|
||||
whichtoinvert=[True],
|
||||
)
|
||||
|
||||
am = ants.create_ants_metric(mr,
|
||||
mytx['warpedmovout'],
|
||||
metric_type='MattesMutualInformation')
|
||||
mytx['metricFM'] = am.get_value()
|
||||
am = ants.create_ants_metric(ct,
|
||||
mytx['warpedfixout'],
|
||||
metric_type='MattesMutualInformation',
|
||||
fixed_mask = mytx['mask'],
|
||||
)
|
||||
mytx['metricMM'] = am.get_value()
|
||||
mytx['metric'] = min([mytx['metricFM'], mytx['metricMM']])
|
||||
mytx['ct'] = ff
|
||||
mytx['type'] = (typ, 'inv')
|
||||
|
||||
mytx['warpedout'] = mytx['warpedfixout']
|
||||
TX.append(mytx)
|
||||
print(mytx['metric'], mytx['metricFM'], mytx['metricMM'])
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
if min([t['metric'] for t in TX]) < MIN_METRIC:
|
||||
break
|
||||
|
||||
print(time.time()-start, 'seconds')
|
||||
|
||||
tx = {
|
||||
'metric': 0,
|
||||
}
|
||||
|
||||
for t in TX:
|
||||
if t['metric'] < tx['metric']:
|
||||
tx = t
|
||||
|
||||
tx['ratio'] = tx['mask'].numpy().sum() / np.prod(ct0.numpy().shape)
|
||||
|
||||
return tx
|
||||
|
||||
def check(epath):
|
||||
roi=None
|
||||
for root, dirs, files in os.walk(epath):
|
||||
dirs.sort()
|
||||
RT_DIR = os.path.join(root, 'RT')
|
||||
EXTERNAL_DIR = os.path.join(RT_DIR, 'EXTERNAL')
|
||||
if not os.path.isdir(EXTERNAL_DIR):
|
||||
continue
|
||||
|
||||
ORGAN_DIR = os.path.join(RT_DIR, 'ORGAN')
|
||||
if not os.path.isdir(ORGAN_DIR):
|
||||
continue
|
||||
|
||||
# if there is no eye, it's no a brain image
|
||||
eye = None
|
||||
organs = sorted(os.scandir(ORGAN_DIR), key=lambda e: e.name)
|
||||
for o in organs:
|
||||
if 'eye' in o.name.lower():
|
||||
eye = o
|
||||
if eye is None:
|
||||
print('no eye... skip', root)
|
||||
# exit()
|
||||
return None
|
||||
|
||||
|
||||
CT_IMAGE = os.path.join(RT_DIR, 'ct_image.nii.gz')
|
||||
|
||||
externals = sorted(os.scandir(EXTERNAL_DIR), key=lambda e: -e.stat().st_size)
|
||||
# for e in externals:
|
||||
# print(e.name, e.stat().st_size)
|
||||
|
||||
print(externals[0].path)
|
||||
|
||||
external = sitk.ReadImage(externals[0].path)
|
||||
# print(external.GetSize())
|
||||
# print(external.GetSpacing())
|
||||
|
||||
sz = external.GetSize()
|
||||
sp = external.GetSpacing()
|
||||
|
||||
outputSize = (
|
||||
round(sz[0]*sp[0]),
|
||||
round(sz[1]*sp[1]),
|
||||
round(sz[2]*sp[2]),
|
||||
)
|
||||
|
||||
outputOrigin = external.GetOrigin()
|
||||
outputSpacing = (1., 1., 1.)
|
||||
outputDirection = external.GetDirection()
|
||||
|
||||
|
||||
mask = sitk.Resample(external, outputSize, sitk.Transform(), sitk.sitkNearestNeighbor, outputOrigin, outputSpacing, outputDirection)
|
||||
# sitk.WriteImage(mask, '0mask.nii.gz')
|
||||
# print(mask.GetSize())
|
||||
# print(mask.GetSpacing())
|
||||
|
||||
|
||||
lsif = sitk.LabelShapeStatisticsImageFilter()
|
||||
lsif.Execute(mask)
|
||||
|
||||
if 1 not in lsif.GetLabels():
|
||||
print('strange mask... skip', root)
|
||||
exit()
|
||||
|
||||
|
||||
boundingBox = lsif.GetBoundingBox(1)
|
||||
print(boundingBox)
|
||||
ix, iy, iz, sx, sy, sz = boundingBox
|
||||
|
||||
sy = min(sy, MAX_Y)
|
||||
|
||||
sz0 = min(sz, SIZE_Z-2) # will pad later
|
||||
iz0 = iz+sz-sz0
|
||||
|
||||
roi = sitk.RegionOfInterest(mask, (sx, sy, sz0), (ix, iy, iz0))
|
||||
|
||||
# remove frame
|
||||
|
||||
ER = 10
|
||||
ER = 29
|
||||
ER = 44
|
||||
ER = 40 # remove most of it
|
||||
ER = 37 # remove most of it
|
||||
|
||||
roi = sitk.BinaryErode(roi, (ER,ER,ER))
|
||||
roi2 = sitk.BinaryDilate(roi, (ER,ER,ER))
|
||||
# sitk.WriteImage(roi, '0roi.nii.gz')
|
||||
# exit()
|
||||
|
||||
# print(external.GetSize())
|
||||
# print(roi.GetSize())
|
||||
|
||||
#Now no shoulder, get BB again
|
||||
lsif.Execute(roi2)
|
||||
|
||||
# Something wrong? 6L63PXNV
|
||||
# print(lsif.GetLabels())
|
||||
if 1 not in lsif.GetLabels():
|
||||
return None
|
||||
|
||||
boundingBox = lsif.GetBoundingBox(1)
|
||||
print(boundingBox)
|
||||
|
||||
ix2, iy2, iz2, sx2, sy2, sz2 = boundingBox
|
||||
# sy2 = sy
|
||||
iy2 = 0
|
||||
# iy2 = min(iy2, roi2.GetSize()[1]-sy2)
|
||||
sy2 = (sy+sy2)//2
|
||||
|
||||
print((sx2, sy2, sz2), (ix2, iy2, iz2))
|
||||
roi = sitk.RegionOfInterest(roi2, (sx2, sy2, sz0), (ix2, iy2, 0))
|
||||
|
||||
# roi = resize_with_pad(roi)
|
||||
# roi = sitk.FFTPad(roi)
|
||||
ypad = min(2, (SIZE_Y-sy2)//2)
|
||||
roi = sitk.ConstantPad(roi, (1,ypad,1), (1,ypad,1))
|
||||
# roi = sitk.ConstantPad(roi, (0,0,0), (0,SIZE_Y-sy2,0))
|
||||
|
||||
print(external.GetSize())
|
||||
print(roi.GetSize())
|
||||
|
||||
|
||||
# sitk.WriteImage(external, '0external.nii.gz')
|
||||
# sitk.WriteImage(roi, '0roi.nii.gz')
|
||||
|
||||
# exit()
|
||||
|
||||
ct = sitk.ReadImage(CT_IMAGE,
|
||||
# sitk.sitkFloat32
|
||||
)
|
||||
CTresampled = sitk.Resample(ct, roi,
|
||||
# sitk.Transform(),
|
||||
# sitk.sitkBSpline,
|
||||
)
|
||||
|
||||
rescaled = sitk.RescaleIntensity(sitk.Clamp(CTresampled,
|
||||
sitk.sitkUInt8,
|
||||
# sitk.sitkFloat32,
|
||||
0, 80))
|
||||
|
||||
TV = None
|
||||
for e in sorted(os.scandir(RT_DIR), key=lambda e: e.name):
|
||||
if not e.name.startswith('TV-'):
|
||||
continue
|
||||
tv = sitk.ReadImage(e.path)
|
||||
TVresampled = sitk.Resample(tv, roi,
|
||||
sitk.Transform(),
|
||||
sitk.sitkNearestNeighbor,
|
||||
)
|
||||
if TV is None:
|
||||
TV = TVresampled
|
||||
else:
|
||||
TV = sitk.Maximum(TV, TVresampled)
|
||||
|
||||
if TV is None:
|
||||
continue
|
||||
|
||||
EXresampled = sitk.Resample(external, roi,
|
||||
sitk.Transform(),
|
||||
sitk.sitkNearestNeighbor,
|
||||
)
|
||||
|
||||
relpath = os.path.relpath(root, PATIENTS_ROOT)
|
||||
OUT_DIR = os.path.join(OUT_ROOT, relpath)
|
||||
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
CT0 = os.path.join(OUT_DIR, 'ct0.nii.gz')
|
||||
CT1 = os.path.join(OUT_DIR, 'ct1.nii.gz')
|
||||
print(CT0)
|
||||
sitk.WriteImage(CTresampled, CT0)
|
||||
sitk.WriteImage(rescaled, CT1)
|
||||
sitk.WriteImage(TV+EXresampled, os.path.join(OUT_DIR, 'label.nii.gz'))
|
||||
|
||||
draw_sitk(rescaled, os.path.join(OUT_ROOT, '0'), '%s.png'%relpath.replace('/', '-'))
|
||||
# exit()
|
||||
|
||||
if max(roi.GetSize()) >= SIZE_X+64: #BODY
|
||||
continue
|
||||
|
||||
if max(roi.GetSize()) > SIZE_X:
|
||||
exit()
|
||||
|
||||
# exit()
|
||||
# continue # skip registration first
|
||||
|
||||
ct0 = ants.image_read(CT0)
|
||||
ct1 = ants.image_read(CT1)
|
||||
# fixed = ants.image_read(CT0)
|
||||
for root2, dirs2, files2 in os.walk(root):
|
||||
dirs2.sort()
|
||||
skip = (root2==root) or ('RT' in root2.split('/'))
|
||||
if skip:
|
||||
continue
|
||||
if root2.endswith('CT'):
|
||||
modality = 'CT'
|
||||
fixed=ct1
|
||||
else:
|
||||
modality = 'other'
|
||||
fixed=ct1
|
||||
print(skip, root2, modality)
|
||||
relpath = os.path.relpath(root2, PATIENTS_ROOT)
|
||||
out_dir = os.path.join(OUT_ROOT, relpath)
|
||||
for mv in sorted(os.scandir(root2), key=lambda e: e.name):
|
||||
|
||||
if not mv.name.endswith('nii.gz'):
|
||||
continue
|
||||
if mv.name.startswith('dose'):
|
||||
continue
|
||||
if '_DTI_' in mv.name:
|
||||
continue
|
||||
if '_RTDOSE_' in mv.name:
|
||||
continue
|
||||
if '_ROI1.' in mv.name:
|
||||
continue
|
||||
# if '_swi_' in mv.name:
|
||||
# continue
|
||||
# if '_ph.' in mv.name:
|
||||
# continue
|
||||
# if '_Doses_' in mv.name:
|
||||
# continue
|
||||
# if '_phMag.' in mv.name:
|
||||
# continue
|
||||
|
||||
OUT_IMG = os.path.join(out_dir, mv.name)
|
||||
if os.path.isfile(OUT_IMG):
|
||||
print('skip', OUT_IMG)
|
||||
continue
|
||||
|
||||
split = mv.name[:-7].split('_')
|
||||
series = None
|
||||
pos = -1
|
||||
while series is None:
|
||||
try:
|
||||
series = int(split[pos])
|
||||
except:
|
||||
pos -= 1
|
||||
print(mv.name, series)
|
||||
# if series > 99:
|
||||
# continue
|
||||
|
||||
moving = ants.image_read(mv.path)
|
||||
|
||||
# skip thin images
|
||||
_, _, _, _, zmin, zmax = bbox2_3D(moving.numpy())
|
||||
mv_height = moving.spacing[2] * (zmax-zmin)
|
||||
z_ratio = mv_height / SIZE_Z
|
||||
if z_ratio < MIN_OVERLAP:
|
||||
print("skip", mv.name, mv_height, z_ratio)
|
||||
continue
|
||||
|
||||
print(mv.path, moving.view().shape, mv_height, z_ratio)
|
||||
|
||||
if moving.max() == 0.0:
|
||||
print('Total Mass of the image was zero. Aborting here to prevent division by zero later on.')
|
||||
continue
|
||||
|
||||
mytx = registration(ct0, ct1, moving, modality)
|
||||
print(mytx['ratio'], mytx['metric'])
|
||||
# if (mytx['metric'] < MIN_METRIC) and (mytx['ratio'] < MIN_OVERLAP):
|
||||
# print("skip", mv.name, mytx['ratio'])
|
||||
# continue
|
||||
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
OUT_MSK = OUT_IMG.replace('.nii.gz', '.mask.nii.gz')
|
||||
OUT_JSON = OUT_IMG.replace('.nii.gz', '.json')
|
||||
OUT_MAT = OUT_IMG.replace('.nii.gz', '.mat')
|
||||
|
||||
jj = {
|
||||
'ct' : mytx['ct'],
|
||||
'type' : mytx['type'],
|
||||
'metric': mytx['metric'],
|
||||
'ratio' : mytx['ratio'],
|
||||
}
|
||||
|
||||
with open(OUT_JSON, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
shutil.copy(mytx['fwdtransforms'][0], OUT_MAT)
|
||||
ants.image_write(mytx['mask'], OUT_MSK)
|
||||
ants.image_write(mytx['warpedout'], OUT_IMG)
|
||||
|
||||
metric = mytx['metric']
|
||||
|
||||
metric_dir = os.path.join(OUT_ROOT, "1")
|
||||
OUT_TXT = os.path.join(metric_dir, '%f-%s'%(metric, mv.name.replace('.nii.gz', '.txt')))
|
||||
|
||||
jj['dir'] = out_dir
|
||||
|
||||
os.makedirs(metric_dir, exist_ok=True)
|
||||
with open(OUT_TXT, 'w') as f:
|
||||
json.dump(jj, f, indent=1)
|
||||
|
||||
|
||||
# exit()
|
||||
|
||||
# exit()
|
||||
if roi is None:
|
||||
return None
|
||||
return roi.GetSize()
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# check('/mnt/1220/Public/dataset2/M6/QT6QVY34') # Lung
|
||||
# check('/mnt/1220/Public/dataset2/M6/24V62QQM') # index limit
|
||||
# check('/mnt/1220/Public/dataset2/M6/WD34XIQO') # index limit
|
||||
# check('/mnt/1220/Public/dataset2/M6/26TYQI3C') # bad registration, need DenseRigid for 1 CT only
|
||||
# check('/mnt/1220/Public/dataset2/M6/5BXKANST') # low score
|
||||
# check('/mnt/1220/Public/dataset2/M6/BQ773ST6') # bbox problem
|
||||
# check('/mnt/1220/Public/dataset2/M6/OJVMKLLO') # series naming conventions
|
||||
# check('/mnt/1220/Public/dataset2/M6/PBH6IPXE') # TOF
|
||||
# check('/mnt/1220/Public/dataset2/M6/SYPFKLU4') # strange frame, eclipse doses
|
||||
# check('/mnt/1220/Public/dataset2/M6/TCZXFBY3') # bad registration
|
||||
# exit()
|
||||
|
||||
EXCLUDE = (
|
||||
'LLUQJUY4', #cervical
|
||||
)
|
||||
|
||||
EXCLUDE = ()
|
||||
|
||||
os.makedirs(OUT_ROOT, exist_ok=True)
|
||||
d = shelve.open(SHELVE) # open -- file may get suffix added by low-level
|
||||
|
||||
for e in sorted(os.scandir(PATIENTS_ROOT), key=lambda e: e.name):
|
||||
if e.is_dir():
|
||||
if e.name in d or e.name in EXCLUDE:
|
||||
print('skip', e.name)
|
||||
continue
|
||||
ret = check(e.path)
|
||||
d[e.name] = ret
|
||||
d.sync()
|
||||
# exit()
|
||||
d.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue