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

Switch to unified view

a b/code/motionEstimation.py
1
#!/usr/bin/python
2
import os, glob
3
from multiprocessing import Pool
4
from functools import partial
5
6
7
# Perform motion tracking for cine MR
8
def track_cine(data_dir, par_dir, tamplate_dir):
9
    
10
    motion_dir = os.path.join(data_dir, 'motion')
11
    if os.path.exists(motion_dir):
12
       os.system('rm -r {0}'.format(motion_dir))
13
       os.mkdir(motion_dir)
14
    else:
15
       os.mkdir(motion_dir)
16
17
    # Split 4D nifti into time phases
18
    os.system('splitvolume '
19
              '{0}/lvsa_.nii.gz '
20
              '{1}/lvsa_ '
21
              '-sequence'
22
              .format(data_dir, motion_dir))
23
24
    n_frame = len(glob.glob('{0}/lvsa_??.nii.gz'.format(motion_dir)))
25
26
    # Inter-frame motion estimation
27
    for fr in range(1, n_frame):
28
        target = '{0}/lvsa_{1:02d}.nii.gz'.format(motion_dir, fr-1)
29
        source = '{0}/lvsa_{1:02d}.nii.gz'.format(motion_dir, fr)
30
        par = '{0}/ffd_motion.cfg'.format(par_dir)
31
        dof = '{0}/ffd_{1:02d}_to_{2:02d}.dof.gz'.format(motion_dir, fr-1, fr)
32
33
        if not os.path.exists(dof):
34
            os.system('mirtk register '
35
                      '{0} '
36
                      '{1} '
37
                      '-parin {2} '
38
                      '-dofout {3}'
39
                      .format(target, source, par, dof))
40
41
    # Compose inter-frame transformation fields
42
    for fr in range(2, n_frame):
43
        dofs = ''
44
        for k in range(1, fr+1):
45
            dof = '{0}/ffd_{1:02d}_to_{2:02d}.dof.gz'.format(motion_dir, k-1, k)
46
            dofs += dof + ' '
47
            dof_out = '{0}/ffd_comp_00_to_{1:02d}.dof.gz'.format(motion_dir, fr)
48
            if not os.path.exists(dof_out):
49
                os.system('mirtk compose-dofs '
50
                          '{0} '
51
                          '{1}'
52
                          .format(dofs, dof_out))
53
54
    # Refine motion fields
55
    # Composition of inter-frame motion fields can lead to accumulative errors. At this step, we refine the motion fields
56
    # by re-registering the n-th frame with the ED frame.
57
    for fr in range(2, n_frame):
58
        target = '{0}/lvsa_00.nii.gz'.format(motion_dir)
59
        source = '{0}/lvsa_{1:02d}.nii.gz'.format(motion_dir, fr)
60
        par = '{0}/ffd_refine.cfg'.format(par_dir)
61
        dofin = '{0}/ffd_comp_00_to_{1:02d}.dof.gz'.format(motion_dir, fr)
62
        dof = '{0}/ffd_00_to_{1:02d}.dof.gz'.format(motion_dir, fr)
63
        if not os.path.exists(dof):
64
            os.system('mirtk register '
65
                      '{0} '
66
                      '{1} '
67
                      '-parin {2} '
68
                      '-dofin {3} '
69
                      '-dofout {4}'
70
                      .format(target, source, par, dofin, dof))
71
72
    # Obtain the RV mesh with the same number of points as the template mesh
73
    os.system('srreg '
74
              '{2}/vtks/RV_ED.vtk '
75
              '{0}/RVendo_ED.vtk '
76
              '-dofout {1}/RV_srreg.dof.gz '
77
              '-symmetric'
78
              .format(tamplate_dir, motion_dir, data_dir))
79
    
80
    os.system('mirtk transform-points '
81
              '{0}/RVendo_ED.vtk '
82
              '{1}/RV_ED_srreg.vtk '
83
              '-dofin {1}/RV_srreg.dof.gz '
84
              '-invert'
85
              .format(tamplate_dir, motion_dir))
86
    
87
    os.system('sareg '
88
              '{0}/RV_ED_srreg.vtk '
89
              '{1}/vtks/RV_ED.vtk '
90
              '-dofout {0}/RV_sareg.dof.gz '
91
              '-symmetric'
92
              .format(motion_dir, data_dir))
93
    
94
    os.system('snreg '
95
              '{0}/RV_ED_srreg.vtk '
96
              '{1}/vtks/RV_ED.vtk '
97
              '-dofin {0}/RV_sareg.dof.gz '
98
              '-dofout {0}/RV_snreg.dof.gz '
99
              '-ds 20 -symmetric'
100
              .format(motion_dir, data_dir))
101
    
102
    os.system('mirtk transform-points '
103
              '{0}/RV_ED_srreg.vtk '
104
              '{0}/RV_fr00.vtk '
105
              '-dofin {0}/RV_snreg.dof.gz'
106
              .format(motion_dir))
107
108
    # Transform the mesh
109
    for fr in range(1, n_frame):
110
        os.system('mirtk transform-points '
111
                  '{0}/RV_fr00.vtk '
112
                  '{0}/RV_fr{1:02d}.vtk '
113
                  '-dofin {0}/ffd_00_to_{1:02d}.dof.gz'
114
                  .format(motion_dir, fr))
115
     
116
    # Convert vtks to text files
117
    for fr in range(0, n_frame):
118
        os.system('vtk2txt '
119
                  '{0}/RV_fr{1:02d}.vtk '
120
                  '{0}/RV_fr{1:02d}.txt'
121
                  .format(motion_dir, fr))
122
123
124
def apply_PC(subject, data_dir, param_dir, template_dir):
125
    
126
    print('  co-registering {0}'.format(subject))    
127
    
128
    subject_dir = os.path.join(data_dir, subject)
129
        
130
    if os.path.isdir(subject_dir):
131
        
132
        track_cine(subject_dir, param_dir, template_dir)
133
        
134
        print('  finish motion tracking in subject {0}'.format(subject))
135
        
136
    else:  
137
        print('  {0} is not a valid directory, do nothing'.format(subject_dir))
138
139
140
def motionTracking(dir_0, dir_2, dir_3, coreNo, parallel):
141
               
142
    if parallel:
143
    
144
        print('Motion tracking running on {0} cores'.format(coreNo))
145
        
146
        pool = Pool(processes = coreNo) 
147
        
148
        # partial only in Python 2.7+
149
        pool.map(partial(apply_PC, 
150
                         data_dir=dir_0,  
151
                         param_dir=dir_2, 
152
                         template_dir=dir_3), 
153
                         sorted(os.listdir(dir_0)))       
154
                
155
    else:
156
        
157
        print('Motion tracking from segmentations running subsequently')
158
                
159
        data_dir, param_dir, template_dir = dir_0, dir_2, dir_3
160
                                     
161
        for subject in sorted(os.listdir(data_dir)):
162
            
163
            subject_dir = os.path.join(data_dir, subject)
164
165
            if not os.path.isdir(subject_dir):
166
                
167
                print('  {0} is not a valid folder, Skip'.format(subject_dir))
168
                
169
                continue 
170
                   
171
            print('  motion tracking {0}'.format(subject))  
172
            
173
            track_cine(subject_dir, param_dir, template_dir)
174
            
175
            print('  finish motion tracking in {0}'.format(subject))