]> Creatis software - clitk.git/blob - scripts/create_midP_masks-2.0.sh
using get_dicom_field_value in midp scripts
[clitk.git] / scripts / create_midP_masks-2.0.sh
1 #! /bin/bash -x
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   if [ "$mask_type" != "patient" ]; then
57     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
58   fi
59   if [ "$mask_type" == "mm" ]; then
60     clitkResampleImage -i $mask_dir_tmp/bones_$phase_nb.mhd -o $mask_dir_tmp/bones_$phase_nb.mhd --like $mask_dir_tmp/patient_$phase_nb.mhd
61   fi
62 }
63
64 compute_motion_mask()
65 {
66   if [ x = x$MotionMaskOffsetDetect ]; then
67     MotionMaskOffsetDetect="0,-5,0"
68   fi
69   if [ x = x$FillingLevel ]; then
70     FillingLevel=94
71   fi
72
73   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 --featureBones $mask_dir_tmp/bones_$phase_nb.mhd --fillingLevel $FillingLevel --offsetDetect $MotionMaskOffsetDetect --pad --writeFeature $mask_dir_tmp/feature_$phase_nb.mhd $MotionMaskExtra  
74   #--monitor=$mask_dir_tmp/monitor_$phase_nb.mhd
75 }
76
77 create_banded_mask()
78 {
79   input=$1
80   input_mask=$2
81   output=$3
82   output_mask=$4
83   radius=$5
84
85   input_dir=`dirname $input`
86   input_base=`basename $input`
87
88   # first band
89   clitkMorphoMath -i $input_mask -o $input_dir/extra1_$input_base --type 1 --radius $radius
90   clitkImageArithm -i $input_dir/extra1_$input_base -j $input_mask -o $input_dir/band1_$input_base -t 7
91   clitkBinarizeImage -i $input_dir/band1_$input_base -o $input_dir/band1_$input_base -l 1 -u 1 --fg 100 --mode both
92   clitkImageConvert -i $input_dir/band1_$input_base -o $input_dir/short_band1_$input_base -t short
93   
94   # second band
95   clitkMorphoMath -i $input_dir/extra1_$input_base -o $input_dir/extra2_$input_base --type 1 --radius $radius
96   clitkImageArithm -i $input_dir/extra2_$input_base -j $input_dir/extra1_$input_base -o $input_dir/band2_$input_base -t 7
97   clitkBinarizeImage -i $input_dir/band2_$input_base -o $input_dir/band2_$input_base -l 1 -u 1 --fg 200 --mode both
98   clitkImageConvert -i $input_dir/band2_$input_base -o $input_dir/short_band2_$input_base -t short
99   
100   # combine bands with masks
101   clitkImageArithm -i $input_mask -j $input_dir/band1_$input_base -o $output_mask -t 0
102   clitkImageArithm -i $output_mask -j $input_dir/band2_$input_base -o $output_mask -t 0
103   # combine bands with image
104   combine_image $input_dir/short_band1_$input_base $input $output $input_dir/band1_$input_base
105   combine_image $input_dir/short_band2_$input_base $output $output $input_dir/band2_$input_base
106
107   # clean-up
108   rm `echo $input_dir/extra?_$input_base | sed 's:.mhd:.*:g'`
109   rm `echo $input_dir/band?_$input_base | sed 's:.mhd:.*:g'`
110   rm `echo $input_dir/short_band?_$input_base | sed 's:.mhd:.*:g'`
111 }
112
113 create_registration_masks()
114 {
115   # extract inside and outside regions from the patient image, 
116   # using the motion mask computed previously
117   echo "$phase_file -> Setting Background..."
118   clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/inside_$phase_nb.mhd --mask $mask_dir_tmp/${mask_type}_$phase_nb.mhd --outsideValue -1200
119   clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/outside_$phase_nb.mhd --mask $mask_dir_tmp/${mask_type}_$phase_nb.mhd --outsideValue -1200 --fg
120
121   # the registration masks for inside (and outside) region correspond
122   # to the motion mask (and its complement) plus extra grey value bands,
123   # obtained with morphological dilations.
124   # 
125   echo "$phase_file -> Creating registration masks..."
126   # inside
127   clitkMorphoMath -i $mask_dir_tmp/${mask_type}_$phase_nb.mhd -o $mask_dir_tmp/mask_inside_$phase_nb.mhd --type 1 --radius 8
128   create_banded_mask $mask_dir_tmp/inside_$phase_nb.mhd $mask_dir_tmp/${mask_type}_$phase_nb.mhd $mask_dir_tmp/banded_inside_$phase_nb.mhd $mask_dir_tmp/banded_mask_inside_$phase_nb.mhd 4
129   # outside 
130   clitkBinarizeImage -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd -l -999 -u 4000 --mode both 
131   #clitkExtractPatient -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd --noAutoCrop
132   clitkMorphoMath -i $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd -o $mask_dir_tmp/mask_outside_$phase_nb.mhd --type 1 --radius 8
133   create_banded_mask $mask_dir_tmp/outside_$phase_nb.mhd $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd $mask_dir_tmp/banded_outside_$phase_nb.mhd $mask_dir_tmp/banded_mask_outside_$phase_nb.mhd 4
134 }
135
136 mm_preprocessing()
137 {
138   extract_patient
139
140   if [ "$mask_type" != "patient" ]; then
141     extract_lungs
142   fi
143
144   if [ "$mask_type" == "mm" ]; then
145     extract_bones
146   fi
147
148   # remove_tmp_masks 1
149   if [ $resample_spacing -ne 0 ] ; then 
150     resample
151   fi
152 }
153
154 mm_postprocessing()
155 {
156   # remove_tmp_masks 2
157   # remove_tmp_masks 3
158
159   create_registration_masks
160 #   if [ "$mask_type" == "mm" ]; then
161 #     create_registration_motion_masks
162 #   elif [ "$mask_type" == "lungs" ]; then
163 #     create_registration_lung_masks
164 #   fi
165 }
166
167 wait_mm_creation()
168 {
169   # the motion masks are first created in a tmp directory. this directory is 
170   # later going to be renamed to the final motion mask directory. concurrent
171   # executions trying to create the same set of masks will be blocked until
172   # the first execution finishes. naturally, these other executions will not
173   # recreate the masks. so first we try to create the tmp directory. 
174   # if the creation fails, it means that another execution is
175   # already creating the masks, so this execution will be blocked. the
176   # execution is unblocked only when the creation of masks is finished and
177   # the mask directory is renamed.
178   #
179   do_mm=1
180   if [ -e $mask_dir ]; then
181     # check that the final mask dir exists and that it contains all files it needs.
182     # the check assumes that the inside and outside masks are the key files to exist.
183     do_mm=0
184     nb_phases=${#phase_nbs[@]}
185     if [ "$mask_type" == "patient" ]; then
186       nb_masks=`ls $mask_dir/lungs_*.mhd | wc -l`
187       if [ $nb_masks != $nb_phases ]; then
188         # if the mask dir is invalid, remove it and recreate all masks, just in case.
189         rm -fr $mask_dir 2> /dev/null
190         do_mm=1
191       fi
192     else
193       nb_mm_masks=`ls $mask_dir/${mask_type}_outside*.mhd | wc -l`
194       nb_in_masks=`ls $mask_dir/mask_in*.mhd | wc -l`
195       nb_out_masks=`ls $mask_dir/mask_out*.mhd | wc -l`
196       if [ $nb_mm_masks != $nb_phases -o $nb_in_masks != $nb_phases -o $nb_out_masks != $nb_phases ]; then
197         # if the mask dir is invalid, remove it and recreate all masks, just in case.
198         rm -fr $mask_dir 2> /dev/null
199         do_mm=1
200       fi
201     fi
202   fi
203   
204   if [ $do_mm = 1 ]; then
205     if ! mkdir $mask_dir_tmp 2> /dev/null; then
206       if [ ! -e $mask_dir_tmp ]; then
207         # if the temp dir couldn't be created, but it doesn't exist, abort
208         abort_on_error wait_mm_creation $? clean_up_masks
209       else
210         # assumes another process is creating the maks in the temp dir.
211         # now we need to wait until the masks are complete or until the
212         # time limit is reached. 
213         interval=10
214         sleeping=0
215         max_wait=3600 # one hour
216         nb_files0=`ls $mask_dir_tmp/* | wc -l`
217         while [ ! -e $mask_dir -a $sleeping -le $max_wait ]; do
218           echo "waiting creation of motion masks..."
219           sleep $interval
220           sleeping=$(( $sleeping + $interval ))
221           nb_files1=`ls $mask_dir_tmp/* | wc -l`
222           if [ $nb_files1 != $nb_files0 ]; then
223             nb_files0=$nb_files1
224             sleeping=0
225           fi  
226         done
227
228         if [ $sleeping -gt $max_wait ]; then
229           abort_on_error wait_mm_creation -1 clean_up_masks
230         else
231           echo "finished waiting"
232           do_mm=0
233         fi
234       fi
235     fi  
236   fi
237 }
238
239 motion_mask()
240 {
241   #set cmd line variables
242   local mhd4d=`basename $1`
243   mask_type=$2
244   if [ $# -eq 4 ] ; then
245     resample_spacing=$3
246     resample_algo=$4
247   else
248     resample_spacing=0
249     resample_algo=0
250   fi
251
252   dir=`dirname $1`
253   cd $dir
254     
255   # import variables specific to each patient
256   if test -e ./variables; then
257     source ./variables
258   fi
259
260   #set other global variables
261   if [ $resample_spacing -ne 0 ] ; then
262     mask_dir="MASK-${resample_spacing}mm-$resample_algo"
263   else
264     mask_dir="MASK"
265   fi
266   mask_dir_tmp="tmp.$mask_dir"
267   extract_4d_phases $mhd4d
268
269   echo
270   echo "------------ Motion mask from create_midP_masks.sh ------------"
271   start=`date`
272   echo "start: $start"
273   echo
274
275   wait_mm_creation
276
277 #   do_mm=1
278 #   mask_dir_tmp=$mask_dir
279   if [ $do_mm == 1 ]; then
280     mask_log_dir=$mask_dir_tmp/LOG
281     mkdir -p $mask_log_dir
282
283     # multi-threaded pre-processing for motion mask calcs
284     pids=( )
285     for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
286       phase_nb=${phase_nbs[$i]}
287       phase_file=${phase_files[$i]}
288       afdb_file=`echo $phase_file | sed 's/mhd/afdb/'`
289
290       check_threads $MAX_THREADS
291       mm_preprocessing &
292       pids=( "${pids[@]}" "$!" )
293     done
294
295     wait_pids ${pids[@]}
296     for ret in $ret_codes; do
297       abort_on_error mm_preprocessing $ret clean_up_masks
298     done
299
300     if [ "$mask_type" == "mm" ]; then
301       # single-threaded motion mask calc
302       for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
303         phase_nb=${phase_nbs[$i]}
304         phase_file=${phase_files[$i]}
305
306         check_threads 1
307         echo "$phase_file -> Computing motion mask..."
308         compute_motion_mask > $mask_log_dir/motion_mask_$phase_file.log
309         abort_on_error compute_motion_mask $? clean_up_masks
310       done
311     fi
312
313     # multi-threaded post-processing of motion mask calcs
314     if [ "$mask_type" != "patient" ]; then
315       pids=( )
316       for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
317         phase_nb=${phase_nbs[$i]}
318         phase_file=${phase_files[$i]}
319
320         check_threads $MAX_THREADS 
321         mm_postprocessing &
322         pids=( "${pids[@]}" "$!" )
323       done
324     
325       wait_pids ${pids[@]}
326       for ret in $ret_codes; do
327         abort_on_error mm_postprocessing $ret clean_up_masks
328       done
329     fi
330
331     # rename tmp mask directory after mask creation
332     check_threads 1
333     mv -f $mask_dir_tmp $mask_dir
334   fi
335
336   echo
337   echo "-------- Motion mask done ! ---------"
338   end=`date`
339   echo "start: $start"
340   echo "end: $end"
341   echo
342 }
343
344
345 #################
346 # main  #
347 #################
348
349 if [ $# -ne 4 -a $# -ne 2 -a $# -ne 1 ]; then
350   echo "Usage: $0 CT_4D TYPE [RESAMPLE_SPACING RESAMPLE_ALGORITHM]"
351   echo "  TYPE: \"mm\" (traditional motion masks); \"lungs\" (lung masks); \"patient\" (patient mask only)"
352   exit -1
353 fi
354
355 #
356 # variables exported in this scope
357 #
358 # mask_dir: directory where all masks are kept
359 #
360
361 if [ $1 != "using-as-lib" ]; then
362   if [ $# -eq 4 ] ; then
363     motion_mask $1 $2 $3 $4
364   elif [ $# -eq 2 ] ; then
365     motion_mask $1 $2
366   else
367     motion_mask $1 all
368   fi
369 fi