Diff of /code/image_utils.py [000000] .. [32d261]

Switch to side-by-side view

--- a
+++ b/code/image_utils.py
@@ -0,0 +1,473 @@
+import os
+import numpy as np
+import nibabel as nib
+from numpy.linalg import inv
+
+def rescale_intensity(image, thres=(1.0, 99.0)):
+    """ Rescale the image intensity to the range of [0, 1] """
+    val_l, val_h = np.percentile(image, thres)
+    image2 = image
+    image2[image < val_l] = val_l
+    image2[image > val_h] = val_h
+    image2 = (image2.astype(np.float32) - val_l) / (val_h - val_l + 1e-6)
+    return image2
+
+
+def imagePreprocessing(originalNii, data_dir, atlas_dir):
+     
+    os.system('headertool '
+              '{0} '
+              '{1}/lvsa_.nii.gz '
+              '-reset'
+              .format(originalNii, data_dir))
+
+    os.system('temporalalign '
+              '{0}/temporal.gipl '
+              '{1}/lvsa_.nii.gz '
+              '{1}/lvsa_.nii.gz ' 
+              '-St1 0 '
+              '-St2 0 '
+              '-Et1 1 '
+              '-Et2 1'
+              .format(atlas_dir, data_dir))
+
+    os.system('autocontrast '
+              '{0}/lvsa_.nii.gz '
+              '{0}/lvsa_.nii.gz'
+              .format(data_dir))
+        
+    os.system('cardiacphasedetection '
+              '{0}/lvsa_.nii.gz '
+              '{0}/lvsa_ED.nii.gz '
+              '{0}/lvsa_ES.nii.gz'
+              .format(data_dir))
+    
+    print('  Image preprocessing is done ...')
+
+
+def clearBaseManbrance(data_dir, output_name):
+
+    nim = nib.load('{0}/{1}'.format(data_dir, output_name))
+    seg = nim.get_data()
+    if seg.ndim == 4:
+        seg = np.squeeze(seg, axis=-1).astype(np.int16)
+        
+    # find the last slice that has RV component 
+    rv = (seg == 4).astype(np.int16)   
+    for i in reversed(range(seg.shape[2])):
+        if np.sum(rv[:,:,i]) > 0: 
+            break
+    lastAppearSlice = i 
+    
+    # create a 2D mask that average the last 12 slice of RV which is robust to noise
+    slicesUsed = 12
+    tmp = np.zeros((seg.shape[0], seg.shape[1]), dtype=np.int16)
+    for j in range(slicesUsed):
+        tmp = tmp + rv[:,:,lastAppearSlice-j]
+    tmp = (tmp > 0).astype(np.int16)   
+    
+    # create a volume mask used to remove the base manbrance caused by RV myocardium
+    mask = np.ones((seg.shape[2], seg.shape[0], seg.shape[1]), dtype=np.int16)
+    mask[lastAppearSlice-slicesUsed:,:,:] = 1 - tmp
+    mask = np.transpose(mask, axes=(1, 2, 0))
+    seg = np.multiply(seg, mask)
+    
+    # fill the gap/hole of RV 
+    flat = False
+    if flat:
+        seg = np.transpose(seg, axes=(2, 0, 1))
+        seg[lastAppearSlice-slicesUsed:lastAppearSlice-3,:,:] = seg[lastAppearSlice-slicesUsed:lastAppearSlice-3,:,:] + 4*tmp
+        seg = np.transpose(seg, axes=(1, 2, 0))
+    else:
+        seg[:,:,lastAppearSlice-slicesUsed:] = seg[:,:,lastAppearSlice-slicesUsed:] + 4*rv[:,:,lastAppearSlice-slicesUsed:]
+    
+    ###############################################################################
+    # find the last slice that has LV component 
+    lv = (seg == 1).astype(np.int16)   
+    for i in reversed(range(seg.shape[2])):
+        if np.sum(lv[:,:,i]) > 0: 
+            break
+    lastAppearSlice = i 
+    
+    # create a 2D mask that average the last 5 slice of RV which is robust to noise
+    slicesUsed = 10
+    tmp = np.zeros((seg.shape[0], seg.shape[1]), dtype=np.int16)
+    for j in range(slicesUsed):
+        tmp = tmp + lv[:,:,lastAppearSlice-j]
+    tmp = (tmp > 0).astype(np.int16)   
+    
+    # create a volume mask used to remove the manbrance caused by LV myocardium
+    mask = np.ones((seg.shape[2], seg.shape[0], seg.shape[1]), dtype=np.int16)
+    mask[lastAppearSlice-slicesUsed:,:,:] = 1 - tmp
+    mask = np.transpose(mask, axes=(1, 2, 0))
+    seg = np.multiply(seg, mask)
+    
+    # fill the gap/hole of LV 
+    flat = True
+    if flat:
+        seg = np.transpose(seg, axes=(2, 0, 1))
+        seg[lastAppearSlice-slicesUsed:lastAppearSlice-1,:,:] = seg[lastAppearSlice-slicesUsed:lastAppearSlice-1,:,:] + tmp
+        seg = np.transpose(seg, axes=(1, 2, 0))
+    else:
+        seg[:,:,lastAppearSlice-slicesUsed:] = seg[:,:,lastAppearSlice-slicesUsed:] + lv[:,:,lastAppearSlice-slicesUsed:]
+
+    # save the result
+    nim2 = nib.Nifti1Image(seg, nim.affine)
+    nim2.header['pixdim'] = nim.header['pixdim']
+    nib.save(nim2, '{0}/{1}'.format(data_dir, output_name))
+
+
+def removeSegsAboveBase(data_dir, output_name):
+
+    # Read segmentations
+    nim = nib.load('{0}/{1}'.format(data_dir, output_name))
+    seg = nim.get_data()
+    if seg.ndim == 4:
+        seg = np.squeeze(seg, axis=-1).astype(np.int16)
+    os.system('vtk2txt {0}/landmarks.vtk {0}/landmarks.txt'.format(data_dir)) 
+    
+    # convert txt file into matrix
+    file = open('{0}/landmarks.txt'.format(data_dir), 'r') 
+    A = file.read()
+    tmp = np.zeros(18)  
+    i, c = 0, 0
+    for p in range(len(A)):
+        if A[p] == ' ' or A[p] == '\n':
+            tmp[i] = np.float32(A[c:p])
+            i = i + 1
+            c = p + 1;
+    tmp = np.reshape(tmp,(6,3))        
+    landmarks = np.ones((6,4)) 
+    landmarks[:,:-1] = tmp
+    landmarks = np.transpose(landmarks).astype(np.float32)           
+    os.system('rm {0}/landmarks.txt'.format(data_dir))    
+       
+    # map world coordinate system to image pixel position
+    pixelsPositions = np.ceil(np.dot(inv(nim.affine),landmarks)).astype(np.int16) 
+    pixelsPositions = np.delete(pixelsPositions, (-1), axis=0)
+    pixelsPositions = np.transpose(pixelsPositions).astype(np.int16) 
+    
+    if output_name[9:11]=='ED':
+        seg[:,:,pixelsPositions[5,2]+1:] = 0
+    else:
+        seg[:,:,pixelsPositions[5,2]:] = 0
+    
+    nim2 = nib.Nifti1Image(seg, nim.affine)
+    nim2.header['pixdim'] = nim.header['pixdim']
+    nib.save(nim2, '{0}/{1}'.format(data_dir, output_name))
+    
+
+def formHighResolutionImg(subject_dir, fr): 
+    
+    os.system('resample ' 
+              '{0}/lvsa_{1}.nii.gz '
+              '{0}/lvsa_SR_{1}.nii.gz '
+              '-size 1.25 1.25 2'
+              .format(subject_dir, fr))
+        
+#    os.system('enlarge_image '
+#              '{0}/lvsa_SR_{1}.nii.gz '
+#              '{0}/lvsa_SR_{1}.nii.gz '
+#              '-z 20 '
+#              '-value 0'
+#              .format(subject_dir, fr))
+
+    
+def convertImageSegment(data_dir, fr):
+   
+    os.system('convert '
+              '{0}/seg_lvsa_SR_{1}.nii.gz '
+              '{0}/PHsegmentation_{1}.gipl'
+              .format(data_dir, fr))
+    
+    os.system('cp '
+              '{0}/lvsa_SR_{1}.nii.gz '
+              '{0}/lvsa_{1}_enlarged_SR.nii.gz'
+              .format(data_dir, fr))
+    
+    
+def outputVolumes(subject_dir, data_dir, subject, fr):
+     
+    os.system('rm '
+              '{0}/{1}_{2}.txt'
+              .format(data_dir, subject, fr))
+    
+    os.system('cardiacvolumecount '
+              '{0}/PHsegmentation_{3}.gipl 1 '
+              '-output '
+              '{1}/{2}_{3}.txt'
+              .format(subject_dir, data_dir, subject, fr))
+    
+    os.system('cardiacvolumecount '
+              '{0}/PHsegmentation_{3}.gipl 2 '
+              '-output '
+              '{1}/{2}_{3}.txt '
+              '-scale 1.05'
+              .format(subject_dir, data_dir, subject, fr))
+    
+    os.system('cardiacvolumecount '
+              '{0}/PHsegmentation_{3}.gipl 4 '
+              '-output '
+              '{1}/{2}_{3}.txt'
+              .format(subject_dir, data_dir, subject, fr))
+    
+    os.system('cardiacvolumecount '
+              '{0}/PHsegmentation_{3}.gipl 3 '
+              '-output '
+              '{1}/{2}_{3}.txt '
+              '-scale 1.05'
+              .format(subject_dir, data_dir, subject, fr))
+    
+    
+def moveVolumes(subject_dir, sizes_dir, fr):
+     
+    os.system('cp '
+              '{0}/lvsa_{2}.nii.gz '
+              '{1}/lvsa_{2}.nii.gz'
+              .format(subject_dir, sizes_dir, fr))
+    
+    os.system('rm '
+              '{0}/lvsa_{1}.nii.gz '
+              .format(subject_dir, fr))
+    
+    os.system('cp '
+              '{0}/seg_lvsa_{2}.nii.gz '
+              '{1}/2D_segmentation_{2}.nii.gz'
+              .format(subject_dir, sizes_dir, fr))
+    
+    os.system('rm '
+              '{0}/seg_lvsa_{1}.nii.gz '
+              .format(subject_dir, fr))
+    
+    os.system('cp '
+              '{0}/lvsa_SR_{2}.nii.gz '
+              '{1}/lvsa_{2}_SR.nii.gz'
+              .format(subject_dir, sizes_dir, fr))
+    
+    os.system('rm '
+              '{0}/lvsa_SR_{1}.nii.gz '
+              .format(subject_dir, fr))
+    
+    os.system('cp '
+              '{0}/seg_lvsa_SR_{2}.nii.gz '
+              '{1}/3D_segmentation_{2}.nii.gz'
+              .format(subject_dir, sizes_dir, fr))
+    
+    os.system('rm '
+              '{0}/seg_lvsa_SR_{1}.nii.gz '
+              .format(subject_dir, fr))
+
+    
+def refineFusionResults(data_dir, output_name, alfa): 
+    
+    ##########################################
+    os.system('binarize '
+              '{0}/{1} '
+              '{0}/tmps/hrt.nii.gz '
+              '1 4 255 0'
+              .format(data_dir, output_name))
+    
+    os.system('blur '
+              '{0}/tmps/hrt.nii.gz '
+              '{0}/tmps/hrt.nii.gz '
+              '{1}'
+              .format(data_dir, alfa))
+    
+    os.system('threshold '
+              '{0}/tmps/hrt.nii.gz '
+              '{0}/tmps/hrt.nii.gz '
+              '130'
+              .format(data_dir))
+    
+    ##########################################
+    os.system('binarize '
+              '{0}/{1} '
+              '{0}/tmps/rvendo.nii.gz '
+              '4 4 255 0'
+              .format(data_dir, output_name))
+    
+    os.system('blur '
+              '{0}/tmps/rvendo.nii.gz '
+              '{0}/tmps/rvendo.nii.gz '
+              '{1}'
+              .format(data_dir, alfa))
+    
+    os.system('threshold '
+              '{0}/tmps/rvendo.nii.gz '
+              '{0}/tmps/rvendo.nii.gz '
+              '130'
+              .format(data_dir))
+    
+    ##########################################
+    os.system('binarize '
+              '{0}/{1} '
+              '{0}/tmps/lvepi.nii.gz '
+              '1 2 255 0'
+              .format(data_dir, output_name))
+       
+    os.system('blur '
+              '{0}/tmps/lvepi.nii.gz '
+              '{0}/tmps/lvepi.nii.gz '
+              '{1}'
+              .format(data_dir, alfa))
+    
+    os.system('threshold '
+              '{0}/tmps/lvepi.nii.gz '
+              '{0}/tmps/lvepi.nii.gz '
+              '115'
+              .format(data_dir))
+    
+    ##########################################
+    os.system('binarize '
+              '{0}/{1} '
+              '{0}/tmps/lvendo.nii.gz '
+              '1 1 255 0'
+              .format(data_dir, output_name))
+    
+    os.system('blur '
+              '{0}/tmps/lvendo.nii.gz '
+              '{0}/tmps/lvendo.nii.gz '
+              '{1}'
+              .format(data_dir, alfa))
+    
+    os.system('threshold '
+              '{0}/tmps/lvendo.nii.gz '
+              '{0}/tmps/lvendo.nii.gz '
+              '130'
+              .format(data_dir))
+       
+    ##########################################
+    os.system('padding '
+              '{0}/tmps/hrt.nii.gz '
+              '{0}/tmps/hrt.nii.gz '
+              '{0}/tmps/hrt.nii.gz '
+              '1 3'
+              .format(data_dir))
+    
+    os.system('padding '
+              '{0}/tmps/hrt.nii.gz '
+              '{0}/tmps/rvendo.nii.gz '
+              '{0}/tmps/rvendo.nii.gz '
+              '1 4'
+              .format(data_dir))
+    
+    os.system('padding '
+              '{0}/tmps/rvendo.nii.gz '
+              '{0}/tmps/lvepi.nii.gz '
+              '{0}/tmps/lvepi.nii.gz '
+              '1 2'
+              .format(data_dir))
+    
+    os.system('padding '
+              '{0}/tmps/lvepi.nii.gz '
+              '{0}/tmps/lvendo.nii.gz '
+              '{0}/{1} '
+              '1 1'
+              .format(data_dir, output_name))
+    
+    
+def allAtlasShapeSelection(dataset_dir):
+   
+    atlases_list, landmarks_list = {}, {}
+    
+    for fr in ['ED', 'ES']:
+            
+        atlases_list[fr], landmarks_list[fr] = [], [] 
+        i = 0
+        for atlas in sorted(os.listdir(dataset_dir)): 
+            
+            atlas_dir = os.path.join(dataset_dir, atlas)
+            
+            if not os.path.isdir(atlas_dir):
+                
+                print('  {0} is not a valid atlas directory, Discard'.format(atlas_dir))
+                
+                continue 
+            
+            atlas_3D_shape = '{0}/PHsegmentation_{1}.nii.gz'.format(atlas_dir, fr)
+           
+            landmarks = '{0}/landmarks.vtk'.format(atlas_dir)
+        
+            if i < 400:
+                if os.path.exists(atlas_3D_shape) or os.path.exists(landmarks):
+                    
+                    atlases_list[fr] += [atlas_3D_shape]
+                
+                    landmarks_list[fr] += [landmarks]
+            else:
+                print(atlases_list)
+                break
+            
+            i = i + 1
+                 
+    return atlases_list, landmarks_list
+
+
+def topSimilarAtlasShapeSelection(atlases, atlas_landmarks, subject_landmarks, tmps_dir, dofs_dir, DLSeg, param_dir, topSimilarAltasNo):            
+    
+    landmarks = False
+    
+    nmi = []
+    
+    topSimilarAtlases_list = []
+    
+    atlasNo = len(atlases)
+    
+    os.system('rm {0}/shapenmi*.txt'.format(tmps_dir))
+    
+    for i in range(atlasNo):
+        
+        if landmarks:
+            
+            os.system('pareg '
+                      '{0} '
+                      '{1} '
+                      '-dofout {2}/shapelandmarks_{3}.dof.gz'
+                      .format(subject_landmarks, atlas_landmarks[i], dofs_dir, i))
+        else: 
+            
+            os.system('areg '
+                      '{0} '
+                      '{1} '
+                      '-dofout {2}/shapelandmarks_{4}.dof.gz '
+                      '-parin {3}/segareg.txt'
+                      .format(DLSeg, atlases[i], dofs_dir, param_dir, i))
+                      
+        os.system('cardiacimageevaluation '
+                  '{0} '
+                  '{1} '
+                  '-nbins_x 64 '
+                  '-nbins_y 64 '
+                  '-dofin {2}/shapelandmarks_{4}.dof.gz '
+                  '-output {3}/shapenmi_{4}.txt'
+                  .format(DLSeg, atlases[i], dofs_dir, tmps_dir, i))
+                        
+        if os.path.exists('{0}/shapenmi_{1}.txt'.format(tmps_dir, i)):
+
+            similarities = np.genfromtxt('{0}/shapenmi_{1}.txt'.format(tmps_dir, i))
+            nmi += [similarities[3]]
+            
+        else:
+            nmi += [0]
+    
+    if topSimilarAltasNo < atlasNo:
+        
+        sortedIndexes = np.array(nmi).argsort()[::-1]  
+        
+        savedInd = np.zeros(topSimilarAltasNo, dtype=int)
+        
+        for i in range(topSimilarAltasNo):
+            
+            topSimilarAtlases_list += [atlases[sortedIndexes[i]]]
+            
+            savedInd[i] = sortedIndexes[i]
+    else:
+        
+        savedInd = np.zeros(atlasNo, dtype=int)
+        
+        topSimilarAtlases_list = atlases
+        
+        savedInd = np.arange(atlasNo)
+        
+    return topSimilarAtlases_list, savedInd    
+