Class: RTKIT::BinVolume

Inherits:
PixelData show all
Defined in:
lib/rtkit/bin_volume.rb

Overview

Contains the DICOM data and methods related to a binary volume.

Inheritance

  • As the BinVolume class inherits from the PixelData class, all PixelData methods are available to instances of BinVolume.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PixelData

#coordinates_from_indices, #coordinates_to_indices, #draw_lines, #flood_fill, #indices_general_to_specific, #indices_specific_to_general, #print_img

Constructor Details

#initialize(series, options = {}) ⇒ BinVolume

Creates a new BinVolume instance.

Parameters

  • series – The image series (e.g. ImageSeries or DoseVolume) which forms the reference data of the BinVolume.

  • options – A hash of parameters.

Options

  • :images – An array of BinImage instances that is assigned to this BinVolume.

  • :source – The object which is the source of the binary (segmented) data (i.e. ROI or Dose/Hounsfield threshold).

Raises:

  • (ArgumentError)


136
137
138
139
140
141
142
143
144
# File 'lib/rtkit/bin_volume.rb', line 136

def initialize(series, options={})
  raise ArgumentError, "Invalid argument 'series'. Expected ImageSeries or DoseVolume, got #{series.class}." unless [ImageSeries, DoseVolume].include?(series.class)
  raise ArgumentError, "Invalid option 'images'. Expected Array, got #{options[:images].class}." if options[:images] && options[:images].class != Array
  raise ArgumentError, "Invalid option 'source'. Expected ROI or RTDose, got #{options[:source].class}." if options[:source] && ![ROI, RTDose].include?(options[:source].class)
  raise ArgumentError, "Invalid option 'images'. Expected only BinImage instances in the array, got #{options[:images].collect{|i| i.class}.uniq}." if options[:images] && options[:images].collect{|i| i.class}.uniq.length > 1
  @series = series
  @bin_images = options[:images] || Array.new
  @source = options[:source]
end

Instance Attribute Details

#bin_imagesObject (readonly)

An array of BinImage references.



12
13
14
# File 'lib/rtkit/bin_volume.rb', line 12

def bin_images
  @bin_images
end

#diceObject

Dice’s Coeffecient.



14
15
16
# File 'lib/rtkit/bin_volume.rb', line 14

def dice
  @dice
end

#narrObject

A NArray associated with this BinVolume (NB! This is a cached copy. If you want to ensure to extract an narray which corresponds to the BinVolume’s Images, use the narray method instead.



17
18
19
# File 'lib/rtkit/bin_volume.rb', line 17

def narr
  @narr
end

#sensitivityObject

A score (fraction) of the segmented volume compared to a master volume, ranging from 0 (worst) to 1 (all true voxels segmented in this volume).



19
20
21
# File 'lib/rtkit/bin_volume.rb', line 19

def sensitivity
  @sensitivity
end

#seriesObject (readonly)

The BinVolume’s series reference (e.g. ImageSeries or DoseVolume).



21
22
23
# File 'lib/rtkit/bin_volume.rb', line 21

def series
  @series
end

#sourceObject (readonly)

A reference to the source of this BinaryVolume (ROI or Dose instance).



23
24
25
# File 'lib/rtkit/bin_volume.rb', line 23

def source
  @source
end

#specificityObject

A score (fraction) of the segmented volume compared to a master volume, ranging from 0 (worst) to 1 (none of the true remaining voxels are segmented in this volume).



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

def specificity
  @specificity
end

Class Method Details

.from_dose(dose_volume, min = nil, max = nil, image_volume) ⇒ Object

Creates a new BinVolume instance from a DoseVolume. The BinVolume is typically defined from a ROI delineation against an image series, but it may also be applied to an rtdose ‘image’ series. Returns the BinVolume instance.

Notes

  • Even though listed as optional parameters, at least one of the min and max options must be specified in order to construct a valid binary volume.

Parameters

  • image_volume – The image volume which the binary volume will be based on (a DoseVolume or an ImageSeries).

  • min – Float. An optional lower dose limit from which to define the the binary volume.

  • max – Float. An optional upper dose limit from which to define the the binary volume.

Raises:

  • (ArgumentError)


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
74
# File 'lib/rtkit/bin_volume.rb', line 43

def self.from_dose(dose_volume, min=nil, max=nil, image_volume)
  raise ArgumentError, "Invalid argument 'dose_volume'. Expected DoseVolume, got #{dose_volume.class}." unless dose_volume.class == DoseVolume
  raise ArgumentError, "Invalid argument 'image_volume'. Expected ImageSeries or DoseVolume, got #{image_volume.class}." unless [ImageSeries, DoseVolume].include?(image_volume.class)
  raise ArgumentError "Need at least one dose limit parameter. Neither min nor max was specified." unless min or max
  # Create the BinVolume instance:
  bv = self.new(dose_volume) # FIXME: Specify dose limit somehow here?!
  # Add BinImages for each of the DoseVolume's images:
  dose_narr = dose_volume.dose_arr
  dose_volume.images.each_index do |i|
    #ref_image = image_volume.image(dose_img.pos_slice)
    ref_image = image_volume.images[i]
    dose_image = dose_narr[i, true, true]
    # Create the bin narray:
    narr = NArray.byte(ref_image.columns, ref_image.rows)
    if !min
      # Only the max limit is specified:
      marked_indices = (dose_image.le max.to_f)
    elsif !max
      # Only the min limit is specified:
      marked_indices = (dose_image.ge min.to_f)
    else
      # Both min and max limits are specified:
      smaller = (dose_image.le max.to_f)
      bigger = (dose_image.ge min.to_f)
      marked_indices = smaller.and bigger
    end
    narr[marked_indices] = 1
    bin_img = BinImage.new(narr, ref_image)
    bv.add(bin_img)
  end
  return bv
end

.from_roi(roi, image_volume) ⇒ Object

Creates a new BinVolume instance from a ROI. The BinVolume is typically defined from a ROI delineation against an image series, but it may also be applied to an rtdose ‘image’ series. Returns the BinVolume instance.

Parameters

  • roi – A ROI from which to define the binary volume.

  • image_volume – The image volume which the binary volume will be based on (an ImageSeries or a DoseVolume).

Raises:

  • (ArgumentError)


86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rtkit/bin_volume.rb', line 86

def self.from_roi(roi, image_volume)
  raise ArgumentError, "Invalid argument 'roi'. Expected ROI, got #{roi.class}." unless roi.is_a?(ROI)
  raise ArgumentError, "Invalid argument 'image_volume'. Expected ImageSeries or DoseVolume, got #{image_volume.class}." unless [ImageSeries, DoseVolume].include?(image_volume.class)
  # Create the BinVolume instance:
  bv = self.new(roi.image_series, :source => roi)
  # Add BinImages for each of the ROIs slices:
  roi.slices.each do |slice|
    image = image_volume.image(slice.pos)
    BinImage.from_contours(slice.contours, image, bv)
    #bv.add(slice.bin_image)
  end
  return bv
end

.from_volume(image_volume) ⇒ Object

Creates a new BinVolume instance from an image series (i.e. ImageSeries or DoseVolume). A BinVolume created this way specified the entire volume: i.e. the Binvolume has the same dimensions as the image series, and all pixels are 1. Returns the BinVolume instance.

Parameters

  • image_volume – The image volume which the binary volume will be based on (an ImageSeries or a DoseVolume).

Raises:

  • (ArgumentError)


109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rtkit/bin_volume.rb', line 109

def self.from_volume(image_volume)
  raise ArgumentError, "Invalid argument 'image_volume'. Expected ImageSeries or DoseVolume, got #{image_volume.class}." unless [ImageSeries, DoseVolume].include?(image_volume.class)
  # Create the BinVolume instance:
  bv = self.new(image_volume)
  # Add BinImages for each of the ROIs slices:
  image_volume.images.each do |image|
    # Make an NArray of proper size filled with ones:
    narr = NArray.byte(image.columns, image.rows).fill(1)
    # Create the BinImage instance and add it to the BinVolume:
    bin_img = BinImage.new(narr, image)
    bv.add(bin_img)
  end
  return bv
end

Instance Method Details

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

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



148
149
150
151
152
# File 'lib/rtkit/bin_volume.rb', line 148

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

#add(bin_image) ⇒ Object

Adds a BinImage instance to the volume.

Raises:

  • (ArgumentError)


158
159
160
161
# File 'lib/rtkit/bin_volume.rb', line 158

def add(bin_image)
  raise ArgumentError, "Invalid argument 'bin_image'. Expected BinImage, got #{bin_image.class}." unless bin_image.is_a?(BinImage)
  @bin_images << bin_image
end

#columnsObject

Returns the number of columns in the images of the volume.



165
166
167
# File 'lib/rtkit/bin_volume.rb', line 165

def columns
  return @bin_images.first.columns if @bin_images.first
end

#framesObject

Returns the number of frames (slices) in the set of images that makes up this volume.



171
172
173
# File 'lib/rtkit/bin_volume.rb', line 171

def frames
  return @bin_images.length
end

#hashObject

Generates a Fixnum hash value for this instance.



177
178
179
# File 'lib/rtkit/bin_volume.rb', line 177

def hash
  state.hash
end

#narray(sort_slices = true) ⇒ Object

Returns 3d volume array consisting of the 2d Narray images from the BinImage instances that makes up this volume. Returns nil if no BinImage instances are connected to this BinVolume.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/rtkit/bin_volume.rb', line 184

def narray(sort_slices=true)
  if @bin_images.length > 0
    # Determine the slice position of each BinImage:
    locations = Array.new
    if sort_slices
      @bin_images.collect {|image| locations << image.pos_slice}
      images = @bin_images.sort_by_order(locations.sort_order)
    else
      images = @bin_images
    end
    # Create volume array and fill in the images:
    volume = NArray.byte(frames, columns, rows)
    images.each_with_index do |sorted_image, i|
      volume[i, true, true] = sorted_image.narray
    end
    @narr = volume
  end
end

#reorder_images(order) ⇒ Object



203
204
205
# File 'lib/rtkit/bin_volume.rb', line 203

def reorder_images(order)
  @bin_images = @bin_images.sort_by_order(order)
end

#rowsObject

Returns the number of rows in the images of the volume.



209
210
211
# File 'lib/rtkit/bin_volume.rb', line 209

def rows
  return @bin_images.first.rows if @bin_images.first
end

#to_bin_volumeObject

Returns self.



215
216
217
# File 'lib/rtkit/bin_volume.rb', line 215

def to_bin_volume
  self
end

#to_roi(struct, options = {}) ⇒ Object

Creates a ROI instance from the segmentation of this BinVolume. Returns the ROI instance.

Parameters

  • struct – A StructureSet instance which the ROI will be connected to.

  • options – A hash of parameters.

Options

  • :algorithm – String. The ROI Generation Algorithm. Defaults to ‘Automatic’.

  • :name – String. The ROI Name. Defaults to ‘BinVolume’.

  • :number – Integer. The ROI Number. Defaults to the first available ROI Number in the StructureSet.

  • :interpreter – String. The ROI Interpreter. Defaults to ‘RTKIT’.

  • :type – String. The ROI Interpreted Type. Defaults to ‘CONTROL’.

Raises:

  • (ArgumentError)


235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/rtkit/bin_volume.rb', line 235

def to_roi(struct, options={})
  raise ArgumentError, "Invalid argument 'struct'. Expected StructureSet, got #{struct.class}." unless struct.is_a?(StructureSet)
  # Set values:
  algorithm = options[:algorithm]
  name = options[:name] || 'BinVolume'
  number = options[:number]
  interpreter = options[:interpreter]
  type = options[:type]
  # Create the ROI:
  roi = struct.create_roi(@series.frame, :algorithm => algorithm, :name => name, :number => number, :interpreter => interpreter, :type => type)
  # Create Slices:
  @bin_images.each do |bin_image|
    bin_image.to_slice(roi)
  end
  return roi
end