metamri 0.1.22 → 0.1.23

Sign up to get free protection for your applications and to get access to all the features.
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