]> Creatis software - clitk.git/blob - scripts/create_midP_masks-2.0.sh
more robust motion mask script
[clitk.git] / scripts / create_midP_masks-2.0.sh
1 #! /bin/bash 
2   
3 ###############################################################################
4 #
5 # FILE: create_midP-2.0.sh
6 # AUTHOR: RĂ´mulo Pinho 05/08/2011
7 #
8 # Version 2.0 of the create_midP_masks.sh script. The most relevant changes are:
9 #   * creation of bands around input and output image regions to try to improve 
10 #   the registration along lung boundaries (naturally, it depends on the quality
11 #   of motion mask generation).
12 #   * some steps are now in different modules, to facilitate re-use (see "includes" section).
13 #   * minor modifications on output file names.
14 #   * attempt to simplify the code a bit.
15 #
16 ###############################################################################
17
18 source `dirname $0`/midp_common.sh
19
20 extract_patient()
21 {
22   echo "$phase_file -> Extracting patient..."
23   clitkExtractPatient -i $phase_file -o $mask_dir_tmp/patient_mask_$phase_nb.mhd --noAutoCrop -a $afdb_file $ExtractPatientExtra
24 #   abort_on_error clitkExtractPatient $?
25
26   clitkSetBackground -i $phase_file -o $mask_dir_tmp/patient_$phase_nb.mhd --mask $mask_dir_tmp/patient_mask_$phase_nb.mhd --outsideValue -1000
27 #   abort_on_error clitkSetBackground $?
28 }
29
30 extract_bones()
31 {
32   if [ x = x$ExtractBonesLower1 ]; then
33     ExtractBonesLower1=120
34   fi
35   if [ x = x$ExtractBonesLower2 ]; then
36     ExtractBonesLower2=80
37   fi
38   echo "$phase_file -> Extracting bones..."
39   clitkImageConvert -i $phase_file -o $mask_dir_tmp/float_$phase_nb.mhd -t float
40   clitkExtractBones -i $mask_dir_tmp/float_$phase_nb.mhd -o $mask_dir_tmp/bones_$phase_nb.mhd -a $afdb_file --lower1 $ExtractBonesLower1 --upper1 2000 --lower2 $ExtractBonesLower2 --upper2 2000 --smooth --time 0.0625 --noAutoCrop
41 }
42
43 extract_lungs()
44 {
45   echo "$phase_file -> Extracting lungs..."  
46   clitkExtractLung -i $phase_file -o $mask_dir_tmp/lungs_$phase_nb.mhd -a $afdb_file --noAutoCrop --doNotSeparateLungs --type 1
47 }
48
49
50
51 resample()
52 {
53   echo "$phase_file -> Resampling..."
54   clitkResampleImage -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/patient_$phase_nb.mhd --spacing $resample_spacing --interp $resample_algo
55   clitkResampleImage -i $mask_dir_tmp/patient_mask_$phase_nb.mhd -o $mask_dir_tmp/patient_mask_$phase_nb.mhd --spacing $resample_spacing --interp $resample_algo
56   clitkResampleImage -i $mask_dir_tmp/lungs_$phase_nb.mhd -o $mask_dir_tmp/lungs_$phase_nb.mhd --like $mask_dir_tmp/patient_$phase_nb.mhd
57 }
58
59 compute_motion_mask()
60 {
61   if [ x = x$MotionMaskOffsetDetect ]; then
62     MotionMaskOffsetDetect="0,-5,0"
63   fi
64   if [ x = x$FillingLevel ]; then
65     FillingLevel=94
66   fi
67
68   clitkMotionMask -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/mm_$phase_nb.mhd --featureLungs $mask_dir_tmp/lungs_$phase_nb.mhd --upperThresholdLungs -400 --fillingLevel $FillingLevel --offsetDetect $MotionMaskOffsetDetect --pad --writeFeature=$mask_dir_tmp/feature_$phase_nb.mhd $MotionMaskExtra 
69   #--monitor=$mask_dir_tmp/monitor_$phase_nb.mhd
70 }
71
72 create_banded_mask()
73 {
74   input=$1
75   input_mask=$2
76   output=$3
77   output_mask=$4
78   radius=$5
79
80   input_dir=`dirname $input`
81   input_base=`basename $input`
82
83   # first band
84   clitkMorphoMath -i $input_mask -o $input_dir/extra1_$input_base --type 1 --radius $radius
85   clitkImageArithm -i $input_dir/extra1_$input_base -j $input_mask -o $input_dir/band1_$input_base -t 7
86   clitkBinarizeImage -i $input_dir/band1_$input_base -o $input_dir/band1_$input_base -l 1 -u 1 --fg 100 --mode both
87   clitkImageConvert -i $input_dir/band1_$input_base -o $input_dir/short_band1_$input_base -t short
88   
89   # second band
90   clitkMorphoMath -i $input_dir/extra1_$input_base -o $input_dir/extra2_$input_base --type 1 --radius $radius
91   clitkImageArithm -i $input_dir/extra2_$input_base -j $input_dir/extra1_$input_base -o $input_dir/band2_$input_base -t 7
92   clitkBinarizeImage -i $input_dir/band2_$input_base -o $input_dir/band2_$input_base -l 1 -u 1 --fg 200 --mode both
93   clitkImageConvert -i $input_dir/band2_$input_base -o $input_dir/short_band2_$input_base -t short
94   
95   # combine bands with masks
96   clitkImageArithm -i $input_mask -j $input_dir/band1_$input_base -o $output_mask -t 0
97   clitkImageArithm -i $output_mask -j $input_dir/band2_$input_base -o $output_mask -t 0
98   # combine bands with image
99   clitkCombineImage -i $input_dir/short_band1_$input_base -j $input -m $input_dir/band1_$input_base -o $output
100   clitkCombineImage -i $input_dir/short_band2_$input_base -j $output -m $input_dir/band2_$input_base -o $output
101
102   # clean-up
103   rm `echo $input_dir/extra?_$input_base | sed 's:.mhd:.*:g'`
104   rm `echo $input_dir/band?_$input_base | sed 's:.mhd:.*:g'`
105   rm `echo $input_dir/short_band?_$input_base | sed 's:.mhd:.*:g'`
106 }
107
108 create_registration_masks()
109 {
110   # extract inside and outside lung regions from the patient image, 
111   # using the motion mask computed previously
112   echo "$phase_file -> Setting Background..."
113   clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/inside_$phase_nb.mhd --mask $mask_dir_tmp/mm_$phase_nb.mhd --outsideValue -1200
114   clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/outside_$phase_nb.mhd --mask $mask_dir_tmp/mm_$phase_nb.mhd --outsideValue -1200 --fg
115
116   # the registration masks for inside (and outside) region correspond
117   # to the motion mask (and its complement) plus extra grey value bands,
118   # obtained with morphological dilations.
119   # 
120   echo "$phase_file -> Creating registration masks..."
121   # inside
122   clitkMorphoMath -i $mask_dir_tmp/mm_$phase_nb.mhd -o $mask_dir_tmp/mask_inside_$phase_nb.mhd --type 1 --radius 8
123   create_banded_mask $mask_dir_tmp/inside_$phase_nb.mhd $mask_dir_tmp/mm_$phase_nb.mhd $mask_dir_tmp/banded_inside_$phase_nb.mhd $mask_dir_tmp/banded_mask_inside_$phase_nb.mhd 4
124   # outside 
125   clitkExtractPatient -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/mm_outside_$phase_nb.mhd --noAutoCrop
126   clitkMorphoMath -i $mask_dir_tmp/mm_outside_$phase_nb.mhd -o $mask_dir_tmp/mask_outside_$phase_nb.mhd --type 1 --radius 8
127   create_banded_mask $mask_dir_tmp/outside_$phase_nb.mhd $mask_dir_tmp/mm_outside_$phase_nb.mhd $mask_dir_tmp/banded_outside_$phase_nb.mhd $mask_dir_tmp/banded_mask_outside_$phase_nb.mhd 4
128 }
129
130 mm_preprocessing()
131 {
132   extract_patient
133   # extract_bones
134   extract_lungs
135   # remove_tmp_masks 1
136   if [ $resample_spacing -ne 0 ] ; then 
137     resample
138   fi
139 }
140
141 mm_postprocessing()
142 {
143   # remove_tmp_masks 2
144   # remove_tmp_masks 3
145   create_registration_masks
146 }
147
148 wait_mm_creation()
149 {
150   # the motion masks are first created in a tmp directory. this directory is 
151   # later going to be renamed to the final motion mask directory. concurrent
152   # executions trying to create the same set of masks will be blocked until
153   # the first execution finishes. naturally, these other executions will not
154   # recreate the masks. so first we try to create the tmp directory. 
155   # if the creation fails, it means that another execution is
156   # already creating the masks, so this execution will be blocked. the
157   # execution is unblocked only when the creation of masks is finished and
158   # the mask directory is renamed.
159   #
160   do_mm=1
161   if [ -e $mask_dir ]; then
162     # check that the final mask dir exists and that it contains all files it needs.
163     # the check assumes that the inside and outside masks are the key files to exist.
164     do_mm=0
165     nb_phases=${#phase_nbs[@]}
166     nb_in_masks=`ls $mask_dir/mask_in*.mhd | wc -l`
167     nb_out_masks=`ls $mask_dir/mask_out*.mhd | wc -l`
168     if [ $nb_in_masks != $nb_phases -o $nb_out_masks != $nb_phases ]; then
169       # if the mask dir is invalid, remove it and recreate all masks, just in case.
170       rm -fr $mask_dir 2> /dev/null
171       do_mm=1
172     fi
173   fi
174   
175   if [ $do_mm = 1 ]; then
176     if ! mkdir $mask_dir_tmp 2> /dev/null; then
177       if [ ! -e $mask_dir_tmp ]; then
178         # if the temp dir couldn't be created, but it doesn't exist, abort
179         abort_on_error wait_mm_creation $? clean_up_masks
180       else
181         # assumes another process is creating the maks in the temp dir.
182         # now we need to wait until the masks are complete or until the
183         # time limit is reached. 
184         interval=10
185         sleeping=0
186         max_wait=3600 # one hour
187         nb_files0=`ls $mask_dir_tmp/* | wc -l`
188         while [ ! -e $mask_dir -a $sleeping -le $max_wait ]; do
189           echo "waiting creation of motion masks..."
190           sleep $interval
191           sleeping=$(( $sleeping + $interval ))
192           nb_files1=`ls $mask_dir_tmp/* | wc -l`
193           if [ $nb_files1 != $nb_files0 ]; then
194             nb_files0=$nb_files1
195             sleeping=0
196           fi  
197         done
198
199         if [ $sleeping -gt $max_wait ]; then
200           abort_on_error wait_mm_creation -1 clean_up_masks
201         else
202           echo "finished waiting"
203           do_mm=0
204         fi
205       fi
206     fi  
207   fi
208 }
209
210 motion_mask()
211 {
212   #set cmd line variables
213   mhd4d=`basename $1`
214   if [ $# -eq 3 ] ; then
215     resample_spacing=$2
216     resample_algo=$3
217   else
218     resample_spacing=0
219     resample_algo=0
220   fi
221
222   dir=`dirname $1`
223   cd $dir
224     
225   # import variables specific to each patient
226   if test -e ./variables; then
227     source ./variables
228   fi
229
230   #set other global variables
231   if [ $resample_spacing -ne 0 ] ; then
232     mask_dir="MASK-${resample_spacing}mm-$resample_algo"
233   else
234     mask_dir="MASK"
235   fi
236   mask_dir_tmp="tmp.$mask_dir"
237   extract_4d_phases $mhd4d
238
239   echo
240   echo "------------ Motion mask from create_midP_masks.sh ------------"
241   start=`date`
242   echo "start: $start"
243   echo
244
245   wait_mm_creation
246
247 #   do_mm=1
248 #   mask_dir_tmp=$mask_dir
249   if [ $do_mm == 1 ]; then
250     mask_log_dir=$mask_dir_tmp/LOG
251     mkdir -p $mask_log_dir
252
253     # multi-threaded pre-processing for motion mask calcs
254     pids=( )
255     for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
256       phase_nb=${phase_nbs[$i]}
257       phase_file=${phase_files[$i]}
258       afdb_file=`echo $phase_file | sed 's/mhd/afdb/'`
259
260       check_threads $MAX_THREADS
261       mm_preprocessing &
262       pids=( "${pids[@]}" "$!" )
263     done
264
265     wait_pids ${pids[@]}
266     for ret in $ret_codes; do
267       abort_on_error mm_preprocessing $ret clean_up_masks
268     done
269
270     # single-threaded motion mask calc
271     for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
272       phase_nb=${phase_nbs[$i]}
273       phase_file=${phase_files[$i]}
274
275       check_threads 1
276       echo "$phase_file -> Computing motion mask..."
277       compute_motion_mask > $mask_log_dir/motion_mask_$phase_file.log
278       abort_on_error compute_motion_mask $? clean_up_masks
279     done
280
281     # multi-threaded post-processing of motion mask calcs
282     pids=( )
283     for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
284       phase_nb=${phase_nbs[$i]}
285       phase_file=${phase_files[$i]}
286
287       check_threads $MAX_THREADS 
288       mm_postprocessing &
289       pids=( "${pids[@]}" "$!" )
290     done
291   
292     wait_pids ${pids[@]}
293     for ret in $ret_codes; do
294       abort_on_error mm_postprocessing $ret clean_up_masks
295     done
296
297
298     # rename tmp mask directory after mask creation
299     check_threads 1
300     mv -f $mask_dir_tmp $mask_dir
301   fi
302
303   echo
304   echo "-------- Motion mask done ! ---------"
305   end=`date`
306   echo "start: $start"
307   echo "end: $end"
308   echo
309 }
310
311
312 #################
313 # main  #
314 #################
315
316 if [ $# -ne 3 -a $# -ne 1 ]; then
317   echo "Usage: $0 CT_4D [RESAMPLE_SPACING RESAMPLE_ALGORITHM]"
318   exit -1
319 fi
320
321 #
322 # variables exported in this scope
323 #
324 # mask_dir: directory where all masks are kept
325 #
326
327 if [ $1 != "using-as-lib" ]; then
328   if [ $# -eq 3 ] ; then
329     motion_mask $1 $2 $3
330   else
331     motion_mask $1
332   fi
333 fi