metamri 0.1.13 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -4,4 +4,4 @@
4
4
  .idea
5
5
  *~
6
6
  test/fixtures/visit_raw_data_directory
7
-
7
+ doc/*
data/README.rdoc CHANGED
@@ -1,6 +1,8 @@
1
1
  == ImageData
2
2
 
3
- A small library that can be used to extract metadata from large collections of research MR imaging data sets. Support is also provided to insert the metadata into a Wisconsin ADRC Imaging Core compatible database. Several
3
+ A small library that can be used to extract metadata from large collections of research MR imaging data sets.
4
+
5
+ Support is also provided to insert the metadata into a Wisconsin ADRC Imaging Core compatible database. Several
4
6
  command line utilities are provided as well as a minimal API that is useful for building ruby on rails rake tasks.
5
7
 
6
8
  You will most likely be interested in either:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.13
1
+ 0.1.14
data/bin/list_visit CHANGED
@@ -9,17 +9,18 @@
9
9
  #
10
10
  # == Examples
11
11
  #
12
- # list_visit /Data/vtrak1/raw/ries.aware.visit1/awr001_7854_02102009
12
+ # %> list_visit /Data/vtrak1/raw/ries.aware.visit1/awr001_7854_02102009
13
13
  #
14
- # cd /Data/vtrak1/raw/ries.aware.visit1/awr001_7854_02102009
14
+ #
15
15
  # list_visit
16
16
  #
17
17
  # If no raw data directory is given, the current directory will be assumed.
18
- # list_visit
18
+ # %> cd /Data/vtrak1/raw/ries.aware.visit1/awr001_7854_02102009
19
+ # %> list_visit
19
20
  #
20
21
  # == Usage
21
- # list_visit <raw_data_directory>
22
- #
22
+ # %> list_visit <raw_data_directory>
23
+ #
23
24
  # For help use: list_vist -h
24
25
  #
25
26
  # == Options
@@ -38,18 +39,19 @@ require 'rdoc/usage'
38
39
  # require 'logger'
39
40
 
40
41
  def list_visit(raw_directory)
41
- # $LOG = Logger.new(STDOUT)
42
- # $LOG.level = Logger::INFO
42
+ unless $LOG
43
+ $LOG = Logger.new(STDOUT)
44
+ $LOG.level = Logger::INFO
45
+ end
43
46
 
44
47
  # First try to lookup Visit and Datasets through active_resource
45
- # Then fall back to scanning them fresh.
48
+ # Then fall back to scanning them fresh using the metamri classes.
46
49
 
47
50
  begin
48
- # raise
49
51
  visit = VisitRawDataDirectoryResource.find(:first, :params => {:search => {:path => raw_directory}})
50
- raise "Could not lookup visit using path." unless visit
51
- raise "Incorrect visit found." unless visit.path == raw_directory
52
- rescue Exception => e
52
+ raise IOError.new("Could not lookup visit using path.") unless visit
53
+ raise IOError.new("Returned visit does not match path.") unless visit.path == raw_directory
54
+ rescue IOError => e
53
55
  puts e
54
56
  visit = VisitRawDataDirectory.new(raw_directory)
55
57
  begin
@@ -60,15 +62,9 @@ def list_visit(raw_directory)
60
62
  end
61
63
  end
62
64
 
63
- # begin
64
- # rescue Exception => e
65
- # $LOG.error "There was a problem scanning a dataset in #{visit.visit_directory}... skipping."
66
- # $LOG.error "Exception message: #{e.message}"
67
- # raise e
68
- # end
69
-
70
- # Visit is Either a RawVisitDataDirectory or a RawVisitDataDirectoryResource
71
- # Either can handle printing to_s
65
+ # Output a pretty version of the visit details.
66
+ # Visit is Either a RawVisitDataDirectory or a RawVisitDataDirectoryResource,
67
+ # and either should respond to to_s
72
68
  visit.to_s
73
69
 
74
70
  end
@@ -48,6 +48,10 @@ class Pathname
48
48
  end
49
49
  end
50
50
 
51
+ # def first_pfile(&block)
52
+ # Pathname.new(filename).local_copy { block }
53
+ # end
54
+
51
55
  def first_dicom
52
56
  entries.each do |leaf|
53
57
  branch = self + leaf
@@ -87,7 +91,14 @@ class Pathname
87
91
  return
88
92
  end
89
93
 
90
- def local_copy(tempdir = Dir.tmpdir)
94
+ =begin
95
+ Creates a local, unzipped copy of a file for use in scanning.
96
+ Will return a pathname to the local copy if called directly, or can also be
97
+ passed a block. If it is passed a block, it will create the local copy
98
+ and ensure the local copy is deleted.
99
+ =end
100
+
101
+ def local_copy(tempdir = Dir.tmpdir, &block)
91
102
  tfbase = self.to_s =~ /\.bz2$/ ? self.basename.to_s.chomp(".bz2") : self.basename.to_s
92
103
  tfbase.escape_filename
93
104
  tmpfile = File.join(tempdir, tfbase)
@@ -96,7 +107,19 @@ class Pathname
96
107
  else
97
108
  FileUtils.cp(self.to_s, tmpfile)
98
109
  end
99
- return Pathname.new(tmpfile)
110
+
111
+ lc = Pathname.new(tmpfile)
112
+
113
+ if block
114
+ begin
115
+ yield lc
116
+ ensure
117
+ lc.delete
118
+ end
119
+
120
+ else
121
+ return lc
122
+ end
100
123
  end
101
124
 
102
125
  end
@@ -9,10 +9,39 @@ class RawImageDatasetResource < ActiveResource::Base
9
9
  # so check the current schema.rb file for those.
10
10
  def to_metamri_raw_image_dataset
11
11
  # A Metamri Class requires at least one valid image file.
12
- # This is a little tricky since we really only care about the variables, not rescanning them.
12
+ # This is a little wasteful since we really only care about the variables,
13
+ # not rescanning them.
13
14
 
14
- Pathname.new(path).first_dicom do |fd|
15
- @dataset = RawImageDataset.new( path, [RawImageFile.new(fd)] )
15
+ filename = Pathname.new(File.join(path, scanned_file))
16
+ filename_matches = /P\d{5}.7(.bz2)?/.match(filename)
17
+
18
+ if filename_matches # Pfile
19
+ if filename_matches[1] # '.bz2' if present, nil if otherwise.
20
+ filename = Pathname.new(File.join(filename, '.bz2'))
21
+ end
22
+
23
+ # The scanned file is always reported in unzipped format, so we don't
24
+ # have to worry about stripping a .bz2 extension.
25
+ # The actual file on the filesystem may be zipped or unzipped
26
+ # (although it Should! be zipped. Check for that or return IOError.
27
+ zipped_filename = filename.to_s.chomp + '.bz2'
28
+
29
+ if filename.file?
30
+ image_file = filename
31
+ elsif Pathname.new(zipped_filename).file?
32
+ image_file = Pathname.new(zipped_filename)
33
+ else
34
+ raise IOError, "Could not find #{filename} or it's bz2 zipped equivalent #{zipped_filename}."
35
+ end
36
+
37
+ image_file.local_copy do |local_pfile|
38
+ @dataset = RawImageDataset.new( path, [RawImageFile.new(local_pfile)])
39
+ end
40
+
41
+ else # Dicom
42
+ Pathname.new(path).first_dicom do |fd|
43
+ @dataset = RawImageDataset.new( path, [RawImageFile.new(fd)] )
44
+ end
16
45
  end
17
46
 
18
47
  return @dataset
@@ -29,4 +58,71 @@ class RawImageDatasetResource < ActiveResource::Base
29
58
  # super
30
59
  # end
31
60
  # end
61
+
62
+ # def file_count
63
+ # unless @file_count
64
+ # if @raw_image_files.first.dicom?
65
+ # @file_count = Dir.open(@directory).reject{ |branch| /^\./.match(branch) }.length
66
+ # elsif @raw_image_files.first.pfile?
67
+ # @file_count = 1
68
+ # else raise "File not recognized as dicom or pfile."
69
+ # end
70
+ # end
71
+ # return @file_count
72
+ # end
73
+
74
+ def pfile?
75
+ scanned_file =~ /^P.*.7$/
76
+ end
77
+
78
+
79
+
80
+ def file_count
81
+ if pfile?
82
+ file_count = 1
83
+ else
84
+ file_count = Dir.open(path).reject{ |branch| /(^\.|.yaml$)/.match(branch) }.length
85
+ end
86
+ return file_count
87
+ end
88
+
89
+ # Returns a relative filepath to the dataset. Handles dicoms by returning the
90
+ # dataset directory, and pfiles by returning either the pfile filename or,
91
+ # if passed a visit directory, the relative path from the visit directory to
92
+ # the pfile (i.e. P00000.7 or raw/P00000.7).
93
+ def relative_dataset_path(visit_dir = nil)
94
+ if pfile?
95
+ relative_dataset_path = scanned_file
96
+ else # Then it's a dicom.
97
+ relative_dataset_path = File.basename(path)
98
+ end
99
+
100
+ return relative_dataset_path
101
+ end
102
+
103
+ # Creates an Hirb Table for pretty output of dataset info.
104
+ # It takes an array of either RawImageDatasets or RawImageDatasetResources
105
+ def self.to_table(datasets)
106
+ Hirb::Helpers::AutoTable.render(
107
+ datasets.sort_by{ |ds| [ds.timestamp, File.basename(ds.path)] },
108
+ :headers => { :relative_dataset_path => 'Dataset', :series_description => 'Series Details', :file_count => "File Count", },
109
+ :fields => [:relative_dataset_path, :series_description, :file_count],
110
+ :description => false # Turn off rendering row count description at bottom.
111
+ )
112
+ rescue NameError => e
113
+ puts e
114
+
115
+ # Header Line
116
+ printf "\t%-15s %-30s [%s]\n", "Directory", "Series Description", "Files"
117
+
118
+ # Dataset Lines
119
+ datasets.sort_by{|ds| [ds.timestamp, File.basename(ds.path)] }.each do |dataset|
120
+ printf "\t%-15s %-30s [%s]\n", dataset.relative_dataset_path, dataset.series_description, dataset.file_count
121
+ end
122
+
123
+ # Reminder Line
124
+ puts "(This would be much prettier if you installed hirb.)"
125
+ return
126
+ end
127
+
32
128
  end
@@ -8,8 +8,9 @@ class VisitRawDataDirectoryResource < ActiveResource::Base
8
8
  self.element_name = "visit"
9
9
 
10
10
  # Creates a Backwards Transfer to go from ActiveRecord to Metamri Classes
11
- # ActiveResource will provide :attr methods for column names from the database,
12
- # so check the current schema.rb file for those.
11
+ #
12
+ # ActiveResource will provide :attr methods for column names from the
13
+ # database, so check the current schema.rb file for those.
13
14
  def to_metamri_visit_raw_data_directory
14
15
  @visit = VisitRawDataDirectory.new(path)
15
16
  @visit.timestamp = date
@@ -23,10 +24,23 @@ class VisitRawDataDirectoryResource < ActiveResource::Base
23
24
  @datasets ||= RawImageDatasetResource.find(:all, :from => "/visits/#{id}/image_datasets.xml" )
24
25
  end
25
26
 
27
+ # Convert a Resource and its datasets to a VisitRawDataDirectory and
28
+ # RawImageDataset, respectively, then pretty print it using
29
+ # VisitRawDataDirectory.to_s
30
+ # def to_s
31
+ # metamri_visit = to_metamri_visit_raw_data_directory
32
+ # metamri_visit.datasets = datasets.collect { |ds| ds.to_metamri_raw_image_dataset}
33
+ # metamri_visit.to_s
34
+ # end
35
+
26
36
  def to_s
27
- metamri_visit = to_metamri_visit_raw_data_directory
28
- metamri_visit.datasets = datasets.collect { |ds| ds.to_metamri_raw_image_dataset}
29
- metamri_visit.to_s
37
+ puts; path.length.times { print "-" }; puts
38
+ puts "#{path}"
39
+ puts "#{rmr} - #{date} - #{scanner_source}"
40
+ puts
41
+ # puts "#{@scan_procedure_name}"
42
+ puts RawImageDatasetResource.to_table(datasets)
43
+ puts "Notes: " + notes unless notes.nil? or notes.empty?
30
44
  end
45
+
31
46
  end
32
-
data/lib/metamri.rb CHANGED
@@ -9,7 +9,7 @@ require 'metamri/visit_raw_data_directory_resource'
9
9
 
10
10
  begin
11
11
  require 'hirb'
12
- rescue LoadError => e
12
+ rescue LoadError
13
13
  puts "Hirb must be installed for pretty output. Use 'sudo gem install hirb'"
14
14
  end
15
15
 
data/lib/nifti_builder.rb CHANGED
@@ -28,4 +28,10 @@ module UnknownImageDataset
28
28
 
29
29
  return nifti_conversion_command, nifti_output_file
30
30
  end
31
+ end
32
+
33
+ module DTIDataset
34
+ def dataset_to_nifti(nifti_output_directory, nifti_filename, input_options = {} )
35
+
36
+ end
31
37
  end
@@ -179,7 +179,15 @@ have more component files than shell commands can handle.
179
179
 
180
180
 
181
181
  def file_count
182
- @file_count ||= Dir.open(@directory).reject{ |branch| /^\./.match(branch) }.length
182
+ unless @file_count
183
+ if @raw_image_files.first.dicom?
184
+ @file_count = Dir.open(@directory).reject{ |branch| /(^\.|.yaml$)/.match(branch) }.length
185
+ elsif @raw_image_files.first.pfile?
186
+ @file_count = 1
187
+ else raise "File not recognized as dicom or pfile."
188
+ end
189
+ end
190
+ return @file_count
183
191
  end
184
192
 
185
193
  # Creates an Hirb Table for pretty output of dataset info.
@@ -191,11 +199,41 @@ have more component files than shell commands can handle.
191
199
 
192
200
  Hirb::Helpers::AutoTable.render(
193
201
  datasets.sort_by{ |ds| [ds.timestamp, File.basename(ds.directory)] },
194
- :headers => { :directory_basename => 'Directory', :series_description => 'Series Description', :file_count => 'File Count'},
195
- :fields => [:directory_basename, :series_description, :file_count]
202
+ :headers => { :relative_dataset_path => 'Dataset', :series_details => 'Series Details', :file_count => 'File Count'},
203
+ :fields => [:relative_dataset_path, :series_details, :file_count],
204
+ :description => false # Turn off rendering row count description at bottom.
196
205
  )
197
206
 
198
207
  end
208
+
209
+ # Returns a relative filepath to the dataset. Handles dicoms by returning the
210
+ # dataset directory, and pfiles by returning either the pfile filename or,
211
+ # if passed a visit directory, the relative path from the visit directory to
212
+ # the pfile (i.e. P00000.7 or raw/P00000.7).
213
+ def relative_dataset_path(visit_dir = nil)
214
+ image_file = @raw_image_files.first
215
+ case image_file.file_type
216
+ when 'dicom'
217
+ relative_dataset_path = File.basename(directory)
218
+ when 'pfile'
219
+ full_dataset_path = Pathname.new(File.join(directory, image_file.filename))
220
+ if visit_dir
221
+ relative_dataset_path = full_dataset_path.relative_path_from(visit_dir)
222
+ else
223
+ relative_dataset_path = image_file.filename
224
+ end
225
+ else raise "Cannot identify #{@raw_image_files.first.filename}"
226
+ end
227
+
228
+ return relative_dataset_path
229
+ end
230
+
231
+ # Reports series details, including description and possilby image quality
232
+ # check comments.
233
+ def series_details
234
+ @series_description
235
+ end
236
+
199
237
  private
200
238
 
201
239
  # Gets the earliest timestamp among the raw image files in this dataset.
@@ -184,12 +184,19 @@ Returns an array of the created nifti files.
184
184
  def to_s
185
185
  puts; @visit_directory.length.times { print "-" }; puts
186
186
  puts "#{@visit_directory}"
187
- puts "#{@rmr_number} - #{@scanner_source}"
188
- puts "#{@scan_procedure_name}"
189
- puts "#{@scanid}"
187
+ puts "#{@rmr_number} - #{@timestamp.strftime('%F')} - #{@scanner_source}"
188
+ puts
190
189
  puts RawImageDataset.to_table(@datasets)
191
190
  return
192
191
  rescue NameError => e
192
+ puts e
193
+ if @datasets.first.class.to_s == "RawImageDatasetResource"
194
+ @datasets = @datasets.map { |ds| ds.to_metamri_image_dataset }
195
+ end
196
+
197
+ # puts @datasets.first.class.to_s
198
+ # puts @datasets
199
+
193
200
  # Header Line
194
201
  printf "\t%-15s %-30s [%s]\n", "Directory", "Series Description", "Files"
195
202
 
data/metamri.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{metamri}
8
- s.version = "0.1.13"
8
+ s.version = "0.1.14"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kristopher J. Kosmatka"]
12
- s.date = %q{2010-02-04}
12
+ s.date = %q{2010-03-11}
13
13
  s.description = %q{Extraction of MRI metadata and insertion into compatible sqlite3 databases.}
14
14
  s.email = %q{kk4@medicine.wisc.edu}
15
15
  s.executables = ["import_study.rb", "import_visit.rb", "import_respiratory_files.rb", "list_visit", "convert_visit.rb"]
@@ -48,7 +48,7 @@ Gem::Specification.new do |s|
48
48
  s.homepage = %q{http://github.com/brainmap/metamri}
49
49
  s.rdoc_options = ["--charset=UTF-8"]
50
50
  s.require_paths = ["lib"]
51
- s.rubygems_version = %q{1.3.5}
51
+ s.rubygems_version = %q{1.3.6}
52
52
  s.summary = %q{MRI metadata}
53
53
  s.test_files = [
54
54
  "test/nifti_builder_spec.rb",
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metamri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 14
9
+ version: 0.1.14
5
10
  platform: ruby
6
11
  authors:
7
12
  - Kristopher J. Kosmatka
@@ -9,29 +14,33 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-04 00:00:00 -06:00
17
+ date: 2010-03-11 00:00:00 -06:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: sqlite3-ruby
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
23
29
  version: "0"
24
- version:
30
+ type: :runtime
31
+ version_requirements: *id001
25
32
  - !ruby/object:Gem::Dependency
26
33
  name: rspec
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
33
41
  version: "0"
34
- version:
42
+ type: :development
43
+ version_requirements: *id002
35
44
  description: Extraction of MRI metadata and insertion into compatible sqlite3 databases.
36
45
  email: kk4@medicine.wisc.edu
37
46
  executables:
@@ -85,18 +94,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
94
  requirements:
86
95
  - - ">="
87
96
  - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
88
99
  version: "0"
89
- version:
90
100
  required_rubygems_version: !ruby/object:Gem::Requirement
91
101
  requirements:
92
102
  - - ">="
93
103
  - !ruby/object:Gem::Version
104
+ segments:
105
+ - 0
94
106
  version: "0"
95
- version:
96
107
  requirements: []
97
108
 
98
109
  rubyforge_project:
99
- rubygems_version: 1.3.5
110
+ rubygems_version: 1.3.6
100
111
  signing_key:
101
112
  specification_version: 3
102
113
  summary: MRI metadata