3 ###############################################################################
5 # FILE: create_midP-2.0.sh
6 # AUTHOR: RĂ´mulo Pinho 05/08/2011
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.
16 ###############################################################################
18 source `dirname $0`/midp_common.sh
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 $?
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 $?
32 if [ x = x$ExtractBonesLower1 ]; then
33 ExtractBonesLower1=120
35 if [ x = x$ExtractBonesLower2 ]; then
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
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
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 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
62 if [ x = x$MotionMaskOffsetDetect ]; then
63 MotionMaskOffsetDetect="0,-5,0"
65 if [ x = x$FillingLevel ]; then
69 #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
70 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
71 #--monitor=$mask_dir_tmp/monitor_$phase_nb.mhd
82 input_dir=`dirname $input`
83 input_base=`basename $input`
86 clitkMorphoMath -i $input_mask -o $input_dir/extra1_$input_base --type 1 --radius $radius
87 clitkImageArithm -i $input_dir/extra1_$input_base -j $input_mask -o $input_dir/band1_$input_base -t 7
88 clitkBinarizeImage -i $input_dir/band1_$input_base -o $input_dir/band1_$input_base -l 1 -u 1 --fg 100 --mode both
89 clitkImageConvert -i $input_dir/band1_$input_base -o $input_dir/short_band1_$input_base -t short
92 clitkMorphoMath -i $input_dir/extra1_$input_base -o $input_dir/extra2_$input_base --type 1 --radius $radius
93 clitkImageArithm -i $input_dir/extra2_$input_base -j $input_dir/extra1_$input_base -o $input_dir/band2_$input_base -t 7
94 clitkBinarizeImage -i $input_dir/band2_$input_base -o $input_dir/band2_$input_base -l 1 -u 1 --fg 200 --mode both
95 clitkImageConvert -i $input_dir/band2_$input_base -o $input_dir/short_band2_$input_base -t short
97 # combine bands with masks
98 clitkImageArithm -i $input_mask -j $input_dir/band1_$input_base -o $output_mask -t 0
99 clitkImageArithm -i $output_mask -j $input_dir/band2_$input_base -o $output_mask -t 0
100 # combine bands with image
101 combine_image $input_dir/short_band1_$input_base $input $output $input_dir/band1_$input_base
102 combine_image $input_dir/short_band2_$input_base $output $output $input_dir/band2_$input_base
105 rm `echo $input_dir/extra?_$input_base | sed 's:.mhd:.*:g'`
106 rm `echo $input_dir/band?_$input_base | sed 's:.mhd:.*:g'`
107 rm `echo $input_dir/short_band?_$input_base | sed 's:.mhd:.*:g'`
110 create_registration_masks()
112 # extract inside and outside regions from the patient image,
113 # using the motion mask computed previously
114 echo "$phase_file -> Setting Background..."
115 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
116 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
118 # the registration masks for inside (and outside) region correspond
119 # to the motion mask (and its complement) plus extra grey value bands,
120 # obtained with morphological dilations.
122 echo "$phase_file -> Creating registration masks..."
124 clitkMorphoMath -i $mask_dir_tmp/${mask_type}_$phase_nb.mhd -o $mask_dir_tmp/mask_inside_$phase_nb.mhd --type 1 --radius 8
125 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
127 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
128 #clitkExtractPatient -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd --noAutoCrop
129 clitkMorphoMath -i $mask_dir_tmp/${mask_type}_outside_$phase_nb.mhd -o $mask_dir_tmp/mask_outside_$phase_nb.mhd --type 1 --radius 8
130 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
133 create_registration_motion_masks()
135 # extract inside and outside regions from the patient image,
136 # using the motion mask computed previously
137 echo "$phase_file -> Setting Background..."
138 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
139 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
141 # the registration masks for inside (and outside) region correspond
142 # to the motion mask (and its complement) plus extra grey value bands,
143 # obtained with morphological dilations.
145 echo "$phase_file -> Creating registration masks..."
147 clitkMorphoMath -i $mask_dir_tmp/mm_$phase_nb.mhd -o $mask_dir_tmp/mask_inside_$phase_nb.mhd --type 1 --radius 8
148 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
150 clitkExtractPatient -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/mm_outside_$phase_nb.mhd --noAutoCrop
151 clitkMorphoMath -i $mask_dir_tmp/mm_outside_$phase_nb.mhd -o $mask_dir_tmp/mask_outside_$phase_nb.mhd --type 1 --radius 8
152 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
155 create_registration_lung_masks()
157 # extract inside and outside lung regions from the patient image,
158 # using the motion mask computed previously
159 echo "$phase_file -> Setting Background..."
160 clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/inside_$phase_nb.mhd --mask $mask_dir_tmp/lungs_$phase_nb.mhd --outsideValue -1200
161 clitkSetBackground -i $mask_dir_tmp/patient_$phase_nb.mhd -o $mask_dir_tmp/outside_$phase_nb.mhd --mask $mask_dir_tmp/lungs_$phase_nb.mhd --outsideValue -1200 --fg
163 # the registration masks for inside (and outside) region correspond
164 # to the motion mask (and its complement) plus extra grey value bands,
165 # obtained with morphological dilations.
167 echo "$phase_file -> Creating registration masks..."
169 clitkMorphoMath -i $mask_dir_tmp/lungs_$phase_nb.mhd -o $mask_dir_tmp/mask_inside_$phase_nb.mhd --type 1 --radius 8
170 create_banded_mask $mask_dir_tmp/inside_$phase_nb.mhd $mask_dir_tmp/lungs_$phase_nb.mhd $mask_dir_tmp/banded_inside_$phase_nb.mhd $mask_dir_tmp/banded_mask_inside_$phase_nb.mhd 4
172 clitkBinarizeImage -i $mask_dir_tmp/outside_$phase_nb.mhd -o $mask_dir_tmp/lungs_outside_$phase_nb.mhd -l -999 -u 4000 --mode both
173 clitkMorphoMath -i $mask_dir_tmp/lungs_outside_$phase_nb.mhd -o $mask_dir_tmp/mask_outside_$phase_nb.mhd --type 1 --radius 8
174 create_banded_mask $mask_dir_tmp/outside_$phase_nb.mhd $mask_dir_tmp/lungs_outside_$phase_nb.mhd $mask_dir_tmp/banded_outside_$phase_nb.mhd $mask_dir_tmp/banded_mask_outside_$phase_nb.mhd 4
183 if [ $resample_spacing -ne 0 ] ; then
193 create_registration_masks
194 # if [ "$mask_type" == "mm" ]; then
195 # create_registration_motion_masks
196 # elif [ "$mask_type" == "lungs" ]; then
197 # create_registration_lung_masks
203 # the motion masks are first created in a tmp directory. this directory is
204 # later going to be renamed to the final motion mask directory. concurrent
205 # executions trying to create the same set of masks will be blocked until
206 # the first execution finishes. naturally, these other executions will not
207 # recreate the masks. so first we try to create the tmp directory.
208 # if the creation fails, it means that another execution is
209 # already creating the masks, so this execution will be blocked. the
210 # execution is unblocked only when the creation of masks is finished and
211 # the mask directory is renamed.
214 if [ -e $mask_dir ]; then
215 # check that the final mask dir exists and that it contains all files it needs.
216 # the check assumes that the inside and outside masks are the key files to exist.
218 nb_phases=${#phase_nbs[@]}
219 if [ "$mask_type" == "patient" ]; then
220 nb_masks=`ls $mask_dir/lungs_*.mhd | wc -l`
221 if [ $nb_masks != $nb_phases ]; then
222 # if the mask dir is invalid, remove it and recreate all masks, just in case.
223 rm -fr $mask_dir 2> /dev/null
227 nb_mm_masks=`ls $mask_dir/${mask_type}_outside*.mhd | wc -l`
228 nb_in_masks=`ls $mask_dir/mask_in*.mhd | wc -l`
229 nb_out_masks=`ls $mask_dir/mask_out*.mhd | wc -l`
230 if [ $nb_mm_masks != $nb_phases -o $nb_in_masks != $nb_phases -o $nb_out_masks != $nb_phases ]; then
231 # if the mask dir is invalid, remove it and recreate all masks, just in case.
232 rm -fr $mask_dir 2> /dev/null
236 # elif [ "$mask_type" == "lungs" ]; then
237 # nb_mm_masks=`ls $mask_dir/lungs_outside*.mhd | wc -l`
238 # nb_in_masks=`ls $mask_dir/mask_in*.mhd | wc -l`
239 # nb_out_masks=`ls $mask_dir/mask_out*.mhd | wc -l`
240 # if [ $nb_mm_masks != $nb_phases -o $nb_in_masks != $nb_phases -o $nb_out_masks != $nb_phases ]; then
241 # # if the mask dir is invalid, remove it and recreate all masks, just in case.
242 # rm -fr $mask_dir 2> /dev/null
245 # elif [ "$mask_type" == "mm" ]; then
246 # nb_mm_masks=`ls $mask_dir/mm_outside*.mhd | wc -l`
247 # nb_in_masks=`ls $mask_dir/mask_in*.mhd | wc -l`
248 # nb_out_masks=`ls $mask_dir/mask_out*.mhd | wc -l`
249 # if [ $nb_mm_masks != $nb_phases -o $nb_in_masks != $nb_phases -o $nb_out_masks != $nb_phases ]; then
250 # # if the mask dir is invalid, remove it and recreate all masks, just in case.
251 # rm -fr $mask_dir 2> /dev/null
257 if [ $do_mm = 1 ]; then
258 if ! mkdir $mask_dir_tmp 2> /dev/null; then
259 if [ ! -e $mask_dir_tmp ]; then
260 # if the temp dir couldn't be created, but it doesn't exist, abort
261 abort_on_error wait_mm_creation $? clean_up_masks
263 # assumes another process is creating the maks in the temp dir.
264 # now we need to wait until the masks are complete or until the
265 # time limit is reached.
268 max_wait=3600 # one hour
269 nb_files0=`ls $mask_dir_tmp/* | wc -l`
270 while [ ! -e $mask_dir -a $sleeping -le $max_wait ]; do
271 echo "waiting creation of motion masks..."
273 sleeping=$(( $sleeping + $interval ))
274 nb_files1=`ls $mask_dir_tmp/* | wc -l`
275 if [ $nb_files1 != $nb_files0 ]; then
281 if [ $sleeping -gt $max_wait ]; then
282 abort_on_error wait_mm_creation -1 clean_up_masks
284 echo "finished waiting"
294 #set cmd line variables
295 local mhd4d=`basename $1`
297 if [ $# -eq 4 ] ; then
308 # import variables specific to each patient
309 if test -e ./variables; then
313 #set other global variables
314 if [ $resample_spacing -ne 0 ] ; then
315 mask_dir="MASK-${resample_spacing}mm-$resample_algo"
319 mask_dir_tmp="tmp.$mask_dir"
320 extract_4d_phases $mhd4d
323 echo "------------ Motion mask from create_midP_masks.sh ------------"
331 # mask_dir_tmp=$mask_dir
332 if [ $do_mm == 1 ]; then
333 mask_log_dir=$mask_dir_tmp/LOG
334 mkdir -p $mask_log_dir
336 # multi-threaded pre-processing for motion mask calcs
338 for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
339 phase_nb=${phase_nbs[$i]}
340 phase_file=${phase_files[$i]}
341 afdb_file=`echo $phase_file | sed 's/mhd/afdb/'`
343 check_threads $MAX_THREADS
345 pids=( "${pids[@]}" "$!" )
349 for ret in $ret_codes; do
350 abort_on_error mm_preprocessing $ret clean_up_masks
353 if [ "$mask_type" == "mm" ]; then
354 # single-threaded motion mask calc
355 for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
356 phase_nb=${phase_nbs[$i]}
357 phase_file=${phase_files[$i]}
360 echo "$phase_file -> Computing motion mask..."
361 compute_motion_mask > $mask_log_dir/motion_mask_$phase_file.log
362 abort_on_error compute_motion_mask $? clean_up_masks
366 # multi-threaded post-processing of motion mask calcs
367 if [ "$mask_type" != "patient" ]; then
369 for i in $( seq 0 $((${#phase_nbs[@]} - 1))); do
370 phase_nb=${phase_nbs[$i]}
371 phase_file=${phase_files[$i]}
373 check_threads $MAX_THREADS
375 pids=( "${pids[@]}" "$!" )
379 for ret in $ret_codes; do
380 abort_on_error mm_postprocessing $ret clean_up_masks
384 # rename tmp mask directory after mask creation
386 mv -f $mask_dir_tmp $mask_dir
390 echo "-------- Motion mask done ! ---------"
402 if [ $# -ne 4 -a $# -ne 2 -a $# -ne 1 ]; then
403 echo "Usage: $0 CT_4D TYPE [RESAMPLE_SPACING RESAMPLE_ALGORITHM]"
404 echo " TYPE: \"motion\" (traditional motion masks); \"lungs\" (lung masks); \"patient\" (patient mask only)"
409 # variables exported in this scope
411 # mask_dir: directory where all masks are kept
414 if [ $1 != "using-as-lib" ]; then
415 if [ $# -eq 4 ] ; then
416 motion_mask $1 $2 $3 $4
417 elif [ $# -eq 2 ] ; then