wadrc-bcp-scripts 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/.svn/entries +41 -0
- data/.svn/format +1 -0
- data/.svn/prop-base/reconstruct_dti_test.rb.svn-base +5 -0
- data/.svn/text-base/reconstruct_dti_test.rb.svn-base +25 -0
- data/Gemfile +4 -0
- data/README.md +5 -0
- data/Rakefile +7 -0
- data/VERSION +1 -0
- data/bin/FS_local_recon +98 -0
- data/bin/FieldmapAtWaisman.rb +35 -0
- data/bin/createFieldmap.rb +33 -0
- data/bin/preprocess_dti.rb +110 -0
- data/bin/run_dti_fit_for_study.sh +26 -0
- data/bin/run_dti_fit_script.sh +28 -0
- data/bin/tensor_transpose.rb +45 -0
- data/lib/.svn/entries +54 -0
- data/lib/.svn/format +1 -0
- data/lib/.svn/prop-base/dti_wrapper.rb.svn-base +5 -0
- data/lib/.svn/prop-base/dtifit_processing.rb.svn-base +5 -0
- data/lib/.svn/text-base/dti_wrapper.rb.svn-base +33 -0
- data/lib/.svn/text-base/dtifit_processing.rb.svn-base +95 -0
- data/lib/additions/NetSshConnectionSession.rb +20 -0
- data/lib/wadrc-bcp-scripts.rb +13 -0
- data/lib/wadrc-bcp-scripts/basic_task.rb +137 -0
- data/lib/wadrc-bcp-scripts/dtitask.rb +156 -0
- data/lib/wadrc-bcp-scripts/fieldmap_classes.rb +166 -0
- data/lib/wadrc-bcp-scripts/freesurfer_roi_task.rb +134 -0
- data/lib/wadrc-bcp-scripts/tensor.rb +25 -0
- data/lib/wadrc-bcp-scripts/version.rb +3 -0
- data/spec/.svn/entries +28 -0
- data/spec/.svn/format +1 -0
- data/spec/FS_local_recon_spec.rb +22 -0
- data/spec/blueprints.rb +12 -0
- data/spec/dtitask_spec.rb +95 -0
- data/spec/examples/johnson.alz.snodrest.visit2.yaml +14 -0
- data/spec/examples/johnson.tbi.aware.visit1.yaml +11 -0
- data/spec/examples/johnson.wrap140.visit1.yaml +12 -0
- data/spec/examples/johnson.wrap140.visit1_TR12s.yaml +12 -0
- data/spec/examples/spec.yaml +22 -0
- data/spec/factories.rb +11 -0
- data/spec/helper_spec.rb +8 -0
- data/test/.svn/entries +41 -0
- data/test/.svn/format +1 -0
- data/test/.svn/prop-base/reconstruct_dti_test.rb.svn-base +5 -0
- data/test/.svn/text-base/reconstruct_dti_test.rb.svn-base +25 -0
- data/test/reconstruct_dti_test.rb +25 -0
- metadata +188 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'tensor'
|
6
|
+
|
7
|
+
def run!
|
8
|
+
# Parse CLI Options and Spec File
|
9
|
+
options = parse_options
|
10
|
+
|
11
|
+
# Create a DTI Preprocessing Flow Task and run it.
|
12
|
+
tensor = Tensor.new(options[:tensor_file])
|
13
|
+
tensor.to_fsl_txt(options[:output_file])
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_options
|
18
|
+
options = Hash.new
|
19
|
+
|
20
|
+
parser = OptionParser.new do |opts|
|
21
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] input_tensor output_transposed_tensor"
|
22
|
+
|
23
|
+
# opts.on('-t', '--tensor TENSOR_FILE', "Tensor File.") do |tensor_file|
|
24
|
+
# options[:tensor_file] = tensor_file
|
25
|
+
# end
|
26
|
+
|
27
|
+
opts.on_tail('-h', '--help', "Show this message") { puts(parser); exit }
|
28
|
+
opts.on_tail("Example: #{File.basename(__FILE__)} 40_direction.txt 40_direction_transposed.txt")
|
29
|
+
end
|
30
|
+
parser.parse!(ARGV)
|
31
|
+
|
32
|
+
options[:tensor_file] = ARGV[0]
|
33
|
+
options[:output_file] = ARGV[1]
|
34
|
+
|
35
|
+
unless ARGV.size == 2
|
36
|
+
puts(parser); exit
|
37
|
+
end
|
38
|
+
|
39
|
+
return options
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
if File.basename(__FILE__) == File.basename($0)
|
44
|
+
run!
|
45
|
+
end
|
data/lib/.svn/entries
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
8
|
2
|
+
|
3
|
+
dir
|
4
|
+
146
|
5
|
+
file:///Data/vtrak1/SysAdmin/lab_repository/trunk/ImageProcessing/lib
|
6
|
+
file:///Data/vtrak1/SysAdmin/lab_repository
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
2009-05-08T17:32:47.685248Z
|
11
|
+
146
|
12
|
+
erik
|
13
|
+
|
14
|
+
|
15
|
+
svn:special svn:externals svn:needs-lock
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
fd7843e3-2c87-496d-a67a-9fe0c7cb9cb9
|
28
|
+
|
29
|
+
dtifit_processing.rb
|
30
|
+
file
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
2009-05-08T17:33:56.000000Z
|
36
|
+
b2bef44f643323c28603d4dcb8dd1da8
|
37
|
+
2009-05-08T17:32:47.685248Z
|
38
|
+
146
|
39
|
+
erik
|
40
|
+
has-props
|
41
|
+
|
42
|
+
dti_wrapper.rb
|
43
|
+
file
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
2009-05-08T17:33:57.000000Z
|
49
|
+
22334daf49e150cb1646a6a6ac7a2033
|
50
|
+
2009-05-08T17:32:47.685248Z
|
51
|
+
146
|
52
|
+
erik
|
53
|
+
has-props
|
54
|
+
|
data/lib/.svn/format
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
8
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
## This is a temporary wrapper to execute DTI data.
|
3
|
+
|
4
|
+
require 'dtifit_processing'
|
5
|
+
|
6
|
+
=begin rdoc
|
7
|
+
This library provides basic processing for Diffusion Tensor Images (DTI)
|
8
|
+
This command-line processing script takes raw DTI dicoms and outputs FA, MD &
|
9
|
+
associated diffusion maps (eigenvalues & eigenvectors).
|
10
|
+
|
11
|
+
Currently, the script assumes raw data are unzipped and the output directory
|
12
|
+
exists, the glob and DTI params are constant across DTI series.
|
13
|
+
=end
|
14
|
+
|
15
|
+
|
16
|
+
#def run!
|
17
|
+
# input_directory = '/Data/vtrak1/raw/wrap140/wrp002_5938_03072008/017'
|
18
|
+
# output_directory = '/Data/vtrak1/preprocessed/visits/wrap140.visit1/wrp002/dti'
|
19
|
+
# subject_prefix = 'wrp002'
|
20
|
+
#
|
21
|
+
# ReconstructDTI.reconstruct!(input_directory, output_directory, subject_prefix)
|
22
|
+
#end
|
23
|
+
#
|
24
|
+
#run!
|
25
|
+
|
26
|
+
|
27
|
+
if __FILE__ == $0
|
28
|
+
if ARGV.size != 3
|
29
|
+
puts "Usage: dtifit_processing.rb input_directory output_directory subject_prefix"
|
30
|
+
else
|
31
|
+
ReconstructDTI.reconstruct!(ARGV[0], ARGV[1], ARGV[2])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
This library provides basic processing for Diffusion Tensor Images (DTI).
|
5
|
+
|
6
|
+
The main function reconstruct! takes 3 arguements: A directory of raw DTI dicoms,
|
7
|
+
an output directory and a filename prefix. A set of batch commands using standard
|
8
|
+
imaging tools (AFNI & FSL) are generated and executed to create Fractional
|
9
|
+
Anisotropy (FA), Mean Diffusivity (MD) and associated diffusion maps
|
10
|
+
(eigenvalues & eigenvectors) in the output directory.
|
11
|
+
|
12
|
+
The script depends on AFNI to be in the path for reconstruction (to3d) and
|
13
|
+
FSL to be in the path for DTI Data Fitting (eddy_correct, bet & dtifit)
|
14
|
+
|
15
|
+
=end
|
16
|
+
|
17
|
+
require 'fileutils'
|
18
|
+
|
19
|
+
class ReconstructDTI
|
20
|
+
|
21
|
+
BVECTORS_FILE = '/Data/vtrak1/preprocessed/progs/wrap140.visit1/DTI_Fitting/25_directions_UWhospital_magnet_horizontal_spaces.csv' # Vector directions of the gradient for each of the 25 directtions in this 25-direction DTI sequence. A 3x26 matrix.
|
22
|
+
BVALUES_FILE = '/Data/vtrak1/preprocessed/progs/wrap140.visit1/DTI_Fitting/25_directions_bvalues.txt' # Magnitude of the direction vectors. A 1x26 matrix of 0 for the first (B0) and then 1000 for each direction afterwards.
|
23
|
+
|
24
|
+
FILE_GLOB = "'I*.dcm'"
|
25
|
+
VOLUMES = 26
|
26
|
+
SLICES_PER_VOLUME = 49
|
27
|
+
SLICE_ORDER = 'altplus'
|
28
|
+
|
29
|
+
# Checks for some required helper applications that must be installed on the
|
30
|
+
# system prior to use. It returns false if there are no missing
|
31
|
+
# processing program binaries and returns the names of the missing programs.
|
32
|
+
def self.missing_required_binaries?
|
33
|
+
missing_binaries = []
|
34
|
+
['to3d', 'eddy_correct', 'bet', 'dtifit'].each do |required_binary|
|
35
|
+
if system("which #{required_binary} > /dev/null") == false
|
36
|
+
missing_binaries << required_binary
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if missing_binaries.size == 0
|
41
|
+
return false
|
42
|
+
else
|
43
|
+
return missing_binaries
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# Constructs the commands used in the script from constants and variables
|
49
|
+
# passed in from the command line.
|
50
|
+
def self.construct_commands
|
51
|
+
to3d_recon_options = "-time:zt #{SLICES_PER_VOLUME} #{VOLUMES} 1 #{SLICE_ORDER} #{@@input_directory}/#{FILE_GLOB}"
|
52
|
+
|
53
|
+
recon_cmd = "to3d -prefix #{@@file_prefix}.nii -session #{@@output_directory} #{to3d_recon_options}"
|
54
|
+
eddy_cmd = "eddy_correct #{@@output_directory}/#{@@file_prefix}.nii #{@@output_directory}/#{@@file_prefix}_ecc.nii 0"
|
55
|
+
mask_cmd = "bet #{@@output_directory}/#{@@file_prefix}_ecc #{@@output_directory}/#{@@file_prefix}_ecc_brain -f 0.1 -g 0 -n -m"
|
56
|
+
dtifit_cmd = "dtifit --data=#{@@output_directory}/#{@@file_prefix}_ecc.nii --out=#{@@output_directory}/#{@@file_prefix}_dti --mask=#{@@output_directory}/#{@@file_prefix}_ecc_brain_mask --bvecs=#{BVECTORS_FILE} --bvals=#{BVALUES_FILE}"
|
57
|
+
|
58
|
+
@@batch_cmd = [recon_cmd, eddy_cmd, mask_cmd, dtifit_cmd].join("; ")
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets variables passed in from the command-line, constructs the processing
|
62
|
+
# commands and then executes them.
|
63
|
+
#
|
64
|
+
# Throws an IOError if input_directory is not found on the filesystem or
|
65
|
+
# output directory already exists.
|
66
|
+
def self.reconstruct!(input_directory, output_directory, file_prefix)
|
67
|
+
@@input_directory = File.expand_path(input_directory)
|
68
|
+
@@output_directory = File.expand_path(output_directory)
|
69
|
+
@@file_prefix = file_prefix
|
70
|
+
|
71
|
+
if missing_required_binaries?
|
72
|
+
puts "You are missing some required processing programs:"
|
73
|
+
missing_required_binaries?.each { |requirement| puts requirement }
|
74
|
+
puts "Please install the missing programs or run this script from a properly configured workstation."
|
75
|
+
raise(Error)
|
76
|
+
end
|
77
|
+
|
78
|
+
raise(IOError, "#{@@input_directory}: not found.") if not File.directory?(@@input_directory)
|
79
|
+
raise(IOError, "#{@@output_directory} already exists.") if File.directory?(@@output_directory)
|
80
|
+
FileUtils.mkdir_p(@@output_directory)
|
81
|
+
|
82
|
+
|
83
|
+
construct_commands
|
84
|
+
|
85
|
+
puts @@batch_cmd
|
86
|
+
system @@batch_cmd
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# Code for when excuting from the command line.
|
92
|
+
if __FILE__ == $0
|
93
|
+
puts "Libraries for DTI processing. To use this with the command-line, use dti_wrapper.rb"
|
94
|
+
end
|
95
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Reopen Net::SSH to allow for a "realtime" ssh run that prints out stdout
|
2
|
+
# immediately upon receipt, so you can interactively watch the results.
|
3
|
+
class Net::SSH::Connection::Session
|
4
|
+
def exec_realtime(cmd)
|
5
|
+
open_channel do |channel|
|
6
|
+
channel.exec(cmd) do |ch, success|
|
7
|
+
abort "could not execute command: #{cmd}" unless success
|
8
|
+
|
9
|
+
channel.on_data do |ch, data|
|
10
|
+
puts "#{data}"
|
11
|
+
end
|
12
|
+
|
13
|
+
channel.on_extended_data do |ch, type, data|
|
14
|
+
warn "ERROR: #{data}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
loop
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'net/ssh'
|
4
|
+
|
5
|
+
require 'wadrc-bcp-scripts/basic_task'
|
6
|
+
require 'wadrc-bcp-scripts/dtitask'
|
7
|
+
require 'wadrc-bcp-scripts/fieldmap_classes'
|
8
|
+
require 'wadrc-bcp-scripts/tensor'
|
9
|
+
require 'wadrc-bcp-scripts/version'
|
10
|
+
require 'additions/NetSshConnectionSession'
|
11
|
+
|
12
|
+
# WADRC Basic Common Processing (BCP) Scripts
|
13
|
+
module WadrcBcpScripts; end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'escoffier'
|
3
|
+
|
4
|
+
module WadrcBcpScripts
|
5
|
+
|
6
|
+
# Enviornment and configuration checks common between processing streams.
|
7
|
+
class BasicTask
|
8
|
+
# Task Configuration Options Hash
|
9
|
+
attr_accessor :config
|
10
|
+
|
11
|
+
# Check for some required helper applications that must be installed on the
|
12
|
+
# system prior to use. It returns true if there are no missing
|
13
|
+
# processing program binaries, otherwise it puts them to the screen and
|
14
|
+
# raises a ScriptError.
|
15
|
+
def environment_requires(*args)
|
16
|
+
missing_binaries = []
|
17
|
+
args.each do |required_binary|
|
18
|
+
if system("which #{required_binary.to_s} > /dev/null") == false
|
19
|
+
missing_binaries << required_binary
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
unless missing_binaries.size == 0
|
25
|
+
error = "
|
26
|
+
Warning: The following processing tools weren't found on your system.
|
27
|
+
- #{missing_binaries.join(', ')}
|
28
|
+
|
29
|
+
|
30
|
+
Please install the missing programs, run this script from a properly configured workstation,
|
31
|
+
or use the dry_run option to output your script to the terminal.\n "
|
32
|
+
puts error
|
33
|
+
raise(ScriptError, "Missing #{missing_binaries.join(", ")}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
# Check for required keys in the @config hash.
|
41
|
+
def config_requires(*args)
|
42
|
+
missing_keys = []
|
43
|
+
args.each do |required_key|
|
44
|
+
unless @config.has_key?(required_key)
|
45
|
+
missing_keys << required_key
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
unless missing_keys.size == 0
|
50
|
+
error = "
|
51
|
+
Warning: Misconfiguration detected.
|
52
|
+
You are missing the following keys from your spec file:
|
53
|
+
- #{missing_keys.join(', ')}
|
54
|
+
|
55
|
+
|
56
|
+
Please install the missing programs, run this script from a properly configured workstation,
|
57
|
+
or use the dry_run option to output your script to the terminal.\n "
|
58
|
+
puts error
|
59
|
+
raise(ScriptError, "Missing Keys: #{missing_keys.join(", ")}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Basic IO Directory Checks
|
64
|
+
def check_setup(input_directory = @input_directory, output_directory = @output_directory)
|
65
|
+
# Check Input Directory
|
66
|
+
raise(IOError, "#{input_directory}: not found.") unless File.directory?(input_directory)
|
67
|
+
|
68
|
+
# Check Gradient Tensor Files
|
69
|
+
ensure_file_exists @config[:bvectors_file], @config[:bvalues_file]
|
70
|
+
|
71
|
+
unless @config[:dry_run]
|
72
|
+
# Check Working Input Directory
|
73
|
+
if @config[:force_sandbox]
|
74
|
+
path = Pathname.new(input_directory)
|
75
|
+
# @working_input_directory = path.sandbox(input_directory)
|
76
|
+
@working_input_directory = path.prep_mise(input_directory + '/', Dir.mktmpdir + '/')
|
77
|
+
@working_input_directory = File.join(@working_input_directory, File.basename(input_directory))
|
78
|
+
else
|
79
|
+
@working_input_directory = input_directory
|
80
|
+
end
|
81
|
+
|
82
|
+
# Check Output Directory and force cleanup if necessary.
|
83
|
+
colliding_files = Dir.glob(File.join(output_directory, @file_prefix) + '*')
|
84
|
+
puts colliding_files
|
85
|
+
if File.directory?(output_directory) && colliding_files.empty? == false
|
86
|
+
if @config[:force_overwrite] then colliding_files.each {|file| puts "Removing #{file}..."; File.delete(file) }
|
87
|
+
else raise(IOError, "#{output_directory} already exists. Set force_overwite in your spec file to overwrite the directory.")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
FileUtils.mkdir_p(output_directory)
|
91
|
+
else
|
92
|
+
# Use the real input directory if the working directory was not assigned
|
93
|
+
# (ie during dry run)
|
94
|
+
@working_input_directory = input_directory
|
95
|
+
end
|
96
|
+
|
97
|
+
# Setup Logging
|
98
|
+
logfile = File.join(output_directory, "#{File.basename(input_directory)}_#{today}.log")
|
99
|
+
if File.writable?(output_directory) && ! @config[:dry_run]
|
100
|
+
$LOG = Logger.new(logfile)
|
101
|
+
else
|
102
|
+
$LOG = Logger.new(STDOUT)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Switch CWD (default output location for rotbvecs script)
|
106
|
+
@cwd = Dir.pwd
|
107
|
+
Dir.chdir(output_directory) unless @config[:dry_run]
|
108
|
+
end
|
109
|
+
|
110
|
+
def ensure_file_exists(*args)
|
111
|
+
args.each do |file|
|
112
|
+
raise(IOError, "#{file} not found.") unless File.exists?(file)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def cleanup
|
120
|
+
Dir.chdir(@cwd)
|
121
|
+
puts Dir.pwd
|
122
|
+
cleanup_directories
|
123
|
+
# $LOG.close
|
124
|
+
end
|
125
|
+
|
126
|
+
# Cleanup Sandbox Directories
|
127
|
+
def cleanup_directories
|
128
|
+
if File.directory?(@working_input_directory) && (@input_directory != @working_input_directory)
|
129
|
+
FileUtils.rm_r @working_input_directory
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def today
|
134
|
+
[Date.today.month, Date.today.day, Date.today.year].join
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module WadrcBcpScripts
|
2
|
+
|
3
|
+
# This library creates scripts for basic processing for Diffusion Tensor Images
|
4
|
+
# (DTI).
|
5
|
+
#
|
6
|
+
# The main function reconstruct! takes 3 arguements: A directory of raw DTI
|
7
|
+
# dicoms, an output directory and a filename prefix. A set of batch commands
|
8
|
+
# using standard imaging tools (AFNI & FSL) are generated and executed to create
|
9
|
+
# Fractional Anisotropy (FA), Mean Diffusivity (MD) and associated diffusion
|
10
|
+
# maps (eigenvalues & eigenvectors) in the output directory.
|
11
|
+
#
|
12
|
+
# The script depends on AFNI to be in the path for reconstruction (to3d) and
|
13
|
+
# FSL to be in the path for DTI Data Fitting (eddy_correct, bet & dtifit)
|
14
|
+
class Dtitask < BasicTask
|
15
|
+
|
16
|
+
# Task Configuration Options Hash
|
17
|
+
attr_accessor :config
|
18
|
+
# Source Directory of DICOMS
|
19
|
+
attr_reader :input_directory
|
20
|
+
# Source Directory of _unzipped_ DICOMS if using a Sandbox (or input_directory if not)
|
21
|
+
attr_reader :working_input_directory
|
22
|
+
# Destination Directory for DTI vectors, values, and maps
|
23
|
+
attr_reader :output_directory
|
24
|
+
# File Prefix to use for processing.
|
25
|
+
attr_reader :file_prefix
|
26
|
+
|
27
|
+
|
28
|
+
# Intialize DTItask with the following options:
|
29
|
+
#
|
30
|
+
# DTI Options
|
31
|
+
# * bvectors_file :
|
32
|
+
# * bvalues_file :
|
33
|
+
# * repetition_time : TR in milliseconds, defaults to 8000
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# File Conversion Options
|
37
|
+
# * file_glob :
|
38
|
+
# * volumes :
|
39
|
+
# * slices_per_volume :
|
40
|
+
# * slice_order:
|
41
|
+
#
|
42
|
+
#
|
43
|
+
# Runtime Options
|
44
|
+
# * dry_run :
|
45
|
+
# * force_overwrite :
|
46
|
+
# * sandbox : Forces copying and unzipping to a temp directory in the case
|
47
|
+
# of zipped dicom files.
|
48
|
+
#
|
49
|
+
def initialize(config = Hash.new)
|
50
|
+
@config = config
|
51
|
+
|
52
|
+
@config[:dry_run] = true if config.empty?
|
53
|
+
|
54
|
+
begin
|
55
|
+
# Intialize Settings for File Conversion and Diffusion Directions and Values
|
56
|
+
config_requires :bvectors_file, :bvalues_file, :file_glob, :volumes,
|
57
|
+
:slices_per_volume, :slice_order
|
58
|
+
|
59
|
+
# List binaries requried for the script to run.
|
60
|
+
environment_requires :to3d, :eddy_correct, :bet, :dtifit, :rotbvecs
|
61
|
+
rescue ScriptError => e
|
62
|
+
raise e unless @config[:dry_run]
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Reconstruct creates a script of commands to execute in order to prepare
|
69
|
+
# DTI data for analyses (take a raw directory of DICOMS, convert them to
|
70
|
+
# nifti, eddy current correct them, and fit them using FSL to create
|
71
|
+
# eigen vectors and values, and MD and FA maps.
|
72
|
+
#
|
73
|
+
# Throws an IOError if input_directory is not found on the filesystem or
|
74
|
+
# output directory already exists (except during a dry_run).
|
75
|
+
def reconstruct!(input_directory, output_directory, file_prefix = nil)
|
76
|
+
@input_directory = File.expand_path(input_directory)
|
77
|
+
@output_directory = File.expand_path(output_directory)
|
78
|
+
@file_prefix = file_prefix ? file_prefix : File.basename(input_directory)
|
79
|
+
|
80
|
+
introduction = "Begin processing #{File.join(@input_directory)}"; puts
|
81
|
+
puts "-" * introduction.size
|
82
|
+
puts introduction; puts
|
83
|
+
|
84
|
+
begin check_setup unless @config[:dry_run]
|
85
|
+
rescue IOError => e
|
86
|
+
puts "Error: #{e}"
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
|
90
|
+
# Construct the Script, output it and run it.
|
91
|
+
batch_cmd = construct_commands(@working_input_directory, @output_directory, @file_prefix)
|
92
|
+
|
93
|
+
batch_cmd.each do |cmd|
|
94
|
+
puts cmd; $LOG.info cmd
|
95
|
+
puts `#{cmd}` unless @config[:dry_run]
|
96
|
+
puts
|
97
|
+
end
|
98
|
+
|
99
|
+
cleanup unless @config[:dry_run]
|
100
|
+
|
101
|
+
puts "Done processing #{@file_prefix}" unless @config[:dry_run]
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Constructs the commands used in the script from constants and variables
|
107
|
+
# set during intialization/configuration and gathered by the main
|
108
|
+
# reconstruct! function.
|
109
|
+
def construct_commands(input_directory, output_directory, file_prefix)
|
110
|
+
rep_time = @config[:repetition_time] ? @config[:repetition_time] : 8000
|
111
|
+
to3d_recon_options = "-time:zt #{@config[:slices_per_volume]} #{@config[:volumes]} #{rep_time} #{@config[:slice_order]} #{input_directory}/#{@config[:file_glob]}"
|
112
|
+
|
113
|
+
commands = Array.new
|
114
|
+
|
115
|
+
# Recon
|
116
|
+
commands << "to3d -prefix #{file_prefix}.nii -session #{output_directory} #{to3d_recon_options}"
|
117
|
+
|
118
|
+
# Eddy Current Correction
|
119
|
+
commands << "eddy_correct #{output_directory}/#{file_prefix}.nii #{output_directory}/#{file_prefix}_ecc.nii 0"
|
120
|
+
|
121
|
+
if @config[:rotate]
|
122
|
+
# Rotate_bvecs
|
123
|
+
subject_bvectors_file = File.join(output_directory, file_prefix + "_" + File.basename(@config[:bvectors_file]))
|
124
|
+
commands << "rotbvecs #{@config[:bvectors_file]} #{subject_bvectors_file} #{File.join(output_directory, file_prefix)}_ecc.ecclog"
|
125
|
+
else
|
126
|
+
subject_bvectors_file = @config[:bvectors_file]
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Apply Mask
|
131
|
+
if @config[:mask]
|
132
|
+
out = "#{File.join(output_directory, file_prefix)}_ecc_ss"
|
133
|
+
commands << "fslmaths #{@config[:mask]} -mul #{File.join(output_directory, file_prefix)}_ecc #{out}"
|
134
|
+
else
|
135
|
+
out = "#{File.join(output_directory, file_prefix)}_ecc"
|
136
|
+
end
|
137
|
+
commands << "bet #{out} #{out}_brain -f 0.1 -g 0 -n -m"
|
138
|
+
|
139
|
+
# Run DTI Fit
|
140
|
+
commands << "dtifit --data=#{output_directory}/#{file_prefix}_ecc.nii \
|
141
|
+
--out=#{output_directory}/#{file_prefix}_dti \
|
142
|
+
--mask=#{out}_brain_mask \
|
143
|
+
--bvecs=#{subject_bvectors_file} \
|
144
|
+
--bvals=#{@config[:bvalues_file]}"
|
145
|
+
|
146
|
+
return commands
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
# Message for when excuting from the command line.
|
152
|
+
if __FILE__ == $0
|
153
|
+
puts "Script generation library for DTI processing. To use this with the command-line, use preprocess_dti.rb"
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|