Class: RTKIT::DataSet

Inherits:
Object
  • Object
show all
Defined in:
lib/rtkit/data_set.rb

Overview

Handles the DICOM data found at a particular location, typically all files contained in a specific directory. A DataSet contains all DICOM objects read from the specified source, organized in a patient - study - series - image structure.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDataSet

Creates a new DataSet instance.



106
107
108
109
110
111
112
# File 'lib/rtkit/data_set.rb', line 106

def initialize
  # Create instance variables:
  @frames = Array.new
  @patients = Array.new
  @associated_frames = Hash.new
  @associated_patients = Hash.new
end

Instance Attribute Details

#framesObject (readonly)

An array of Frame instances loaded for this DataSet.



25
26
27
# File 'lib/rtkit/data_set.rb', line 25

def frames
  @frames
end

#patientsObject (readonly)

An array of Patient instances loaded for this DataSet.



27
28
29
# File 'lib/rtkit/data_set.rb', line 27

def patients
  @patients
end

Class Method Details

.load(objects) ⇒ Object

Creates (and returns) a new DataSet instance from an array of DICOM objects.

Parameters

  • objects – An array of DICOM::DObject instances which will be loaded into the DataSet.

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rtkit/data_set.rb', line 35

def self.load(objects)
  raise ArgumentError, "Invalid argument 'objects'. Expected Array, got #{objects.class}." unless objects.is_a?(Array)
  raise ArgumentError, "Invalid argument 'objects'. Expected Array to contain only DObjects, got #{objects.collect{|dcm| dcm.class}.uniq}." if objects.collect{|dcm| dcm.class}.uniq != [DICOM::DObject]
  # We will put the objects in arrays sorted by modality, to control
  # the sequence in which they are loaded in our data structure:
  images = Array.new
  structs = Array.new
  plans = Array.new
  doses = Array.new
  rtimages = Array.new
  # Read and sort:
  objects.each do |dcm|
    # Find out which modality our DICOM file is and handle it accordingly:
    modality = dcm.value("0008,0060")
    case modality
      when *IMAGE_SERIES
        images << dcm
      when 'RTSTRUCT'
        structs << dcm
      when 'RTPLAN'
        plans << dcm
      when 'RTDOSE'
        doses << dcm
      when 'RTIMAGE'
        rtimages << dcm
      else
        #puts "Notice: Unsupported modality (ignored): #{modality}"
    end
  end
  # Create the DataSet:
  ds = DataSet.new
  # Add the objects to our data structure in a specific sequence:
  [images, structs, plans, doses, rtimages].each do |modality|
    modality.each do |dcm|
      ds.add(dcm)
    end
  end
  return ds
end

.read(path) ⇒ Object

Creates (and returns) a new DataSet instance from a specified path, by reading and loading the DICOM files found in this directory (including its sub-directories).

Parameters

  • path – A path to the directory containing the DICOM files you want to load.

Raises:

  • (ArgumentError)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rtkit/data_set.rb', line 82

def self.read(path)
  raise ArgumentError, "Invalid argument 'path'. Expected String, got #{path.class}." unless path.is_a?(String)
  # Get the files:
  files = RTKIT.files(path)
  raise ArgumentError, "No files found in the specified folder: #{path}" unless files.length > 0
  # Load DICOM objects:
  objects = Array.new
  failed = Array.new
  files.each do |file|
    dcm = DICOM::DObject.read(file)
    if dcm.read?
      objects << dcm
    else
      failed << file
      #puts "Warning: A file was not successfully read as a DICOM object. (#{file})"
    end
  end
  raise ArgumentError, "No DICOM files were successfully read from the specified folder: #{path}" unless objects.length > 0
  # Create the DataSet:
  return DataSet.load(objects)
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Returns true if the argument is an instance with attributes equal to self.



116
117
118
119
120
# File 'lib/rtkit/data_set.rb', line 116

def ==(other)
  if other.respond_to?(:to_data_set)
    other.send(:state) == state
  end
end

#add(dcm) ⇒ Object

Adds a DICOM object to the dataset, by adding it to an existing Patient, or creating a new Patient.

Restrictions

To ensure a correct relationship between objects of different modality, please add DICOM objects in the specific order: images, structs, plans, doses, rtimages Alternatively, use the class method DataSet.load(objects), which handles this automatically.



133
134
135
136
137
138
139
140
141
# File 'lib/rtkit/data_set.rb', line 133

def add(dcm)
  id = dcm.value(PATIENTS_ID)
  p = patient(id)
  if p
    p.add(dcm)
  else
    add_patient(Patient.load(dcm, self))
  end
end

#add_frame(frame) ⇒ Object

Adds a Frame to this DataSet.

Raises:

  • (ArgumentError)


145
146
147
148
149
150
# File 'lib/rtkit/data_set.rb', line 145

def add_frame(frame)
  raise ArgumentError, "Invalid argument 'frame'. Expected Frame, got #{frame.class}." unless frame.is_a?(Frame)
  # Do not add it again if the frame already belongs to this instance:
  @frames << frame unless @associated_frames[frame.uid]
  @associated_frames[frame.uid] = frame
end

#add_patient(patient) ⇒ Object

Adds a Patient to this DataSet.

Raises:

  • (ArgumentError)


154
155
156
157
158
159
# File 'lib/rtkit/data_set.rb', line 154

def add_patient(patient)
  raise ArgumentError, "Invalid argument 'patient'. Expected Patient, got #{patient.class}." unless patient.is_a?(Patient)
  # Do not add it again if the patient already belongs to this instance:
  @patients << patient unless @associated_patients[patient.id]
  @associated_patients[patient.id] = patient
end

#frame(*args) ⇒ Object

Returns the Frame instance mathcing the specified Frame’s UID (if an UID argument is used). If a specified UID doesn’t match, nil is returned. If no argument is passed, the first Frame instance associated with the DataSet is returned.

Parameters

  • uid – String. The Frame of Reference UID.

Raises:

  • (ArgumentError)


169
170
171
172
173
174
175
176
177
178
# File 'lib/rtkit/data_set.rb', line 169

def frame(*args)
  raise ArgumentError, "Expected one or none arguments, got #{args.length}." unless [0, 1].include?(args.length)
  if args.length == 1
    raise ArgumentError, "Expected String (or nil), got #{args.first.class}." unless [String, NilClass].include?(args.first.class)
    return @associated_frames[args.first]
  else
    # No argument used, therefore we return the first Frame instance:
    return @frames.first
  end
end

#hashObject

Generates a Fixnum hash value for this instance.



182
183
184
# File 'lib/rtkit/data_set.rb', line 182

def hash
  state.hash
end

#patient(*args) ⇒ Object

Returns the Patient instance mathcing the specified Patient’s ID (if an ID argument is used). If a specified ID doesn’t match, nil is returned. If no argument is passed, the first Patient instance associated with the DataSet is returned.

Parameters

  • id – String. The value of the Patient’s ID element.

Raises:

  • (ArgumentError)


194
195
196
197
198
199
200
201
202
203
# File 'lib/rtkit/data_set.rb', line 194

def patient(*args)
  raise ArgumentError, "Expected one or none arguments, got #{args.length}." unless [0, 1].include?(args.length)
  if args.length == 1
    raise ArgumentError, "Expected String (or nil), got #{args.first.class}." unless [String, NilClass].include?(args.first.class)
    return @associated_patients[args.first]
  else
    # No argument used, therefore we return the first Patient instance:
    return @patients.first
  end
end

Prints the nested structure of patient - study - series - images that have been loaded to the dataset instance.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/rtkit/data_set.rb', line 207

def print
  @patients.each do |p|
    puts p.name
    p.studies.each do |st|
      puts "  #{st.uid}"
      st.series.each do |se|
        puts "    #{se.modality}"
        if se.images
          puts "      (#{se.images.length} images)"
        end
      end
    end
  end
end

Prints the nested structure of patient - study - modalities from a RT point of view, with image_series - ss - plan, etc.



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/rtkit/data_set.rb', line 225

def print_rt
  @patients.each do |p|
    puts p.name
    p.studies.each do |st|
      puts "  #{st.uid}"
      st.image_series.each do |is|
        puts "    #{is.modality} (#{is.images.length} images)"
        is.structs.each do |struct|
          puts "      StructureSet"
          struct.plans.each do |plan|
            puts "        RTPlan"
            puts "          RTDose" if plan.dose
            puts "          RTImage" if plan.rtimage
          end
        end
      end
    end
  end
end

#to_data_setObject

Returns self.



247
248
249
# File 'lib/rtkit/data_set.rb', line 247

def to_data_set
  self
end