Class: RawImageFile

Inherits:
Object
  • Object
show all
Defined in:
lib/metamri/raw_image_file.rb

Overview

Implements a collection of metadata associated with a raw image file. In this case, by image we mean one single file. For the case of Pfiles one file corresponds to a complete 4D data set. For dicoms one file corresponds to a single 2D slice, many of which are assembled later during reconstruction to create a 4D data set. The motivation for this class is to provide access to the metadata stored in image file headers so that they can be later reconstructed into nifti data sets.

Primarily used to instantiate a #RawImageDataset

Constant Summary collapse

MIN_HDR_LENGTH =

:stopdoc:

400
DICOM_HDR =
"dicom_hdr"
RDGEHDR =
"rdgehdr"
PRINTRAW =
"printraw"
RUBYDICOM_HDR =
"rubydicom"
VALID_HEADERS =
[DICOM_HDR, PRINTRAW, RDGEHDR, RUBYDICOM_HDR]
MONTHS =
{
  :jan => "01", :feb => "02", :mar => "03", :apr => "04", :may => "05", 
  :jun => "06", :jul => "07", :aug => "08", :sep => "09", :oct => "10", 
  :nov => "11", :dec => "12" 
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pathtofile) ⇒ RawImageFile

Creates a new instance of the class given a path to a valid image file.

Throws IOError if the file given is not found or if the available header reading utilities cannot read the image header. Also raises IOError if any of the attributes cannot be found in the header. Be aware that the filename used to initialize your instance is used to set the “file” attribute. If you need to unzip a file to a temporary location, be sure to keep the same filename for the temporary file.

Raises:

  • (IOError)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/metamri/raw_image_file.rb', line 97

def initialize(pathtofile)
  # raise an error if the file doesn't exist
  absfilepath = File.expand_path(pathtofile)
  raise(IOError, "File not found at #{absfilepath}.") if not File.exists?(absfilepath)
  @filename = File.basename(absfilepath)
  @warnings = []
  
  # try to read the header, raise an IOError if unsuccessful
  begin
    @hdr_data, @hdr_reader = read_header(absfilepath)
  rescue Exception => e
    raise(IOError, "Header not readable for file #{@filename} using #{@current_hdr_reader ? @current_hdr_reader : "unknown header reader."}. #{e}")
  end
  
  # file type is based on file name but only if the header was read successfully
  @file_type = determine_file_type
  
  # try to import attributes from the header, raise an ScriptError or NoMethodError 
  # if any required attributes are not found
  begin
    import_hdr
  rescue ScriptError, NoMethodError => e
    # puts e.backtrace
    raise e, "Could not find required DICOM Header Meta Element: #{e}"
  rescue StandardError => e
    raise e, "Header import failed for file #{@filename}.  #{e} . Has the scanner software version changed? A new version of the p-file reading software (printraw or rdgehdr) might be needed. "
  end
  
  # deallocate the header data to save memory space.
  @hdr_data = nil
end

Instance Attribute Details

#acquisition_matrix_xObject (readonly)

Voxels in x axis.



65
66
67
# File 'lib/metamri/raw_image_file.rb', line 65

def acquisition_matrix_x
  @acquisition_matrix_x
end

#acquisition_matrix_yObject (readonly)

Voxels in y axis.



67
68
69
# File 'lib/metamri/raw_image_file.rb', line 67

def acquisition_matrix_y
  @acquisition_matrix_y
end

#bold_repsObject (readonly)

Number of bold reps in the complete functional task run.



71
72
73
# File 'lib/metamri/raw_image_file.rb', line 71

def bold_reps
  @bold_reps
end

#dicom_headerObject (readonly)

Serialized RubyDicomHeader Object (for DICOMs only)



75
76
77
# File 'lib/metamri/raw_image_file.rb', line 75

def dicom_header
  @dicom_header
end

#dicom_image_uidObject (readonly)

DICOM SOP Instance UID (from the scanned file)



79
80
81
# File 'lib/metamri/raw_image_file.rb', line 79

def dicom_image_uid
  @dicom_image_uid
end

#dicom_series_uidObject (readonly)

DICOM Series UID



81
82
83
# File 'lib/metamri/raw_image_file.rb', line 81

def dicom_series_uid
  @dicom_series_uid
end

#dicom_study_uidObject (readonly)

DICOM Study UID



83
84
85
# File 'lib/metamri/raw_image_file.rb', line 83

def dicom_study_uid
  @dicom_study_uid
end

#dicom_taghashObject (readonly)

Hash of all DICOM Tags including their Names and Values (See #dicom_taghash for more information on the structure)



77
78
79
# File 'lib/metamri/raw_image_file.rb', line 77

def dicom_taghash
  @dicom_taghash
end

#exam_numberObject (readonly)

An identifier unique to a Study Session - AKA Exam Number



46
47
48
# File 'lib/metamri/raw_image_file.rb', line 46

def exam_number
  @exam_number
end

#file_typeObject (readonly)

File types are either ‘dicom’ or ‘pfile’.



38
39
40
# File 'lib/metamri/raw_image_file.rb', line 38

def file_type
  @file_type
end

#filenameObject (readonly)

The file name that the instance represents.



34
35
36
# File 'lib/metamri/raw_image_file.rb', line 34

def filename
  @filename
end

#genderObject (readonly)

M or F.



55
56
57
# File 'lib/metamri/raw_image_file.rb', line 55

def gender
  @gender
end

#hdr_readerObject (readonly)

Which header reading utility reads this file, currently ‘rdgehdr’(old p-files&wimr) or ‘dicom_hdr’ or ‘printraw’(new p-files->waisman).



36
37
38
# File 'lib/metamri/raw_image_file.rb', line 36

def hdr_reader
  @hdr_reader
end

#num_slicesObject (readonly)

Number of slices in the data set that includes this file, used by AFNI for reconstruction.



57
58
59
# File 'lib/metamri/raw_image_file.rb', line 57

def num_slices
  @num_slices
end

#operator_nameObject (readonly)

Scan Tech Initials



85
86
87
# File 'lib/metamri/raw_image_file.rb', line 85

def operator_name
  @operator_name
end

#patient_nameObject (readonly)

Patient “Name”, usually StudyID or ENUM



87
88
89
# File 'lib/metamri/raw_image_file.rb', line 87

def patient_name
  @patient_name
end

#protocol_nameObject (readonly)

A short string describing the study protocol. These come from the scanner.



53
54
55
# File 'lib/metamri/raw_image_file.rb', line 53

def protocol_name
  @protocol_name
end

#reconstruction_diameterObject (readonly)

AKA Field of View, in millimeters.



63
64
65
# File 'lib/metamri/raw_image_file.rb', line 63

def reconstruction_diameter
  @reconstruction_diameter
end

#rep_timeObject (readonly)

Time for each bold repetition, relevent for functional scans.



69
70
71
# File 'lib/metamri/raw_image_file.rb', line 69

def rep_time
  @rep_time
end

#rmr_numberObject (readonly)

An identifier unique to a ‘visit’, these are assigned by the scanner techs at scan time.



44
45
46
# File 'lib/metamri/raw_image_file.rb', line 44

def rmr_number
  @rmr_number
end

#series_descriptionObject (readonly)

A short string describing the acquisition sequence. These come from the scanner. code and are used to initialise SeriesDescription objects to find related attributes.



49
50
51
# File 'lib/metamri/raw_image_file.rb', line 49

def series_description
  @series_description
end

#slice_spacingObject (readonly)

Gap between slices in millimeters.



61
62
63
# File 'lib/metamri/raw_image_file.rb', line 61

def slice_spacing
  @slice_spacing
end

#slice_thicknessObject (readonly)

Given in millimeters.



59
60
61
# File 'lib/metamri/raw_image_file.rb', line 59

def slice_thickness
  @slice_thickness
end

#sourceObject (readonly)

The scanner used to perform this scan, e.g. ‘Andys3T’.



42
43
44
# File 'lib/metamri/raw_image_file.rb', line 42

def source
  @source
end

#study_descriptionObject (readonly)

A short string describing the study sequence. These come from the scanner.



51
52
53
# File 'lib/metamri/raw_image_file.rb', line 51

def study_description
  @study_description
end

#timestampObject (readonly)

The date on which this scan was acquired, this is a ruby DateTime object.



40
41
42
# File 'lib/metamri/raw_image_file.rb', line 40

def timestamp
  @timestamp
end

#warningsObject (readonly)

Import Warnings - Fields that could not be read.



73
74
75
# File 'lib/metamri/raw_image_file.rb', line 73

def warnings
  @warnings
end

Instance Method Details

#db_fetchObject

Returns an SQL statement to select this image file row from the raw_image_files table of a compatible database.



201
202
203
# File 'lib/metamri/raw_image_file.rb', line 201

def db_fetch
  "SELECT *" + from_table_where + sql_match_conditions
end

#db_fetch!(db_file) ⇒ Object

Finds the row in the raw_image_files table of the given db file that matches this object. ORM is based on combination of rmr_number, timestamp, and filename. The row is returned as an array of values (see ‘sqlite3’ gem docs).



235
236
237
238
239
240
# File 'lib/metamri/raw_image_file.rb', line 235

def db_fetch!( db_file )
  db = SQLite3::Database.new( db_file )
  db_row = db.execute( db_fetch )
  db.close
  return db_row
end

#db_insert(image_dataset_id) ⇒ Object

Returns an SQL statement to insert this image into the raw_images table of a compatible database (sqlite3). This is intended for inserting into the rails backend database.



188
189
190
191
192
193
194
195
196
197
# File 'lib/metamri/raw_image_file.rb', line 188

def db_insert(image_dataset_id)
  "INSERT INTO raw_image_files
  (filename, header_reader, file_type, timestamp, source, rmr_number, series_description, 
  gender, num_slices, slice_thickness, slice_spacing, reconstruction_diameter, 
  acquisition_matrix_x, acquisition_matrix_y, rep_time, bold_reps, created_at, updated_at, image_dataset_id)
  VALUES ('#{@filename}', '#{@hdr_reader}', '#{@file_type}', '#{@timestamp.to_s}', '#{@source}', '#{@rmr_number}', 
  '#{@series_description}', '#{@gender}', #{@num_slices}, #{@slice_thickness}, #{@slice_spacing}, 
  #{@reconstruction_diameter}, #{@acquisition_matrix_x}, #{@acquisition_matrix_y}, #{@rep_time}, 
  #{@bold_reps}, '#{DateTime.now}', '#{DateTime.now}', #{image_dataset_id})"
end

#db_insert!(db_file) ⇒ Object

Uses the db_insert method to actually perform the database insert using the specified database file.



214
215
216
217
218
219
220
221
222
223
# File 'lib/metamri/raw_image_file.rb', line 214

def db_insert!( db_file )
  db = SQLite3::Database.new( db_file )
  db.transaction do |database|
    if not database.execute( db_fetch ).empty?
      raise(IndexError, "Entry exists for #{filename}, #{@rmr_number}, #{@timestamp.to_s}... Skipping.")
    end
    database.execute( db_insert )
  end
  db.close
end

#db_removeObject

Returns and SQL statement to remove this image file from the raw_image_files table of a compatible database.



207
208
209
# File 'lib/metamri/raw_image_file.rb', line 207

def db_remove
  "DELETE" + from_table_where + sql_match_conditions
end

#db_remove!(db_file) ⇒ Object

Removes this instance from the raw_image_files table of the specified database.



226
227
228
229
230
# File 'lib/metamri/raw_image_file.rb', line 226

def db_remove!( db_file )
  db = SQLite3::Database.new( db_file )
  db.execute( db_remove )
  db.close
end

#dicom?Boolean

Predicate simply returns true if “dicom” is stored in the img_type instance variable.

Returns:

  • (Boolean)


147
148
149
# File 'lib/metamri/raw_image_file.rb', line 147

def dicom?
  return @file_type == "dicom"
end

#geifile?Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/metamri/raw_image_file.rb', line 151

def geifile?
  return @file_type == "geifile"
end

#image?Boolean

Predicate method that tells whether or not the file is actually an image. This judgement is based on whether one of the available header reading utilities can actually read the header information.

Returns:

  • (Boolean)


134
135
136
# File 'lib/metamri/raw_image_file.rb', line 134

def image?
  return ( VALID_HEADERS.include? @hdr_reader )
end

#image_uidObject

The UID unique to the raw image file scanned



249
250
251
# File 'lib/metamri/raw_image_file.rb', line 249

def image_uid
  @dicom_image_uid || @image_uid
end

#pfile?Boolean

Predicate simply returns true if “pfile” is stored in the @img_type instance variable.

Returns:

  • (Boolean)


141
142
143
# File 'lib/metamri/raw_image_file.rb', line 141

def pfile?
  return @file_type == "pfile"
end

#series_uidObject

The series ID (dicom_series_uid [dicom] or series_uid [pfile/ifile]) This is unique for DICOM datasets, but not for PFiles



244
245
246
# File 'lib/metamri/raw_image_file.rb', line 244

def series_uid
  @dicom_series_uid || @series_uid
end

#to_arrayObject

Returns the internal, parsed data fields in an array. This is used when scanning dicom slices, to compare each dicom slice in a folder and make sure they all hold the same data.



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/metamri/raw_image_file.rb', line 171

def to_array
  return [@filename,
  @timestamp,
  @source,
  @rmr_number,
  @series_description,
  @gender,
  @slice_thickness,
  @slice_spacing,
  @reconstruction_diameter, 
  @acquisition_matrix_x,
  @acquisition_matrix_y]
end

#to_yamlObject

Returns a yaml string based on a subset of the attributes. Specifically, the @hdr_data is not included. This is used to generate .yaml files that are placed in image directories for later scanning by YamlScanner.



159
160
161
162
163
164
165
# File 'lib/metamri/raw_image_file.rb', line 159

def to_yaml
  yamlhash = {}
  instance_variables.each do |var|
    yamlhash[var[1..-1]] = instance_variable_get(var) if (var != "@hdr_data")
  end
  return yamlhash.to_yaml
end