metamri 0.1.22 → 0.1.23

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.22
1
+ 0.1.23
data/bin/list_visit CHANGED
@@ -40,11 +40,17 @@ require 'metamri'
40
40
  def run!
41
41
  options = parse_options
42
42
 
43
- # Default to scanning the current directory if no argument was given.
44
- raw_directory = ARGV[0] ||= Dir.pwd
45
- raw_directory = File.expand_path(raw_directory)
43
+ # Default to scanning the current directory if no argument was given,
44
+ # otherwise go through each list.
45
+ unless ARGV.length == 1
46
+ input_directories = ARGV
47
+ else
48
+ input_directories = ARGV[0]
49
+ end
46
50
 
47
- list_visit raw_directory, options
51
+ input_directories.each do |raw_directory|
52
+ list_visit raw_directory, options
53
+ end
48
54
 
49
55
  end
50
56
 
@@ -5,6 +5,12 @@ class String
5
5
  mgsub([[/[\s\:\)\(\/\?\,]+/, "-"], [/\*/, "star"], [/\./,""]])
6
6
  end
7
7
 
8
+ # Does some basic string replacements to ensure valid directory names.
9
+ def escape_dirname
10
+ mgsub( [ [/[\s\:\)\(\?\,]+/, "-"], [/\*/, "star"] ] )
11
+ end
12
+
13
+
8
14
  # gsub multiple pairs of regexp's
9
15
  def mgsub(key_value_pairs=[].freeze)
10
16
  regexp_fragments = key_value_pairs.collect { |k,v| k }
@@ -1,11 +1,24 @@
1
- require 'dicom'
2
- require 'RMagick'
3
1
  require 'tmpdir'
2
+ begin
3
+ %W{dicom RMagick}.each do |lib|
4
+ require lib
5
+ end
6
+ rescue LoadError => e
7
+ raise LoadError, "Could not load #{e}. Thumbnailing will use slicer instead of ruby-dicom."
8
+ end
9
+
4
10
 
5
11
  # This class is a ruby object encapsulating a .png 2D Thumbnail of a Dataset
12
+ # Initialize it with an #RawImageDataset
6
13
  class RawImageDatasetThumbnail
14
+ VALID_PROCESSORS = [:rubydicom, :slicer]
7
15
 
8
- attr_reader :dataset, :path
16
+ # The parent #RawImageDataset
17
+ attr_reader :dataset
18
+ # The path to the thumbnail image if it's already been created
19
+ attr_reader :path
20
+ # The processor for creating the thumbnail (:rubydicom or :slicer)
21
+ attr_reader :processor
9
22
 
10
23
  def initialize(dataset)
11
24
  if dataset.class == RawImageDataset
@@ -19,41 +32,67 @@ class RawImageDatasetThumbnail
19
32
  @path ||= create_thumbnail
20
33
  end
21
34
 
22
- # Returns the path of png and sets the instance variable 'path' after successfull creation.
35
+ # Creates a thumbnail image (.png or .jpg) and returns the full file path of the thumbnail.
23
36
  # Raises a ScriptError if the thumbnail could not be created.
24
37
  # Raises a StandardError if the format is incorrect (i.e. P-file instead of DICOM)
25
- def create_thumbnail(output = nil)
38
+ #
39
+ # Be sure your filename is a valid unix filename - no spaces.
40
+ # Sets the @path instance variable and returns the full filename to the thumbnail.
41
+ #
42
+ # Pass in either a absolute or relative path or filename for the output image,
43
+ # and an options hash to manually specify the processor (Ruby Dicom or FSL Slicer).
44
+ # {:processor => :rubydicom or :slicer}
45
+ #
46
+ def create_thumbnail(output = nil, options = {:processor => :rubydicom})
26
47
  raise StandardError, "Thumbnail available only for DICOM format." unless dataset.raw_image_files.first.dicom?
27
48
  if output
28
49
  if File.directory?(output)
29
- output_directory = output.escape_filename
50
+ # output is a directory. Set the output directory but leave filepath nil.
51
+ output_directory = output.escape_dirname
30
52
  else
31
- output_directory = File.dirname(output).escape_filename
32
- png_filename = File.basename(output).escape_filename
53
+ # output is a path. Set the output_directory and specify that the full filepath is already complete.
54
+ output_directory = File.dirname(output).escape_dirname
55
+ filepath = output
33
56
  end
34
57
  else
58
+ # If no output was given, default to a new temp directory.
35
59
  output_directory = Dir.mktmpdir
36
60
  end
37
- name = @dataset.series_description.escape_filename
38
- png_filename ||= File.join(output_directory, name + '.png')
39
- nifti_filename ||= File.join(output_directory, name + '.nii')
61
+
62
+ @processor = options[:processor]
63
+
64
+ # Set a default filepath unless one was explicitly passed in.
65
+ default_name = @dataset.series_description.escape_filename
66
+ filepath ||= File.join(output_directory, default_name + '.png')
40
67
 
41
68
  begin
42
- @path = create_thumbnail_with_rubydicom(png_filename)
69
+ case @processor
70
+ when :rubydicom
71
+ @path = create_thumbnail_with_rubydicom(filepath)
72
+ when :slicer
73
+ @path = create_thumbnail_with_fsl_slicer(filepath)
74
+ end
43
75
  rescue RangeError, ScriptError => e
44
- puts "Could not create thumbnail with rubydicom. Trying FSL slicer."
45
- @path = create_thumbnail_with_fsl_slicer(output_directory, nifti_filename, png_filename)
76
+ unless @processor == :slicer
77
+ puts "Could not create thumbnail with rubydicom. Trying FSL slicer."
78
+ @processor = :slicer
79
+ retry
80
+ else
81
+ raise e
82
+ end
46
83
  end
47
84
 
85
+ raise ScriptError, "Could not create thumbnail from #{@dataset.series_description} - #{File.join(@dataset.directory, @dataset.scanned_file)}" unless @path && File.readable?(@path)
48
86
  return @path
49
87
  end
50
88
 
51
89
  private
52
90
 
53
- def create_thumbnail_with_rubydicom(output_file = nil)
54
- unless output_file && File.writable?(File.dirname(output_file))
55
- output_file = File.join(Dir.mktmpdir, dataset.series_description.escape_filename + '.jpg')
56
- end
91
+ # Creates a thumbnail using RubyDicom
92
+ # Pass in an absolute or relative filepath, including filename and extension.
93
+ # Returns an absolute path to the created thumbnail image.
94
+ def create_thumbnail_with_rubydicom(output_file)
95
+ output_file = File.expand_path(output_file)
57
96
 
58
97
  dicom_files = Dir.glob(File.join(dataset.directory, dataset.glob))
59
98
  if dicom_files.empty? # Try the glob again with a zipped extension.
@@ -67,29 +106,30 @@ class RawImageDatasetThumbnail
67
106
  dcm = DICOM::DObject.new(lc.to_s)
68
107
  raise ScriptError, "Could not read dicom #{dicom_file.to_s}" unless dcm.read_success
69
108
  image = dcm.get_image_magick(:rescale => true)
70
- raise ScriptError, "RubyDicom did not return an image array (this is probably a color image)." unless image
71
- image[0].write(output_file)
109
+ raise ScriptError, "RubyDicom did not return an image array (this is probably a color image)." unless image.kind_of? Magick::Image
110
+ image.write(output_file)
72
111
  end
73
112
 
113
+ raise(ScriptError, "Error creating thumbnail #{output_file}") unless File.exist?(output_file)
114
+
74
115
  return output_file
75
116
  end
76
117
 
77
- def create_thumbnail_with_fsl_slicer(output_directory, nifti_filename, png_filename)
78
- nii_path = File.join(output_directory, nifti_filename)
79
- @path = File.join(output_directory, png_filename)
118
+ # Creates a thumbnail using FSL's Slicer bash utility.
119
+ # Pass in an output filepath.
120
+ def create_thumbnail_with_fsl_slicer(output_file)
121
+ nii_tmpdir = Dir.mktmpdir
122
+ nifti_output_file = File.basename(output_file, File.extname(output_file)) + '.nii'
80
123
  Pathname.new(dataset.directory).all_dicoms do |dicom_files|
81
124
  # First Create a Nifti File to read
82
- @dataset.to_nifti!(output_directory, nifti_filename, {:input_directory => File.dirname(dicom_files.first)} )
125
+ @dataset.to_nifti!(nii_tmpdir, nifti_output_file, {:input_directory => File.dirname(dicom_files.first)} )
83
126
  end
84
-
85
-
86
-
87
127
  # Then create the .png
88
- `slicer #{nii_path} -a #{@path}`
128
+ `slicer #{File.join(nii_tmpdir, nifti_output_file)} -a #{output_file}`
89
129
 
90
- raise(ScriptError, "Error creating thumbnail #{@path}") unless File.exist?(@path)
130
+ raise(ScriptError, "Error creating thumbnail #{output_file}") unless File.exist?(output_file)
91
131
 
92
- return @path
132
+ return output_file
93
133
  end
94
134
 
95
135
  end
@@ -1,7 +1,8 @@
1
-
1
+ require 'pp'
2
2
  require 'rubygems';
3
3
  require 'yaml';
4
4
  require 'sqlite3';
5
+ require 'dicom'
5
6
 
6
7
  =begin rdoc
7
8
  Implements a collection of metadata associated with a raw image file. In
@@ -17,6 +18,7 @@ class RawImageFile
17
18
  MIN_HDR_LENGTH = 400
18
19
  DICOM_HDR = "dicom_hdr"
19
20
  RDGEHDR = "rdgehdr"
21
+ RUBYDICOM_HDR = "rubydicom"
20
22
  MONTHS = {
21
23
  :jan => "01", :feb => "02", :mar => "03", :apr => "04", :may => "05",
22
24
  :jun => "06", :jul => "07", :aug => "08", :sep => "09", :oct => "10",
@@ -61,6 +63,14 @@ class RawImageFile
61
63
  attr_reader :bold_reps
62
64
  # Import Warnings - Fields that could not be read.
63
65
  attr_reader :warnings
66
+ # Serialized RubyDicomHeader Object (for DICOMs only)
67
+ attr_reader :dicom_header
68
+ # DICOM Sequence UID
69
+ attr_reader :dicom_sequence_uid
70
+ # DICOM Series UID
71
+ attr_reader :dicom_series_uid
72
+ # DICOM Study UID
73
+ attr_reader :dicom_study_uid
64
74
 
65
75
  =begin rdoc
66
76
  Creates a new instance of the class given a path to a valid image file.
@@ -82,7 +92,6 @@ temporary file.
82
92
  # try to read the header, raise an IOError if unsuccessful
83
93
  begin
84
94
  @hdr_data, @hdr_reader = read_header(absfilepath)
85
- #puts "@hdr_data: #{@hdr_data}; @hdr_reader: #{@hdr_reader}"
86
95
  rescue Exception => e
87
96
  raise(IOError, "Header not readable for file #{@filename}. #{e}")
88
97
  end
@@ -250,12 +259,15 @@ private
250
259
 
251
260
  =begin rdoc
252
261
  Reads the file header using one of the available header reading utilities.
253
- Returns both the header data as a one big string, and the name of the utility
262
+ Returns both the header data as either a RubyDicom object or one big string, and the name of the utility
254
263
  used to read it.
255
264
 
256
265
  Note: The rdgehdr is a binary file; the correct version for your architecture must be installed in the path.
257
266
  =end
258
267
  def read_header(absfilepath)
268
+ # header = DICOM::DObject.new(absfilepath)
269
+ # return [header, RUBYDICOM_HDR] if defined? header.read_success && header.read_success
270
+
259
271
  header = `#{DICOM_HDR} '#{absfilepath}' 2> /dev/null`
260
272
  #header = `#{DICOM_HDR} #{absfilepath}`
261
273
  if ( header.index("ERROR") == nil and
@@ -292,11 +304,21 @@ Parses the header data and extracts a collection of instance variables. If
292
304
  =end
293
305
  def import_hdr
294
306
  raise(IndexError, "No Header Data Available.") if @hdr_data == nil
295
- dicom_hdr_import if (@hdr_reader == "dicom_hdr")
296
- rdgehdr_import if (@hdr_reader == "rdgehdr")
307
+ case @hdr_reader
308
+ when "rubydicom" then rubydicom_hdr_import
309
+ when "dicom_hdr" then dicom_hdr_import
310
+ when "rdgehdr" then rdgehdr_import
311
+ end
297
312
  end
298
313
 
299
314
 
315
+ =begin rdoc
316
+ Extract a collection of metadata from @hdr_data retrieved using RubyDicom
317
+ =end
318
+ def rubydicom_hdr_import
319
+
320
+ end
321
+
300
322
  =begin rdoc
301
323
  Extracts a collection of metadata from @hdr_data retrieved using the dicom_hdr
302
324
  utility.
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.22"
8
+ s.version = "0.1.23"
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-10-05}
12
+ s.date = %q{2010-11-16}
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"]
@@ -40,6 +40,10 @@ Gem::Specification.new do |s|
40
40
  "lib/metamri/visit_raw_data_directory_resource.rb",
41
41
  "metamri.gemspec",
42
42
  "test/fixtures/respiratory_fixtures.yaml",
43
+ "test/fixtures/s03_bravo.0156",
44
+ "test/fixtures/thumbnail.png",
45
+ "test/fixtures/thumbnail_slicer.png",
46
+ "test/helper_spec.rb",
43
47
  "test/nifti_builder_spec.rb",
44
48
  "test/raw_image_dataset_test.rb",
45
49
  "test/raw_image_dataset_thumbnail_spec.rb",
@@ -58,7 +62,8 @@ Gem::Specification.new do |s|
58
62
  "test/raw_image_file_test.rb",
59
63
  "test/visit_duplication_test.rb",
60
64
  "test/visit_test.rb",
61
- "test/raw_image_dataset_thumbnail_spec.rb"
65
+ "test/raw_image_dataset_thumbnail_spec.rb",
66
+ "test/helper_spec.rb"
62
67
  ]
63
68
 
64
69
  if s.respond_to? :specification_version then
Binary file
Binary file
Binary file
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ require 'tmpdir'
10
+ require 'fileutils'
11
+ require 'yaml'
12
+ require 'pp'
13
+ require 'rubygems'
14
+
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+
17
+ $MRI_DATA = ENV['MRI_DATA'] || '/Data/vtrak1/raw/test/fixtures/metamri'
18
+
@@ -1,9 +1,8 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
2
 
3
3
  require 'spec'
4
+ require 'helper_spec'
4
5
  require 'escoffier'
5
- require 'tmpdir'
6
- # require 'metamri'
7
6
  require 'metamri/core_additions'
8
7
  require 'metamri/raw_image_dataset'
9
8
  require 'metamri/raw_image_file'
@@ -20,14 +19,17 @@ describe "Create a thumbnail png for display." do
20
19
  # FileUtils.cp_r(VISIT_FIXTURE, VISIT_FIXTURE_UNZIPPED)
21
20
  # `find #{VISIT_FIXTURE_UNZIPPED} -name '*.bz2' -exec bunzip2 {} \\;`
22
21
  # end
23
- @fixture_path = '/Data/vtrak1/raw/johnson.merit220.visit1/mrt00033_830_04232010/dicoms/s10_cubet2'
22
+ @fixture_path = File.join($MRI_DATA, 'mrt00000_000_010101', 'dicoms', 's10_cubet2')
24
23
  end
25
24
 
26
25
  before(:each) do
27
- tmpdir = Dir.mktmpdir
28
- Pathname.new(@fixture_path).prep_mise_to(tmpdir)
29
- @dataset_wd = File.join(tmpdir, File.basename(@fixture_path))
26
+ @tmpdir = Dir.mktmpdir
27
+ Pathname.new(@fixture_path).prep_mise_to(@tmpdir)
28
+ @dataset_wd = File.join(@tmpdir, File.basename(@fixture_path))
30
29
  @ds = RawImageDataset.new(@dataset_wd, RawImageFile.new(File.join(@dataset_wd, 's10_cubet2.0001')))
30
+ @valid_thumbnail = File.join('fixtures', 'thumbnail.png')
31
+ @valid_thumbnail_slicer = File.join('fixtures', 'thumbnail_slicer.png')
32
+ @test_niftis = []
31
33
  end
32
34
 
33
35
  it "should create a thumbnail in a tmpdir without a specified path." do
@@ -36,6 +38,7 @@ describe "Create a thumbnail png for display." do
36
38
 
37
39
  File.basename(t.path).should == 'Sag-CUBE-T2.png'
38
40
  File.exist?(t.path).should be_true
41
+ File.compare(@valid_thumbnail, t.path).should be true
39
42
  end
40
43
 
41
44
  it "should create a thumbnail with a specified path." do
@@ -47,10 +50,11 @@ describe "Create a thumbnail png for display." do
47
50
 
48
51
  t.path.should == output_filename
49
52
  File.exist?(t.path).should be_true
53
+ File.compare(@valid_thumbnail, t.path).should be true
50
54
 
51
55
  end
52
56
 
53
- it "should create a thumbnail with a specified path and filename." do
57
+ it "should create a thumbnail with an absolute path to file." do
54
58
  output_filename = "/tmp/test.png"
55
59
  File.delete(output_filename) if File.exist?(output_filename)
56
60
 
@@ -59,18 +63,40 @@ describe "Create a thumbnail png for display." do
59
63
 
60
64
  t.path.should == '/tmp/test.png'
61
65
  File.exist?(t.path).should be_true
66
+ File.compare(@valid_thumbnail, t.path).should be true
62
67
  end
63
68
 
69
+ it "should create a thumbnail with a relative path to file." do
70
+ output_filename = "test.png"
71
+ File.delete(output_filename) if File.exist?(output_filename)
72
+
73
+ t = RawImageDatasetThumbnail.new(@ds)
74
+ t.create_thumbnail(output_filename)
75
+
76
+ File.exist?(t.path).should be_true
77
+ File.compare(@valid_thumbnail, t.path).should be true
78
+ end
79
+
80
+
64
81
  it "should raise a ScriptError if the file could not be created." do
65
82
  t = RawImageDatasetThumbnail.new(@ds)
66
83
 
67
84
  File.stub!(:exist?).and_return(false)
68
- lambda { t.create_thumbnail }.should raise_error(ScriptError, /Error creating thumbnail/ )
85
+ lambda { t.create_thumbnail }.should raise_error(ScriptError, /Error creating thumbnail/ )
86
+ end
87
+
88
+ it "should create a thumbnail in a tmpdir without a specified path using FSL Slicer." do
89
+ t = RawImageDatasetThumbnail.new(@ds)
90
+ t.create_thumbnail(nil, {:processor => :slicer})
91
+
92
+ File.basename(t.path).should == 'Sag-CUBE-T2.png'
93
+ File.exist?(t.path).should be_true
94
+ File.compare(@valid_thumbnail_slicer, t.path).should be true
69
95
  end
70
96
 
71
97
  after(:each) do
72
98
  # @test_niftis.flatten.each { |nifti| File.delete(nifti) } unless @test_niftis.empty?
73
- # [@output_directories, Dir.tmpdir, '/tmp'].flatten.each do |temp_dir|
99
+ # [@output_directories, @tmpdir, '/tmp'].flatten.each do |temp_dir|
74
100
  # Dir.foreach(temp_dir) {|f| File.delete(File.join(temp_dir, f)) if File.extname(f) == '.nii'}
75
101
  # end
76
102
  end
@@ -8,15 +8,16 @@ require 'metamri/raw_image_file'
8
8
 
9
9
  class RawImageFileTest < Test::Unit::TestCase
10
10
  def setup
11
- @GE_IFile = 'fixtures/I.001'
12
- @Dicom = 'fixtures/S4_EFGRE3D.0001'
13
- @EarlyGEPfile = 'fixtures/P59392.7'
14
- @LateGEPfile = 'fixtures/P27648.7'
15
- @notafile = 'fixtures/XXX.XXX'
16
- @ged = RawImageFile.new(@GE_IFile)
17
- @did = RawImageFile.new(@Dicom)
18
- @egep = RawImageFile.new(@EarlyGEPfile)
19
- @lgep = RawImageFile.new(@LateGEPfile)
11
+ # @GE_IFile = 'fixtures/I.001'
12
+ # @Dicom = 'fixtures/S4_EFGRE3D.0001'
13
+ # @EarlyGEPfile = 'fixtures/P59392.7'
14
+ # @LateGEPfile = 'fixtures/P27648.7'
15
+ # @notafile = 'fixtures/XXX.XXX'
16
+ # @ged = RawImageFile.new(@GE_IFile)
17
+ # @did = RawImageFile.new(@Dicom)
18
+ # @egep = RawImageFile.new(@EarlyGEPfile)
19
+ # @lgep = RawImageFile.new(@LateGEPfile)
20
+ @RubyDicom = 'fixtures/s03_bravo.0156'
20
21
  end
21
22
 
22
23
  def test_gehdr_dicom_init
@@ -29,6 +30,11 @@ class RawImageFileTest < Test::Unit::TestCase
29
30
  RawImageFile.new(@Dicom)
30
31
  end
31
32
  end
33
+ def test_rubydicom_dicom_init
34
+ assert_nothing_raised do
35
+ RawImageFile.new(@RubyDicom)
36
+ end
37
+ end
32
38
  def test_early_gehdr_pfile_init
33
39
  assert_nothing_raised do
34
40
  RawImageFile.new(@EarlyGEPfile)
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 22
9
- version: 0.1.22
8
+ - 23
9
+ version: 0.1.23
10
10
  platform: ruby
11
11
  authors:
12
12
  - Kristopher J. Kosmatka
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-05 00:00:00 -05:00
17
+ date: 2010-11-16 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -89,6 +89,10 @@ files:
89
89
  - lib/metamri/visit_raw_data_directory_resource.rb
90
90
  - metamri.gemspec
91
91
  - test/fixtures/respiratory_fixtures.yaml
92
+ - test/fixtures/s03_bravo.0156
93
+ - test/fixtures/thumbnail.png
94
+ - test/fixtures/thumbnail_slicer.png
95
+ - test/helper_spec.rb
92
96
  - test/nifti_builder_spec.rb
93
97
  - test/raw_image_dataset_test.rb
94
98
  - test/raw_image_dataset_thumbnail_spec.rb
@@ -132,3 +136,4 @@ test_files:
132
136
  - test/visit_duplication_test.rb
133
137
  - test/visit_test.rb
134
138
  - test/raw_image_dataset_thumbnail_spec.rb
139
+ - test/helper_spec.rb