123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- #! /usr/bin/env perl
- #
- # linear fitting using parameters optimised by Claude Lepage,
- # using a brain mask for the source and the target. This was
- # greatly inspired by best1stepnlreg.pl by Steve Robbins.
- #
- # Claude Lepage - claude@bic.mni.mcgill.ca
- # Andrew Janke - rotor@cmr.uq.edu.au
- # Center for Magnetic Resonance
- # The University of Queensland
- # http://www.cmr.uq.edu.au/~rotor
- #
- # Copyright Andrew Janke, The University of Queensland.
- # Permission to use, copy, modify, and distribute this software and its
- # documentation for any purpose and without fee is hereby granted,
- # provided that the above copyright notice appear in all copies. The
- # author and the University of Queensland make no representations about the
- # suitability of this software for any purpose. It is provided "as is"
- # without express or implied warranty.
- use strict;
- use warnings "all";
- use Getopt::Tabular;
- use File::Basename;
- use File::Temp qw/ tempdir /;
- my @conf = (
- { type => "blur",
- trans => [qw/-est_translations/],
- blur_fwhm => 16,
- steps => [qw/8 8 8/],
- tolerance => 0.01,
- simplex => 32 },
- { type => "blur",
- trans => undef,
- blur_fwhm => 8,
- steps => [qw/4 4 4/],
- tolerance => 0.004,
- simplex => 16 },
- { type => "blur",
- trans => undef,
- blur_fwhm => 4,
- steps => [qw/4 4 4/],
- tolerance => 0.004,
- simplex => 8 },
- { type => "dxyz",
- trans => undef,
- blur_fwhm => 8,
- steps => [qw/4 4 4/],
- tolerance => 0.004,
- simplex => 4 },
- { type => "dxyz",
- trans => undef,
- blur_fwhm => 4,
- steps => [qw/4 4 4/],
- tolerance => 0.004,
- simplex => 2 }
-
- );
- my($Help, $Usage, $me);
- my(@opt_table, %opt, $source, $target, $outxfm, $outfile, @args, $tmpdir);
- $me = &basename($0);
- %opt = (
- 'verbose' => 1,
- 'clobber' => 0,
- 'fake' => 0,
- 'init_xfm' => undef,
- 'source_mask' => undef,
- 'target_mask' => undef,
- 'lsqtype' => "-lsq9",
- 'work_dir' => undef,
- 'sec_source' => undef,
- 'sec_target' => undef,
- 'cost_function' => '-xcorr',
- 'noshear' => 0,
- 'noscale' => 0,
- 'norot' => 0,
- 'noshift' => 0,
- 'close' => 0,
- );
- $Help = <<HELP;
- | $me does hierachial linear fitting between two files.
- | you will have to edit the script itself to modify the
- | fitting levels themselves
- |
- | Problems or comments should be sent to: claude\@bic.mni.mcgill.ca
- HELP
- $Usage = "Usage: $me [options] source.mnc target.mnc output.xfm [output.mnc]\n".
- " $me -help to list options\n\n";
- @opt_table = (
- ["-verbose", "boolean", 0, \$opt{verbose},
- "be verbose" ],
- ["-clobber", "boolean", 0, \$opt{clobber},
- "clobber existing check files" ],
- ["-fake", "boolean", 0, \$opt{fake},
- "do a dry run, (echo cmds only)" ],
- ["-init_xfm", "string", 1, \$opt{init_xfm},
- "initial transformation (default identity)" ],
- ["-source_mask", "string", 1, \$opt{source_mask},
- "source mask to use during fitting" ],
- ["-target_mask", "string", 1, \$opt{target_mask},
- "target mask to use during fitting" ],
- ["-lsq9", "const", "-lsq9", \$opt{lsqtype},
- "use 9-parameter transformation (default)" ],
- ["-lsq12", "const", "-lsq12", \$opt{lsqtype},
- "use 12-parameter transformation (default -lsq9)" ],
- ["-lsq6", "const", "-lsq6", \$opt{lsqtype},
- "use 6-parameter transformation" ],
- ["-lsq7", "const", "-lsq7", \$opt{lsqtype},
- "use 7-parameter transformation" ],
- ["-quaternions","const",'-quaternions', \$opt{lsqtype},
- "use quaternion transformation" ],
- ["-mi","const",'-mi', \$opt{cost_function},
- "Mutual information cost function" ],
- ["-xcorr","const",'-xcorr', \$opt{cost_function},
- "Cross-correlation cost function" ],
- ["-work_dir", "string", 1, \$opt{work_dir},
- "Directory to keep blurred files" ],
- ["-sec_source", "string", 1, \$opt{sec_source},
- "secondaty source" ],
- ["-sec_target", "string", 1, \$opt{sec_target},
- "secondary target" ],
- ["-noshear", "boolean", 1, \$opt{noshear},
- "lsq12 w/o shear" ],
- ["-noscale", "boolean", 1, \$opt{noscale},
- "lsq12 w/o scale" ],
- ["-norot", "boolean", 1, \$opt{norot},
- "lsq12 w/o rotations" ],
- ["-noshift", "boolean", 1, \$opt{noshift},
- "lsq12 w/o shifts" ],
- ["-close", "boolean", 1, \$opt{close},
- "Samples are close" ],
- );
- delete $ENV{MINC_COMPRESS} if $ENV{MINC_COMPRESS};
- # Check arguments
- &Getopt::Tabular::SetHelp($Help, $Usage);
- &GetOptions (\@opt_table, \@ARGV) || exit 1;
- die $Usage if(! ($#ARGV == 2 || $#ARGV == 3));
- $source = shift(@ARGV);
- $target = shift(@ARGV);
- $outxfm = shift(@ARGV);
- $outfile = (defined($ARGV[0])) ? shift(@ARGV) : undef;
- # check for files
- die "$me: Couldn't find input file: $source\n\n" if (!-e $source);
- die "$me: Couldn't find input file: $target\n\n" if (!-e $target);
- if(-e $outxfm && !$opt{clobber}){
- die "$me: $outxfm exists, -clobber to overwrite\n\n";
- }
- if(defined($outfile) && -e $outfile && !$opt{clobber}){
- die "$me: $outfile exists, -clobber to overwrite\n\n";
- }
- # make tmpdir
- $tmpdir = &tempdir( "$me-XXXXXXXX", TMPDIR => 1, CLEANUP => 1 );
- $opt{work_dir}=$tmpdir unless $opt{work_dir};
- # set up filename base
- my($i, $s_base, $t_base, $tmp_xfm, $tmp_source, $tmp_target, $prev_xfm,
- $tmp_sec_source, $tmp_sec_target);
- $s_base = &basename($source);
- $s_base =~ s/\.mnc(.gz)?$//;
- $s_base = 's_'.$s_base;
- $t_base = &basename($target);
- $t_base =~ s/\.mnc(.gz)?$//;
- $t_base = 't_'.$t_base;
- # Mask the source and target once before blurring. Both masks must exist.
- my $source_masked = $source;
- my $target_masked = $target;
- # initial transformation supplied by the user, applied to both the
- # source image and its mask.
- #if( defined $opt{init_xfm} ) {
- # my $source_resampled = "${tmpdir}/${s_base}_resampled.mnc";
- # &do_cmd( 'mincresample',
- # '-clobber',
- # '-like', $target_masked,
- # '-transform', $opt{init_xfm},
- # $source_masked, $source_resampled );
- # $source_masked = $source_resampled;
- # #apply it to the mask, if it's defined
- # if(defined($opt{source_mask}))
- # {
- # my $mask_resampled = "${tmpdir}/${s_base}_mask_resampled.mnc";
- # &do_cmd( 'mincresample', '-clobber', '-like', $target_masked,
- # '-nearest_neighbour', '-transform', $opt{init_xfm},
- # $opt{source_mask}, $mask_resampled );
- # $opt{source_mask} = $mask_resampled;
- # }
- #}
- $prev_xfm = undef;
- # a fitting we shall go...
- for ($i=0; $i<=$#conf; $i++){
-
- # set up intermediate files
- $tmp_xfm = "$tmpdir/$s_base\_$i.xfm";
- $tmp_source = "$opt{work_dir}/$s_base\_$conf[$i]{blur_fwhm}";
- $tmp_target = "$opt{work_dir}/$t_base\_$conf[$i]{blur_fwhm}";
- $tmp_source = "$opt{work_dir}/$s_base\_$conf[$i]{blur_fwhm}";
- $tmp_target = "$opt{work_dir}/$t_base\_$conf[$i]{blur_fwhm}";
-
- if($opt{close})
- {
- next if($conf[$i]{blur_fwhm}>8);
- $conf[$i]{simplex}=1;
- $conf[$i]{steps}=[qw/2 2 2/];
- }
- print STDOUT "-+-------------------------[$i]-------------------------\n".
- " | steps: @{$conf[$i]{steps}}\n".
- " | blur_fwhm: $conf[$i]{blur_fwhm}\n".
- " | simplex: $conf[$i]{simplex}\n".
- " | source: $tmp_source\_$conf[$i]{type}.mnc\n".
- " | target: $tmp_target\_$conf[$i]{type}.mnc\n".
- " | xfm: $tmp_xfm\n".
- "-+-----------------------------------------------------\n".
- "\n";
-
- # blur the masked source and target images
- my @grad_opt = ();
- push( @grad_opt, '-gradient' ) if( $conf[$i]{type} eq "dxyz" );
-
- if($conf[$i]{blur_fwhm}>0) # actually this should be 1
- {
- if(!-e "$tmp_source\_$conf[$i]{type}.mnc") {
- &do_cmd('mincblur', '-clobber', '-no_apodize', '-fwhm', $conf[$i]{blur_fwhm},
- @grad_opt, $source_masked, $tmp_source);
- }
- if(!-e "$tmp_target\_$conf[$i]{type}.mnc") {
- &do_cmd('mincblur', '-clobber', '-no_apodize', '-fwhm', $conf[$i]{blur_fwhm},
- @grad_opt, $target_masked, $tmp_target);
- }
- if(defined($opt{sec_source}) && defined($opt{sec_target}) )
- {
- $tmp_sec_source = "$opt{work_dir}/sec_$s_base\_$conf[$i]{blur_fwhm}";
- $tmp_sec_target = "$opt{work_dir}/sec_$t_base\_$conf[$i]{blur_fwhm}";
- if(! -e "$tmp_sec_source\_$conf[$i]{type}.mnc")
- {
- &do_cmd('mincblur', '-clobber', '-no_apodize', '-fwhm',
- $conf[$i]{blur_fwhm},
- @grad_opt, $opt{sec_source}, $tmp_sec_source);
- }
- if(! -e "$tmp_sec_target\_$conf[$i]{type}.mnc")
- {
- &do_cmd('mincblur', '-clobber', '-no_apodize', '-fwhm',
- $conf[$i]{blur_fwhm},
- @grad_opt, $opt{sec_target}, $tmp_sec_target);
- }
- $tmp_sec_source="$tmp_sec_source\_$conf[$i]{type}.mnc";
- $tmp_sec_target="$tmp_sec_target\_$conf[$i]{type}.mnc";
- }
- } else { # noop
- if(!-e "$tmp_source\_$conf[$i]{type}.mnc") {
- do_cmd('ln','-s',$source_masked,"$tmp_source\_$conf[$i]{type}.mnc");
- }
- if(!-e "$tmp_target\_$conf[$i]{type}.mnc") {
- &do_cmd('ln', '-s', $target_masked, "$tmp_target\_$conf[$i]{type}.mnc");
- }
- if(defined($opt{sec_source}) && defined($opt{sec_target}) )
- {
- $tmp_sec_source =$opt{sec_source};
- $tmp_sec_target =$opt{sec_target};
- }
- }
- # set up registration
- @args = ('minctracc', '-clobber', $opt{lsqtype},
- '-step', @{$conf[$i]{steps}}, '-simplex', $conf[$i]{simplex},
- '-tol', $conf[$i]{tolerance});
- # Initial transformation will be computed from the from Principal axis
- # transformation (PAT).
- push(@args, @{$conf[$i]{trans}}) if( defined $conf[$i]{trans} && !$opt{init_xfm} );
- # Current transformation at this step
- if( defined $prev_xfm )
- {
- push(@args, '-transformation', $prev_xfm ) ;
- } elsif( defined $opt{init_xfm} ) {
- push(@args, '-transformation', $opt{init_xfm} ) ;
- #push(@args, '-est_center' ) ;
-
- } elsif($opt{close}) {
- push(@args, '-identity') ;
- }
- # masks (even if the blurred image is masked, it's still preferable
- # to use the mask in minctracc)
- push(@args, '-source_mask', $opt{source_mask} ) if defined($opt{source_mask});
- push(@args, '-model_mask', $opt{target_mask}) if defined($opt{target_mask});
- if($tmp_sec_source && $tmp_sec_target )
- {
- push(@args, $opt{cost_function},
- "$tmp_source\_$conf[$i]{type}.mnc",
- "$tmp_target\_$conf[$i]{type}.mnc");
- push(@args, '-feature_vol',$tmp_sec_source,$tmp_sec_target,'xcorr',1.0);
- } else {
- push(@args, $opt{cost_function},"$tmp_source\_$conf[$i]{type}.mnc",
- "$tmp_target\_$conf[$i]{type}.mnc");
- }
- push @args,'-w_shear',0,0,0 if $opt{noshear};
- push @args,'-w_scales',0,0,0 if $opt{noscale};
- push @args,'-w_translations',0,0,0 if $opt{noshift};
- push @args,'-w_rotations',0,0,0 if $opt{norot};
-
- # add files and run registration
- push(@args, $tmp_xfm);
- &do_cmd(@args);
-
- $prev_xfm = $tmp_xfm;
- }
- # Concatenate transformations if an initial transformation was given.
- #if( defined $opt{init_xfm} ) {
- # &do_cmd( 'xfmconcat', $prev_xfm, $opt{init_xfm}, $outxfm );
- #} else {
- do_cmd( 'mv', '-f', $prev_xfm, $outxfm );
- #}
- # resample if required
- if(defined($outfile)){
- print STDOUT "-+- creating $outfile using $outxfm\n".
- &do_cmd( 'mincresample', '-clobber', '-like', $target,
- '-transformation', $outxfm, $source, $outfile );
- }
- sub do_cmd {
- print STDOUT "@_\n" if $opt{verbose};
- if(!$opt{fake}){
- system(@_) == 0 or die;
- }
- }
-
|