metamri 0.1.13 → 0.1.14

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 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