Mercurial > hg > minc-tools
changeset 2635:148cf7a20ca4
merged with Andrew
author | Vladimir S. FONOV <vladimir.fonov@gmail.com> |
---|---|
date | Mon, 12 Mar 2012 18:16:14 -0400 |
parents | 69d086569d83 (current diff) 589a953e208d (diff) |
children | b0e5228b9c74 |
files | CMakeLists.txt progs/CMakeLists.txt progs/mincpik/mincpik progs/mincpik/mincpik.man1 |
diffstat | 7 files changed, 678 insertions(+), 645 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ SET(CPACK_GENERATOR TGZ) SET(CPACK_PACKAGE_VERSION_MAJOR 2) SET(CPACK_PACKAGE_VERSION_MINOR 1) -SET(CPACK_PACKAGE_VERSION_PATCH 1) +SET(CPACK_PACKAGE_VERSION_PATCH 10) INCLUDE(CPack)
--- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,8 @@ $(POD2MAN) --section=1 $< > $@ progs/minchistory/minchistory.man1: progs/minchistory/minchistory $(POD2MAN) --section=1 $< > $@ +progs/mincpik/mincpik.man1: progs/mincpik/mincpik + $(POD2MAN) --section=1 $< > $@ # Add these to the include searches. # @@ -172,13 +174,13 @@ progs/mincdiff/mincdiff \ progs/mincedit/mincedit \ progs/mincheader/mincheader \ - progs/mincpik/mincpik \ progs/mincview/mincview # Scripts that we process (to add version #s) before install bin_SCRIPTS = \ progs/minccomplete/minccomplete \ progs/minchistory/minchistory \ + progs/mincpik/mincpik \ progs/xfm/xfmflip # Programs we build and install. @@ -243,6 +245,7 @@ $(m4_files) \ progs/minccomplete/minccomplete.in \ progs/minchistory/minchistory.in \ + progs/mincpik/mincpik.in \ progs/xfm/xfmflip.in \ libsrc/strdup.c \ epm-header.in \
--- a/configure.in +++ b/configure.in @@ -103,5 +103,6 @@ progs/xfm/xfmflip progs/minccomplete/minccomplete progs/minchistory/minchistory +progs/mincpik/mincpik )
--- a/progs/CMakeLists.txt +++ b/progs/CMakeLists.txt @@ -163,21 +163,19 @@ PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ DESTINATION bin ) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/minchistory/minchistory.in ${CMAKE_CURRENT_BINARY_DIR}/minchistory.pl @ONLY) -add_custom_target(minchistory.pl chmod +x ${CMAKE_CURRENT_BINARY_DIR}/minchistory.pl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/minchistory/minchistory.in) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/minchistory/minchistory.in ${CMAKE_CURRENT_BINARY_DIR}/minchistory @ONLY) +add_custom_target(minchistory chmod +x ${CMAKE_CURRENT_BINARY_DIR}/minchistory DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/minchistory/minchistory.in) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mincpik/mincpik.in ${CMAKE_CURRENT_BINARY_DIR}/mincpik @ONLY) +add_custom_target(mincpik chmod +x ${CMAKE_CURRENT_BINARY_DIR}/mincpik DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/mincpik/mincpik.in) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mincpik/mincpik.in ${CMAKE_CURRENT_BINARY_DIR}/mincpik.pl @ONLY) -add_custom_target(mincpik.pl chmod +x ${CMAKE_CURRENT_BINARY_DIR}/mincpik.pl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/mincpik/mincpik.in) +INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/minchistory + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ + DESTINATION bin ) INSTALL(PROGRAMS - ${CMAKE_CURRENT_BINARY_DIR}/minchistory.pl + ${CMAKE_CURRENT_BINARY_DIR}/mincpik PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ - DESTINATION bin - RENAME minchistory ) - -INSTALL(PROGRAMS - ${CMAKE_CURRENT_BINARY_DIR}/mincpik.pl - PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ - DESTINATION bin - RENAME mincpik ) + DESTINATION bin )
deleted file mode 100755 --- a/progs/mincpik/mincpik +++ /dev/null @@ -1,522 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2009 -# Andrew Janke - a.janke@gmail.com -# 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 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($Help, $Usage, $me, @opt_table, $tmpdir, %opt); -my(@args, $args, $infile, $outfile, %ordering, $CODE); - -# permutation 'matrix' for differing views -%ordering = ( - 'zspace' => ['yspace', 'xspace'], - 'yspace' => ['zspace', 'xspace'], - 'xspace' => ['zspace', 'yspace'], - ); - -$me = &basename($0); -%opt = ( - 'verbose' => 0, - 'clobber' => 0, - 'fake' => 0, - - 'slice' => undef, - 'scale' => 2, - 'width' => undef, - 'bitdepth' => 8, - 'range' => undef, - 'image_range' => undef, - 'auto_range' => 0, - 'lookup' => undef, - 'dirs' => ['zspace'], - - 'triplanar' => 0, - 'tilesize' => 250, - 'title' => 0, - 'title_text' => undef, - 'title_size' => 16, - 'sagittal_offset' => undef, - 'sagittal_offset_perc' => undef, - 'orientation' => 'vertical', - 'anot_bar' => undef, - ); - -$Help = <<HELP; -| $me generates image files from MINC volumes using the Imagemagick -| convert utility. For a complete list of output file types see the -| convert man pages. (man convert) The resulting image is piped to -| STDOUT -| -| EXAMPLES: -| To display a default view, transverse slicing, middle slice -| using display. (display is part of the Imagemagick package) -| -| \$ mincpik infile.mnc PNG:- | display - -| -| To generate a PNG file of the 15th coronal slice -| -| \$ mincpik -slice 15 -coronal infile.mnc outfile.png -| -| To generate a JPG file using the hotmetal lookup table -| with the image range 0 to 100 -| -| \$ mincpik -lookup '-hotmetal' -image_range 0 100 infile.mnc outfile.jpg -| -| ImageMagick: http://www.wizards.dupont.com/cristy/ImageMagick.html -| NB: ImageMagick should be compiled without 16-bit quanta. -| -| Problems or comments should be sent to: a.janke\@gmail.com -HELP - -$Usage = "Usage: $me [options] <infile.mnc> [<image.type>]\n". - " $me -help to list options\n\n"; - -@opt_table = ( - ['-verbose', 'boolean', 0, \$opt{'verbose'}, - 'be verbose'], - ['-clobber', 'boolean', 0, \$opt{'clobber'}, - 'overwrite existing files'], - ['-fake', 'boolean', 0, \$opt{'fake'}, - 'do a dry run, (echo cmds only)' ], - ['-slice', 'integer', 1, \$opt{'slice'}, - 'slice number to get', - '<int>'], - ['-scale', 'integer', 1, \$opt{'scale'}, - 'scaling factor for resulting image', - '<int>'], - ['-width', 'integer', 1, \$opt{'width'}, - 'autoscale the image to have a fixed image width (in pixels)', - '<int>'], - ['-depth', 'integer', 1, \$opt{'bitdepth'}, - 'bitdepth for resulting image 8 or 16 (MSB machines only!)', - '<int>'], - ['-title', "boolean", 0, \$opt{'title'}, - "add a title to the resulting image"], - ['-title_text', "string", 1, \$opt{'title_text'}, - "use <string> for the title [default: input-filename]", - "<string>"], - ['-title_size', "integer", 1, \$opt{'title_size'}, - "font point size for the title", - "<int>"], - ['-anot_bar', "string", 1, \$opt{'anot_bar'}, - "create an annotated bar to match the image (use height of the output image)", - "<fname.png>"], - - ['Image range and lookup table options', 'section' ], - ['-range', 'float', 2, \@{$opt{'range'}}, - 'valid range of values for MINC file', - '<real> <real>'], - ['-image_range', 'float', 2, \@{$opt{'image_range'}}, - 'range of image values to use for pixel intensity', - '<real> <real>'], - ['-auto_range', 'boolean', 0, \$opt{'auto_range'}, - 'automatically determine image range'], - ['-lookup', 'string', 1, \$opt{'lookup'}, - 'arguments to pass to minclookup', - '<\'argument list\'>'], - - ['Slicing options', 'section' ], - ['-transverse', 'arrayconst', ['zspace'], \@{$opt{'dirs'}}, - 'get a transverse slice'], - ['-axial', 'arrayconst', ['zspace'], \@{$opt{'dirs'}}, - 'synonym for transverse'], - ['-coronal', 'arrayconst', ['yspace'], \@{$opt{'dirs'}}, - 'get a coronal slice'], - ['-sagittal', 'arrayconst', ['xspace'], \@{$opt{'dirs'}}, - 'get a sagital slice'], - ['-allthree', 'arrayconst', ['zspace', 'xspace', 'yspace'], \@{$opt{'dirs'}}, - 'you probably dont want this, it is somewhat broken, use -triplanar instead'], - - ['triplanar options', 'section' ], - ['-triplanar', 'boolean', 0, \$opt{'triplanar'}, - 'create a triplanar view of the input MINC file'], - ['-tilesize', "integer", 1, \$opt{'tilesize'}, - "pixel size for each image in a triplanar"], - ['-sagittal_offset', "integer", 1, \$opt{'sagittal_offset'}, - "offset the sagittal slice from the centre", - "<# slices>"], - ['-sagittal_offset_perc', "integer", 1, \$opt{'sagittal_offset_perc'}, - "offset the sagittal slice by a percentage from the centre", - "<% offset>"], - ['-vertical', 'const', 'vertical', \$opt{'orientation'}, - 'create a vertical triplanar view (Default)'], - ['-horizontal', 'const', 'horizontal', \$opt{'orientation'}, - 'create a horizontal triplanar view'], - ); - -# Check arguments -&Getopt::Tabular::SetHelp ($Help, $Usage); -&GetOptions (\@opt_table, \@ARGV) || exit 1; -die $Usage if ($#ARGV < 0); - -# create temporary directory -$tmpdir = &tempdir( "$me-XXXXXXXX", TMPDIR => 1, CLEANUP => 1 ); - -# set up file names and do a few checks -$infile = $ARGV[0]; -$outfile = (defined($ARGV[1])) ? $ARGV[1] : 'PNG:-'; - -die "$me: Couldn't find $infile\n\n" if (!-e $infile); -if($outfile ne 'PNG:-' && -e $outfile && !$opt{'clobber'}){ - die "\n$me: $outfile exists, use -clobber to overwrite\n\n"; - } - -if($opt{'bitdepth'} != 16 && $opt{bitdepth} != 8) { - die "\n$me: Invalid bitdepth specified - $opt{bitdepth} instead of 8 or 16\n\n"; - } - -# sanity check -if($opt{'auto_range'} && @{$opt{'image_range'}}){ - die "\n$me: only specify one of -auto_range and -image_range (not both)\n\n"; - } - -# warn about -slice and -triplanar -if(defined($opt{'slice'}) && $opt{'triplanar'}){ - warn "\n$me: you probably don't want to use both -triplanar and -slice\n\n"; - } - -# warn about -sagittal_offset and -sagittal_offset_perc -if(defined($opt{'sagittal_offset'}) && $opt{'sagittal_offset_perc'}){ - warn "\n$me: only use one of -sagittal_offset -sagittal_offset_perc\n\n"; - } - -# set up directions for triplanar -if($opt{'triplanar'}){ - $opt{'dirs'} = ['zspace', 'xspace', 'yspace']; - } - -my ($space, $n_slices, $convert_infile, $imgfile, - @extract_args, @convert_args, - $img_x, $img_y, - $img_step_x, $img_step_y, - $img_length_x, $img_length_y, - $dim_names, $pipe_args, $dimorder, - @mont_files); - -# find the 5% to 95% PcT image range if -auto_range -if($opt{'auto_range'}){ - my $buf; - - print STDERR "Getting range of $infile\n" if $opt{'verbose'}; - - chomp($buf = `mincstats -quiet -pctT 5 $infile`); - $buf *= 1.0; - @{$opt{'image_range'}}[0] = $buf; - - chomp($buf = `mincstats -quiet -pctT 95 $infile`); - $buf *= 1.0; - @{$opt{'image_range'}}[1] = $buf; - - # a bit of output - if($opt{'verbose'}){ - print STDERR "Using image range of [@{$opt{image_range}}[0]:@{$opt{image_range}}[1]]\n"; - } - } - -# foreach slicing direction -foreach $space (@{$opt{'dirs'}}){ - - print STDERR "Doing direction $space\n" if $opt{'verbose'}; - - my($slice); - $CODE = "GRAY"; - - # set up the imgfile depending on triplanar and -title - if($opt{'triplanar'}){ - $imgfile = "$tmpdir/trip-$space.png"; - push(@mont_files, $imgfile); - } - elsif($opt{'title'}){ - $imgfile = "$tmpdir/image.png"; - } - else{ - $imgfile = $outfile; - } - - # Get the info we need - $args = "mincinfo ". - "-dimlength $space ". - "-dimlength $ordering{$space}[0] ". - "-dimlength $ordering{$space}[1] ". - "-attvalue $ordering{$space}[0]:step ". - "-attvalue $ordering{$space}[1]:step ". - "-dimnames ". - $infile; - ($n_slices, $img_x, $img_y, $img_step_x, $img_step_y, $dim_names) = split("\n", `$args`); - - if(defined($opt{'width'})){ - $opt{'scale'} = $opt{'width'}/abs($img_step_y * $img_y); - print STDERR "Auto-scaling width factor: $opt{'scale'}\n" if $opt{'verbose'}; - } - $img_length_x = abs(int($img_step_x * $img_x * $opt{'scale'})); - $img_length_y = abs(int($img_step_y * $img_y * $opt{'scale'})); - - # figure out the slice to get - $slice = (!defined($opt{'slice'})) ? int($n_slices/2) : $opt{'slice'}; - - # do the sagittal offset (only one of these should be done) - if($space eq 'xspace'){ - - # slice offset - if(defined($opt{'sagittal_offset'})){ - $slice += $opt{'sagittal_offset'}; - } - - # perc offset - if(defined($opt{'sagittal_offset_perc'})){ - $slice += int($n_slices * $opt{'sagittal_offset_perc'} / 100); - } - } - - # check we didn't step of the edge - if($slice >= $n_slices || $slice < 0){ - die "Slice $slice out of range (0-" . ($n_slices-1) . ")\n\n"; - } - - # check if we have a vector_dimension already - if($dim_names =~ m/vector_dimension/){ - $CODE = 'RGB'; - } - - # take only the first timepoint if we have a time dimension - my @time_res_args = (); - if($dim_names =~ m/time/){ - @time_res_args = ('-dimrange', "time=0,0"); - } - - # do the reshaping - $dimorder = join(',', $space, @{$ordering{$space}}); - if($CODE eq 'RGB'){ - $dimorder .= ',vector_dimension'; - } - @args = ('mincreshape', '-clobber', '-quiet', - '-normalize', - '+direction', - '-dimsize', "$space=-1", - '-dimsize', "$ordering{$space}[0]=-1", - '-dimsize', "$ordering{$space}[1]=-1", - '-dimorder', $dimorder, - '-dimrange', "$space=$slice,1", - @time_res_args, - $infile, "$tmpdir/reshaped.mnc"); - if(scalar(@{$opt{'range'}}) != 0){ - push(@args, '-valid_range', @{$opt{'range'}}[0], @{$opt{'range'}}[1]); - } - if(scalar(@{$opt{'image_range'}}) != 0){ - push(@args, '-image_range', @{$opt{'image_range'}}[0], @{$opt{'image_range'}}[1]); - } - &do_cmd(@args); - - # do the lookup if required - $convert_infile = "$tmpdir/reshaped.mnc"; - if($opt{'lookup'}){ - if($CODE eq 'RGB'){ - warn "$me: Input is vector-valued already. No colour lookup done.\n"; - } - else{ - $convert_infile = "$tmpdir/lookup.mnc"; - $CODE = 'RGB'; - &do_cmd('minclookup', '-clobber', '-quiet', - split(' ', $opt{'lookup'}), - "$tmpdir/reshaped.mnc", $convert_infile); - } - } - - # set up mincextract command - @extract_args = ('mincextract', $convert_infile, - '-normalize', - ($opt{'bitdepth'} == 16) ? ('-short', '-unsigned') : '-byte'); - - # set up convert arguments - # a flip is 'normal' due to the difference between mnc and most image co-ordinates - @convert_args = ('convert', - '-depth', $opt{'bitdepth'}, - '-flip', - '-size', $img_y . 'x' . $img_x, - '-geometry', $img_length_y . 'x' . $img_length_x . '!', - "$CODE:-", $imgfile); - - # check if we are big or little endian for convert's MSB wierdity - $pipe_args = '|'; - if($opt{'bitdepth'} == 16){ - if(unpack("c",substr(pack("s",1),0,1))){ - warn "$me: LSB machine, swapping bytes with dd and crossing fingers\n"; - $pipe_args .= ' dd conv=swab | '; - } - } - - &do_cmd(join(' ', @extract_args, $pipe_args, @convert_args)); - } - -# do the triplanar if requested -if($opt{'triplanar'}){ - my @orient_args; - - if($opt{'title'}){ - $imgfile = "$tmpdir/mont.png"; - } - else{ - $imgfile = $outfile; - } - - if($opt{'orientation'} eq 'vertical'){ - @orient_args = ('-tile', ('1x' . ($#mont_files + 1))); - } - else{ # $opt{orientation} eq 'horizontal' - @orient_args = ('-tile', (($#mont_files + 1) . 'x1')); - } - - # do the montage - &do_cmd('montage', - @orient_args, - '-background', 'grey10', - '-geometry', "$opt{tilesize}x$opt{tilesize}+1+1", - @mont_files, $imgfile); - } - -# Add the title -if($opt{'title'}){ - - # set up the title text - if(!defined($opt{'title_text'})){ - $opt{'title_text'} = &basename($infile); - $opt{'title_text'} =~ s/\.mnc$//; - } - -# This really does not work all that well (but should), go figure -# &do_cmd('convert', '-box', 'black', -# '-font', '7x13', -# '-fill', 'white', -# '-draw', "text 4,12 \"$opt{'title_text'}\"", -# $imgfile, $outfile); -# - # use montage instead - &do_cmd('montage', - '-geometry', '100x100%', - '-background', 'black', - '-fill', 'white', - '-label', $opt{'title_text'}, - '-pointsize', $opt{'title_size'}, - $imgfile, $outfile); - } - -# create the annotated bar if required -if(defined($opt{'anot_bar'})){ - - my($min, $max, $pcode, - $q0, $q1, $q2, $q3, $q4, $bh, $bw, $bb, $ob, - $textbump, $i, @buf); - - # set up a few constants - $textbump = 3; - $pcode = '%6g'; - - # text border, other border, height, width - $bb = 50; - $ob = 25; - $bh = $img_length_y - ($ob*2); - $bw = int($bh/10); - - # get range if not defined - if(!defined($opt{'image_range'}[0])){ - print STDERR "Getting image range\n" if $opt{'verbose'}; - - @buf = split(/\n/, `mincstats -min -max -quiet $infile`); - @{$opt{'image_range'}}[0] = $buf[0] * 1.0; - @{$opt{'image_range'}}[1] = $buf[1] * 1.0; - } - - $min = @{$opt{'image_range'}}[0]; - $max = @{$opt{'image_range'}}[1]; - - # set up the datafile - my(@data) = undef; - my($packstring) = ''; - for($i=0; $i<$bh; $i++){ - $data[$i] = $i; - $packstring .= 'f'; - } - - open(FH, ">$tmpdir/tmp-float.raw"); - for($i=0; $i<$bw; $i++){ - syswrite(FH, pack($packstring, @data)); - } - close(FH); - - # make minc file - &do_cmd('rawtominc', '-clobber', - '-float', - '-input', "$tmpdir/tmp-float.raw", - '-xstep', 1, '-ystep', 1, '-zstep', 1, - '-xstart', 0, '-ystart', 0, '-zstart', 0, - '-dimorder', 'xspace,yspace,zspace', - "$tmpdir/bar.mnc", $bw, $bh, 1); - - - # make .miff bar image (whoa... recursion!) - &do_cmd('mincpik', '-clobber', - '-scale', 1, - (defined($opt{'lookup'})) ? ('-lookup', $opt{'lookup'}) : (), - "$tmpdir/bar.mnc", "$tmpdir/bar.png"); - - # set up the text - $q0 = sprintf($pcode, $min); - $q1 = sprintf($pcode, (($max-$min) * 0.25) + $min); - $q2 = sprintf($pcode, (($max-$min) * 0.5) + $min); - $q3 = sprintf($pcode, (($max-$min) * 0.75) + $min); - $q4 = sprintf($pcode, $max); - - - # create the bar itself via convert - &do_cmd('convert', - '-bordercolor', 'white', - '-border', $bb, - - # color for all the decorations - '-fill', 'black', - - # bar border - '-draw', "line " . join(',', $bb, $bb, ($bb+$bw), $bb ), - '-draw', "line " . join(',', $bb, ($bb+$bh), ($bb+$bw), ($bb+$bh)), - '-draw', "line " . join(',', $bb, $bb, $bb, ($bb+$bh)), - '-draw', "line " . join(',', ($bb+$bw), $bb, ($bb+$bw), ($bb+$bh)), - - # 3 ticks at 1/4, 1/2 and 3/4 - '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*1/4)), ($bb+$bw), ($bb+($bh*1/4))), - '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*2/4)), ($bb+$bw), ($bb+($bh*2/4))), - '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*3/4)), ($bb+$bw), ($bb+($bh*3/4))), - - # text - '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*0/4)+$textbump) . " '$q4'", - '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*1/4)+$textbump) . " '$q3'", - '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*2/4)+$textbump) . " '$q2'", - '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*3/4)+$textbump) . " '$q1'", - '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*4/4)+$textbump) . " '$q0'", - - # finally crop of the extra border - '-crop', (($bb*2)+$bw-($bb-$ob)) . "x" . (($bb*2)+$bh-$bb) . "+" . ($bb-$ob) . "+" . ($bb-$ob), - - "$tmpdir/bar.png", $opt{'anot_bar'}); - } - - -sub do_cmd { - print STDERR "@_\n" if $opt{'verbose'}; - if(!$opt{'fake'}){ - system(@_) == 0 or die "\n$me: Failed executing @_\n\n"; - } - }
new file mode 100755 --- /dev/null +++ b/progs/mincpik/mincpik.in @@ -0,0 +1,661 @@ +#! /usr/bin/env perl +# +# Copyright 2009 +# Andrew Janke - a.janke@gmail.com +# 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 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::Long; +use Pod::Usage; +use File::Basename; +use File::Temp qw/ tempdir /; + +my($Help, $Usage, $me, @opt_table, $tmpdir, %opt); +my(@args, $args, $infile, $outfile, %ordering, $CODE); + +# permutation 'matrix' for differing views +%ordering = ( + 'zspace' => ['yspace', 'xspace'], + 'yspace' => ['zspace', 'xspace'], + 'xspace' => ['zspace', 'yspace'], + ); + +$me = &basename($0); +%opt = ( + 'help' => 0, + 'man' => 0, + 'verbose' => 0, + 'clobber' => 0, + 'fake' => 0, + + 'scale' => 2, + 'width' => undef, + 'bitdepth' => 8, + 'range' => undef, + 'image_range' => undef, + 'auto_range' => 0, + 'lookup' => undef, + + 'slice' => undef, + 'dirs' => ['zspace'], + + 'triplanar' => 0, + 'tilesize' => 250, + 'title' => 0, + 'title_text' => undef, + 'title_size' => 16, + 'sagittal_offset' => undef, + 'sagittal_offset_perc' => undef, + 'orientation' => 'vertical', + 'anot_bar' => undef, + ); + +# Check arguments +&GetOptions( + 'help|?' => \$opt{'help'}, + 'man' => \$opt{'man'}, + 'version' => sub { &print_version_info }, + 'v|verbose' => \$opt{'verbose'}, + 'c|clobber' => \$opt{'clobber'}, + 'f|fake' => \$opt{'fake'}, + + 'scale=i' => \$opt{'scale'}, + 'width=i' => \$opt{'width'}, + 'depth=i' => \$opt{'bitdepth'}, + + 'title' => \$opt{'title'}, + 'title_text=s' => \$opt{'title_text'}, + 'title_size=i' => \$opt{'title_size'}, + 'anot_bar=s' => \$opt{'anot_bar'}, + + # Image range and lookup table options + 'range=f{2}' => \@{$opt{'range'}}, + 'image_range=f{2}' => \@{$opt{'image_range'}}, + 'auto_range' => \$opt{'auto_range'}, + 'lookup=s' => \$opt{'lookup'}, + + # Slicing options + 's|slice=i' => \$opt{'slice'}, + 'z|axial|transverse' => sub { $opt{'dirs'} = ['zspace']; }, + 'y|coronal' => sub { $opt{'dirs'} = ['yspace']; }, + 'x|sagittal' => sub { $opt{'dirs'} = ['xspace']; }, + + # triplanar options + 't|triplanar' => \$opt{'triplanar'}, + 'tilesize=i' => \$opt{'tilesize'}, + 'sagittal_offset=i' => \$opt{'sagittal_offset'}, + 'sagittal_offset_perc=i' => \$opt{'sagittal_offset_perc'}, + 'vertical' => \$opt{'orientation'}, + 'horizontal' => \$opt{'orientation'}, + ) or pod2usage(-verbose => 1) && exit; + +# handle -man, -help or missing args +pod2usage(-verbose => 1) if $opt{'help'}; +pod2usage(-exitstatus => 0, -verbose => 2) if $opt{'man'}; +pod2usage(-verbose => 0) && exit if ($#ARGV != 1); + +# Check arguments +#&Getopt::Tabular::SetHelp ($Help, $Usage); +#&GetOptions (\@opt_table, \@ARGV) || exit 1; +#die $Usage if ($#ARGV < 0); + +# create temporary directory +$tmpdir = &tempdir( "$me-XXXXXXXX", TMPDIR => 1, CLEANUP => 1 ); + +# set up file names and do a few checks +$infile = $ARGV[0]; +$outfile = (defined($ARGV[1])) ? $ARGV[1] : 'PNG:-'; + +die "$me: Couldn't find $infile\n\n" if (!-e $infile); +if($outfile ne 'PNG:-' && -e $outfile && !$opt{'clobber'}){ + die "\n$me: $outfile exists, use -clobber to overwrite\n\n"; + } + +if($opt{'bitdepth'} != 16 && $opt{bitdepth} != 8) { + die "\n$me: Invalid bitdepth specified - $opt{bitdepth} instead of 8 or 16\n\n"; + } + +# sanity check +if($opt{'auto_range'} && @{$opt{'image_range'}}){ + die "\n$me: only specify one of -auto_range and -image_range (not both)\n\n"; + } + +# warn about -slice and -triplanar +if(defined($opt{'slice'}) && $opt{'triplanar'}){ + warn "\n$me: you probably don't want to use both -triplanar and -slice\n\n"; + } + +# warn about -sagittal_offset and -sagittal_offset_perc +if(defined($opt{'sagittal_offset'}) && $opt{'sagittal_offset_perc'}){ + warn "\n$me: only use one of -sagittal_offset -sagittal_offset_perc\n\n"; + } + +# set up directions for triplanar +if($opt{'triplanar'}){ + $opt{'dirs'} = ['zspace', 'xspace', 'yspace']; + } + +my ($space, $n_slices, $convert_infile, $imgfile, + @extract_args, @convert_args, + $img_x, $img_y, + $img_step_x, $img_step_y, + $img_length_x, $img_length_y, + $dim_names, $pipe_args, $dimorder, + @mont_files); + +# find the 5% to 95% PcT image range if -auto_range +if($opt{'auto_range'}){ + my $buf; + + print STDERR "Getting range of $infile\n" if $opt{'verbose'}; + + chomp($buf = `mincstats -quiet -pctT 5 $infile`); + $buf *= 1.0; + @{$opt{'image_range'}}[0] = $buf; + + chomp($buf = `mincstats -quiet -pctT 95 $infile`); + $buf *= 1.0; + @{$opt{'image_range'}}[1] = $buf; + + # a bit of output + if($opt{'verbose'}){ + print STDERR "Using image range of [@{$opt{image_range}}[0]:@{$opt{image_range}}[1]]\n"; + } + } + +# foreach slicing direction +foreach $space (@{$opt{'dirs'}}){ + + print STDERR "Doing direction $space\n" if $opt{'verbose'}; + + my($slice); + $CODE = "GRAY"; + + # set up the imgfile depending on triplanar and -title + if($opt{'triplanar'}){ + $imgfile = "$tmpdir/trip-$space.png"; + push(@mont_files, $imgfile); + } + elsif($opt{'title'}){ + $imgfile = "$tmpdir/image.png"; + } + else{ + $imgfile = $outfile; + } + + # Get the info we need + $args = "mincinfo ". + "-dimlength $space ". + "-dimlength $ordering{$space}[0] ". + "-dimlength $ordering{$space}[1] ". + "-attvalue $ordering{$space}[0]:step ". + "-attvalue $ordering{$space}[1]:step ". + "-dimnames ". + $infile; + ($n_slices, $img_x, $img_y, $img_step_x, $img_step_y, $dim_names) = split("\n", `$args`); + + if(defined($opt{'width'})){ + $opt{'scale'} = $opt{'width'}/abs($img_step_y * $img_y); + print STDERR "Auto-scaling width factor: $opt{'scale'}\n" if $opt{'verbose'}; + } + $img_length_x = abs(int($img_step_x * $img_x * $opt{'scale'})); + $img_length_y = abs(int($img_step_y * $img_y * $opt{'scale'})); + + # figure out the slice to get + $slice = (!defined($opt{'slice'})) ? int($n_slices/2) : $opt{'slice'}; + + # do the sagittal offset (only one of these should be done) + if($space eq 'xspace'){ + + # slice offset + if(defined($opt{'sagittal_offset'})){ + $slice += $opt{'sagittal_offset'}; + } + + # perc offset + if(defined($opt{'sagittal_offset_perc'})){ + $slice += int($n_slices * $opt{'sagittal_offset_perc'} / 100); + } + } + + # check we didn't step of the edge + if($slice >= $n_slices || $slice < 0){ + die "Slice $slice out of range (0-" . ($n_slices-1) . ")\n\n"; + } + + # check if we have a vector_dimension already + if($dim_names =~ m/vector_dimension/){ + $CODE = 'RGB'; + } + + # take only the first timepoint if we have a time dimension + my @time_res_args = (); + if($dim_names =~ m/time/){ + @time_res_args = ('-dimrange', "time=0,0"); + } + + # do the reshaping + $dimorder = join(',', $space, @{$ordering{$space}}); + if($CODE eq 'RGB'){ + $dimorder .= ',vector_dimension'; + } + @args = ('mincreshape', '-clobber', '-quiet', + '-normalize', + '+direction', + '-dimsize', "$space=-1", + '-dimsize', "$ordering{$space}[0]=-1", + '-dimsize', "$ordering{$space}[1]=-1", + '-dimorder', $dimorder, + '-dimrange', "$space=$slice,1", + @time_res_args, + $infile, "$tmpdir/reshaped.mnc"); + if(scalar(@{$opt{'range'}}) != 0){ + push(@args, '-valid_range', @{$opt{'range'}}[0], @{$opt{'range'}}[1]); + } + if(scalar(@{$opt{'image_range'}}) != 0){ + push(@args, '-image_range', @{$opt{'image_range'}}[0], @{$opt{'image_range'}}[1]); + } + &do_cmd(@args); + + # do the lookup if required + $convert_infile = "$tmpdir/reshaped.mnc"; + if($opt{'lookup'}){ + if($CODE eq 'RGB'){ + warn "$me: Input is vector-valued already. No colour lookup done.\n"; + } + else{ + $convert_infile = "$tmpdir/lookup.mnc"; + $CODE = 'RGB'; + &do_cmd('minclookup', '-clobber', '-quiet', + split(' ', $opt{'lookup'}), + "$tmpdir/reshaped.mnc", $convert_infile); + } + } + + # set up mincextract command + @extract_args = ('mincextract', $convert_infile, + '-normalize', + ($opt{'bitdepth'} == 16) ? ('-short', '-unsigned') : '-byte'); + + # set up convert arguments + # a flip is 'normal' due to the difference between mnc and most image co-ordinates + @convert_args = ('convert', + '-depth', $opt{'bitdepth'}, + '-flip', + '-size', $img_y . 'x' . $img_x, + '-geometry', $img_length_y . 'x' . $img_length_x . '!', + "$CODE:-", $imgfile); + + # check if we are big or little endian for convert's MSB wierdity + $pipe_args = '|'; + if($opt{'bitdepth'} == 16){ + if(unpack("c",substr(pack("s",1),0,1))){ + warn "$me: LSB machine, swapping bytes with dd and crossing fingers\n"; + $pipe_args .= ' dd conv=swab | '; + } + } + + &do_cmd(join(' ', @extract_args, $pipe_args, @convert_args)); + } + +# do the triplanar if requested +if($opt{'triplanar'}){ + my @orient_args; + + if($opt{'title'}){ + $imgfile = "$tmpdir/mont.png"; + } + else{ + $imgfile = $outfile; + } + + if($opt{'orientation'} eq 'vertical'){ + @orient_args = ('-tile', ('1x' . ($#mont_files + 1))); + } + else{ # $opt{orientation} eq 'horizontal' + @orient_args = ('-tile', (($#mont_files + 1) . 'x1')); + } + + # do the montage + &do_cmd('montage', + @orient_args, + '-background', 'grey10', + '-geometry', "$opt{tilesize}x$opt{tilesize}+1+1", + @mont_files, $imgfile); + } + +# Add the title +if($opt{'title'}){ + + # set up the title text + if(!defined($opt{'title_text'})){ + $opt{'title_text'} = &basename($infile); + $opt{'title_text'} =~ s/\.mnc$//; + } + +# This really does not work all that well (but should), go figure +# &do_cmd('convert', '-box', 'black', +# '-font', '7x13', +# '-fill', 'white', +# '-draw', "text 4,12 \"$opt{'title_text'}\"", +# $imgfile, $outfile); +# + # use montage instead + &do_cmd('montage', + '-geometry', '100x100%', + '-background', 'black', + '-fill', 'white', + '-label', $opt{'title_text'}, + '-pointsize', $opt{'title_size'}, + $imgfile, $outfile); + } + +# create the annotated bar if required +if(defined($opt{'anot_bar'})){ + + my($min, $max, $pcode, + $q0, $q1, $q2, $q3, $q4, $bh, $bw, $bb, $ob, + $textbump, $i, @buf); + + # set up a few constants + $textbump = 3; + $pcode = '%6g'; + + # text border, other border, height, width + $bb = 50; + $ob = 25; + $bh = $img_length_y - ($ob*2); + $bw = int($bh/10); + + # get range if not defined + if(!defined($opt{'image_range'}[0])){ + print STDERR "Getting image range\n" if $opt{'verbose'}; + + @buf = split(/\n/, `mincstats -min -max -quiet $infile`); + @{$opt{'image_range'}}[0] = $buf[0] * 1.0; + @{$opt{'image_range'}}[1] = $buf[1] * 1.0; + } + + $min = @{$opt{'image_range'}}[0]; + $max = @{$opt{'image_range'}}[1]; + + # set up the datafile + my(@data) = undef; + my($packstring) = ''; + for($i=0; $i<$bh; $i++){ + $data[$i] = $i; + $packstring .= 'f'; + } + + open(FH, ">$tmpdir/tmp-float.raw"); + for($i=0; $i<$bw; $i++){ + syswrite(FH, pack($packstring, @data)); + } + close(FH); + + # make minc file + &do_cmd('rawtominc', '-clobber', + '-float', + '-input', "$tmpdir/tmp-float.raw", + '-xstep', 1, '-ystep', 1, '-zstep', 1, + '-xstart', 0, '-ystart', 0, '-zstart', 0, + '-dimorder', 'xspace,yspace,zspace', + "$tmpdir/bar.mnc", $bw, $bh, 1); + + + # make .miff bar image (whoa... recursion!) + &do_cmd('mincpik', '-clobber', + '-scale', 1, + (defined($opt{'lookup'})) ? ('-lookup', $opt{'lookup'}) : (), + "$tmpdir/bar.mnc", "$tmpdir/bar.png"); + + # set up the text + $q0 = sprintf($pcode, $min); + $q1 = sprintf($pcode, (($max-$min) * 0.25) + $min); + $q2 = sprintf($pcode, (($max-$min) * 0.5) + $min); + $q3 = sprintf($pcode, (($max-$min) * 0.75) + $min); + $q4 = sprintf($pcode, $max); + + + # create the bar itself via convert + &do_cmd('convert', + '-bordercolor', 'white', + '-border', $bb, + + # color for all the decorations + '-fill', 'black', + + # bar border + '-draw', "line " . join(',', $bb, $bb, ($bb+$bw), $bb ), + '-draw', "line " . join(',', $bb, ($bb+$bh), ($bb+$bw), ($bb+$bh)), + '-draw', "line " . join(',', $bb, $bb, $bb, ($bb+$bh)), + '-draw', "line " . join(',', ($bb+$bw), $bb, ($bb+$bw), ($bb+$bh)), + + # 3 ticks at 1/4, 1/2 and 3/4 + '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*1/4)), ($bb+$bw), ($bb+($bh*1/4))), + '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*2/4)), ($bb+$bw), ($bb+($bh*2/4))), + '-draw', "line " . join(',', ($bb+($bw*3/4)), ($bb+($bh*3/4)), ($bb+$bw), ($bb+($bh*3/4))), + + # text + '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*0/4)+$textbump) . " '$q4'", + '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*1/4)+$textbump) . " '$q3'", + '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*2/4)+$textbump) . " '$q2'", + '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*3/4)+$textbump) . " '$q1'", + '-draw', 'text ' . ($bb+$bw) . ',' . ($bb+($bh*4/4)+$textbump) . " '$q0'", + + # finally crop of the extra border + '-crop', (($bb*2)+$bw-($bb-$ob)) . "x" . (($bb*2)+$bh-$bb) . "+" . ($bb-$ob) . "+" . ($bb-$ob), + + "$tmpdir/bar.png", $opt{'anot_bar'}); + } + + +sub do_cmd { + print STDERR "@_\n" if $opt{'verbose'}; + if(!$opt{'fake'}){ + system(@_) == 0 or die "\n$me: Failed executing @_\n\n"; + } + } + +# print version information +sub print_version_info { + my $PACKAGE = '@PACKAGE_NAME@'; + my $VERSION = '@PACKAGE_VERSION@'; + my $PACKAGE_BUGREPORT = '@PACKAGE_BUGREPORT@'; + + print STDOUT "\n$PACKAGE version $VERSION\n". + "Comments to $PACKAGE_BUGREPORT\n\n"; + exit 0; + } + +__END__ + +=head1 NAME + +B<mincpik> - generate images from minc files + +=head1 SYNOPSIS + +B<mincpik> [options] <infile>.mnc [<image.type>] + +mincpik generates image files from MINC volumes using the Imagemagick +convert utility. Use -help or -man for more information and examples + +=head1 DESCRIPTION + +B<mincpik> generates image files from MINC volumes using the Imagemagick +B<convert> utility. For a complete list of output file types see the +B<convert> man pages. + +EXAMPLES: +To display a default view, axial (z) slicing, middle slice +using display. (display is part of the Imagemagick package) + + mincpik infile.mnc PNG:- | display - + +To generate a PNG file of the 15th coronal slice + + mincpik -slice 15 -coronal infile.mnc outfile.png + +To generate a JPG file using the hotmetal lookup table +with the image range 0 to 100 + + mincpik -lookup '-hotmetal' -image_range 0 100 infile.mnc outfile.jpg + +ImageMagick: http://www.wizards.dupont.com/cristy/ImageMagick.html + NB: ImageMagick should be compiled without 16-bit quanta. + +Currently if there is a time dimension in the file the image will +only produced from the first time point + +Problems or comments should be sent to: a.janke\@gmail.com + +=head1 OPTIONS + +=over 4 + +=item B<-v>, B<--verbose> + +Be noisy when doing things + +=item B<--version> + +Print version number and exit + +=item B<-?>, B<--help> + +Dump some quick help output + +=item B<--man> + +Dump a man page + +=item B<-c> B<--clobber> + +overwrite the output file if it exists already + +=item B<-f> B<--fake> + +do a dry run, (echo cmds only). This is usually used in combination with -verbose to echo commands only + +=item B<--scale> + +scaling factor for resulting image, by default images are output +at twice their original resolution + +=item B<--width> + +autoscale the resulting image to have a fixed image width (in pixels) + +=item B<--depth> + +bitdepth for resulting image 8 or 16 (MSB machines only!) + +=item B<--title> + +add a title to the resulting image, if just this option is specified the text used for the title is the name of the input image file. + +=item B<--title_text> + +use the input string for the title [default: input-filename]. This option must be used in conjunction with -title + +=item B<--title_size> + +font point size for the title + +=item B<--anot_bar> + +create an annotated bar to match the image (use height of the output image) + + +=head3 Image range and lookup table options + +=item B<--range> + +valid range of values for MINC file + +=item B<--image_range> + +range of image values to use for pixel intensity + +=item B<--auto_range> + +automatically determine image range using a 5 and 95% PcT. (histogram) + +=item B<--lookup> + +arguments to pass to minclookup + + +=head3 Slicing options + +=item B<-s> B<--slice> + +slice number to get. (note this is in voxel co-ordinates) + +=item B<-z> B<--axial> B<--transverse> + +get an axial/transverse (z) slice + +=item B<-y> B<--coronal> + +get a coronal (y) slice + +=item B<-x> B<--sagittal> + +get a sagital (x) slice + + +=head3 Triplanar options + +=item B<-t> B<--triplanar> + +create a triplanar view of the input file + +=item B<--tilesize> + +pixel size for each image in a triplanar + +=item B<--sagittal_offset> + +offset the sagittal slice from the centre + +=item B<--sagittal_offset_perc> + +offset the sagittal slice by a percentage from the centre + +=item B<--vertical> + +create a vertical triplanar view (Default) + +=item B<--horizontal> + +create a horizontal triplanar view + + +=back + +=head1 SEE ALSO + +convert(1) mincextract(1) display(1) + +=head1 AUTHOR + +Andrew Janke - a.janke@gmail.com + +=head1 COPYRIGHTS + +Copyright 2012 by Andrew L Janke + +=cuts + +
deleted file mode 100644 --- a/progs/mincpik/mincpik.man1 +++ /dev/null @@ -1,108 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH MINCPIK 1 "$Date: 2009-08-11 13:49:19 $" "" "MINC User's Guide" - -.SH NAME -mincpik \- generate images from minc files - -.SH SYNOPSIS -.B mincpik -[options] <infile>.mnc [<image.type>] - -.SH DESCRIPTION -.I mincpik -generates image files from MINC volumes using the Imagemagick -convert utility. For a complete list of output file types see the -convert man pages. - -Currently if there is a time dimension in the file the image will -only produced from the first time point - -.SH General options -.TP -\fB\-verbose\fR -print out extra information -.TP -\fB\-clobber\fR -overwrite the output file if it exists already -.TP -\fB\-fake\fR -usually used in combination with -verbose to echo commands only -.TP -\fB\-slice\fR -slice number to get (note this is in voxel co-ordinates) -.TP -\fB\-scale\fR -scaling factor for resulting image, by default images are output -at twice their original resolution -.TP -\fB\-width\fR -autoscale the resulting image to have a fixed image width (in pixels) -.TP -\fB\-depth\fR -bit-depth for resulting image 8 or 16 (MSB machines only) -.TP -\fB\-title\fR -add a title to the resulting image, if just this option is specified the text used for the title is the name of the input image file. -\fB\-title_text\fR -specify the title text to use. This option must be used in conjunction with -title -.TP -.SH Image range and lookup table options -.TP -\fB\-range\fR\ \fImin max\fR -valid range of values to use from MINC file -.TP -\fB\-image_range\fR\ \fImin max\fR -range of image values to use for pixel intensity -.TP -\fB\-auto_range\fR -automatically determine image range using a 5 and 95% PcT. (histogram) -.TP -\fB\-lookup\fR\ \fIarguments\fR -arguments to pass to minclookup - -.SH Slicing options -.TP -\fB\-transverse\fR -get a transverse slice -.TP -\fB\-axial\fR -synonym for transverse -.TP -\fB\-coronal\fR -get a coronal slice -.TP -\fB\-sagittal\fR -get a sagital slice -.TP -\fB\-allthree\fR -this option is deprecated, use -triplanar instead - -.SH Triplanar options -.TP -\fB\-triplanar\fR -create a triplanar view of the input MINC file -.TP -\fB\-tilesize\fR -pixel size for each image in a triplanar -.TP -\fB\-sagittal_offset\fR -offset the saggital slice from the centre in the triplanar -.TP -\fB\-vertical\fR -create a vertical triplanar series of images (this is the default) -.TP -\fB\-horizontal\fR -create a horizontal triplanar instead of a vertical one - -.SH Generic options for all commands: -.TP -\fB\-help\fR -Print summary of command-line options and abort. - -.SH AUTHOR -Andrew Janke - <a.janke@gmail.com> - -.SH "SEE ALSO" -.IR minclookup (1), -.IR convert (1), -.IR display (1).