Class: RTKIT::DoseVolume
- Includes:
- ImageParent
- Defined in:
- lib/rtkit/dose_volume.rb
Overview
Contains the DICOM data and methods related to a pixel dose volume.
Inheritance
-
DoseVolume inherits all methods and attributes from the Series class.
Instance Attribute Summary collapse
-
#dcm ⇒ Object
readonly
The DObject instance of this dose Volume.
-
#dose_series ⇒ Object
readonly
The DoseSeries that this dose Volume belongs to.
-
#frame ⇒ Object
The Frame (of Reference) which this DoseVolume belongs to.
-
#images ⇒ Object
readonly
An array of dose pixel Image instances (frames) associated with this dose Volume.
-
#scaling ⇒ Object
The Dose Grid Scaling factor (float).
-
#sop_uid ⇒ Object
readonly
The SOP Instance UID.
Attributes inherited from Series
#class_uid, #date, #description, #modality, #series_uid, #study, #time
Class Method Summary collapse
-
.load(dcm, series) ⇒ Object
Creates a new Volume instance by loading image information from the specified DICOM object.
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
Returns true if the argument is an instance with attributes equal to self.
-
#add(dcm) ⇒ Object
Registers a DICOM Object to the dose Volume, and processes it to create (and reference) a (dose) Image instance (frame) linked to this dose Volume.
-
#add_image(image) ⇒ Object
Adds an Image to this Volume.
-
#bin_volume(options = {}) ⇒ Object
Creates a binary volume object consisting of a series of binary (dose thresholded) images, extracted from this dose volume.
-
#distribution(roi = nil) ⇒ Object
Returns the dose distribution for a specified ROI (or entire volume) and a specified beam (or all beams).
-
#dose_arr ⇒ Object
Returns the 3D dose pixel NArray retrieved from the #narray method, multiplied with the scaling coefficient, which in effect yields a 3D dose array.
-
#hash ⇒ Object
Generates a Fixnum hash value for this instance.
-
#image(*args) ⇒ Object
Returns the Image instance mathcing the specified SOP Instance UID (if an argument is used).
-
#initialize(sop_uid, frame, series, options = {}) ⇒ DoseVolume
constructor
Creates a new Volume instance.
-
#narray ⇒ Object
Builds a 3D dose pixel NArray from the dose images belonging to this DoseVolume.
-
#to_dose_volume ⇒ Object
Returns self.
Methods included from ImageParent
#slice_spacing, #update_image_position
Methods inherited from Series
Constructor Details
#initialize(sop_uid, frame, series, options = {}) ⇒ DoseVolume
Creates a new Volume instance. The SOP Instance UID tag value is used to uniquely identify a volume.
Parameters
-
sop_uid
– The SOP Instance UID string. -
frame
– The Frame instance that this DoseVolume belongs to. -
series
– The Series instance that this Image belongs to. -
options
– A hash of parameters.
Options
-
:sum
– Boolean. If true, the DoseVolume will not be added as a (beam) volume to the parent RTDose.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/rtkit/dose_volume.rb', line 60 def initialize(sop_uid, frame, series, ={}) raise ArgumentError, "Invalid argument 'sop_uid'. Expected String, got #{sop_uid.class}." unless sop_uid.is_a?(String) raise ArgumentError, "Invalid argument 'frame'. Expected Frame, got #{frame.class}." unless frame.is_a?(Frame) raise ArgumentError, "Invalid argument 'series'. Expected Series, got #{series.class}." unless series.is_a?(Series) raise ArgumentError, "Invalid argument 'series'. Expected Series to have an image related modality, got #{series.modality}." unless IMAGE_MODALITIES.include?(series.modality) # Pass attributes to Series initialization: super(series.uid, 'RTDOSE', series.study) # Key attributes: @sop_uid = sop_uid @frame = frame @dose_series = series # Default attributes: @images = Array.new @associated_images = Hash.new @image_positions = Hash.new # Register ourselves with the DoseSeries: @dose_series.add_volume(self) unless [:sum] # Register ourselves with the study & frame: #@study.add_series(self) @frame.add_series(self) end |
Instance Attribute Details
#dcm ⇒ Object (readonly)
The DObject instance of this dose Volume.
14 15 16 |
# File 'lib/rtkit/dose_volume.rb', line 14 def dcm @dcm end |
#dose_series ⇒ Object (readonly)
The DoseSeries that this dose Volume belongs to.
16 17 18 |
# File 'lib/rtkit/dose_volume.rb', line 16 def dose_series @dose_series end |
#frame ⇒ Object
The Frame (of Reference) which this DoseVolume belongs to.
18 19 20 |
# File 'lib/rtkit/dose_volume.rb', line 18 def frame @frame end |
#images ⇒ Object (readonly)
An array of dose pixel Image instances (frames) associated with this dose Volume.
20 21 22 |
# File 'lib/rtkit/dose_volume.rb', line 20 def images @images end |
#scaling ⇒ Object
The Dose Grid Scaling factor (float).
22 23 24 |
# File 'lib/rtkit/dose_volume.rb', line 22 def scaling @scaling end |
#sop_uid ⇒ Object (readonly)
The SOP Instance UID.
24 25 26 |
# File 'lib/rtkit/dose_volume.rb', line 24 def sop_uid @sop_uid end |
Class Method Details
.load(dcm, series) ⇒ Object
Creates a new Volume instance by loading image information from the specified DICOM object. The volume object’s SOP Instance UID string value is used to uniquely identify a volume.
Parameters
-
dcm
– An instance of a DICOM object (DObject). -
series
– The Series instance that this Volume belongs to.
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/rtkit/dose_volume.rb', line 34 def self.load(dcm, series) raise ArgumentError, "Invalid argument 'dcm'. Expected DObject, got #{dcm.class}." unless dcm.is_a?(DICOM::DObject) raise ArgumentError, "Invalid argument 'series'. Expected Series, got #{series.class}." unless series.is_a?(Series) raise ArgumentError, "Invalid argument 'dcm'. Expected an image related modality, got #{dcm.value(MODALITY)}." unless IMAGE_MODALITIES.include?(dcm.value(MODALITY)) sop_uid = dcm.value(SOP_UID) # Check if a Frame with the given UID already exists, and if not, create one: frame = series.study.patient.dataset.frame(dcm.value(FRAME_OF_REF)) || frame = series.study.patient.create_frame(dcm.value(FRAME_OF_REF), dcm.value(POS_REF_INDICATOR)) # Create the RTDose instance: volume = self.new(sop_uid, frame, series) volume.add(dcm) return volume end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
Returns true if the argument is an instance with attributes equal to self.
84 85 86 87 88 |
# File 'lib/rtkit/dose_volume.rb', line 84 def ==(other) if other.respond_to?(:to_dose_volume) other.send(:state) == state end end |
#add(dcm) ⇒ Object
Registers a DICOM Object to the dose Volume, and processes it to create (and reference) a (dose) Image instance (frame) linked to this dose Volume.
95 96 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 128 129 |
# File 'lib/rtkit/dose_volume.rb', line 95 def add(dcm) raise ArgumentError, "Invalid argument 'dcm'. Expected DObject, got #{dcm.class}." unless dcm.is_a?(DICOM::DObject) @dcm = dcm self.scaling = dcm.value(DOSE_GRID_SCALING) pixels = dcm.narray rows = dcm.value(ROWS) cols = dcm.value(COLUMNS) image_position = dcm.value(IMAGE_POSITION).split("\\") pos_x = image_position[0].to_f pos_y = image_position[1].to_f frame_origin = image_position[2].to_f cosines = dcm.value(IMAGE_ORIENTATION).split("\\").collect {|val| val.to_f} if dcm.value(IMAGE_ORIENTATION) spacing = dcm.value(SPACING).split("\\") col_spacing = spacing[1].to_f row_spacing = spacing[0].to_f nr_frames = dcm.value(NR_FRAMES).to_i frame_offsets = dcm.value(GRID_FRAME_OFFSETS).split("\\").collect {|value| value.to_f} sop_uids = RTKIT.sop_uids(nr_frames) # Iterate each frame and create dose images: nr_frames.times do |i| # Create an Image instance (using an arbitrary UID, as individual dose frames don't really have UIDs in DICOM): img = Image.new(sop_uids[i], self) # Fill in image information: img.columns = cols img.rows = rows img.pos_x = pos_x img.pos_y = pos_y img.pos_slice = frame_origin + frame_offsets[i] img.col_spacing = col_spacing img.row_spacing = row_spacing img.cosines = cosines # Fill in the pixel frame data: img.narray = pixels[i, true, true] end end |
#add_image(image) ⇒ Object
Adds an Image to this Volume.
133 134 135 136 137 138 |
# File 'lib/rtkit/dose_volume.rb', line 133 def add_image(image) raise ArgumentError, "Invalid argument 'image'. Expected Image, got #{image.class}." unless image.is_a?(Image) @images << image unless @associated_images[image.uid] @associated_images[image.uid] = image @image_positions[image.pos_slice] = image end |
#bin_volume(options = {}) ⇒ Object
Creates a binary volume object consisting of a series of binary (dose thresholded) images, extracted from this dose volume. Returns a BinVolume instance with binary image references equal to the number of dose images defined for this DoseVolume.
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
-
options
– A hash of parameters.
Options
-
:min
– Float. The lower dose threshold for dose elements to be included in the resulting dose bin volume. -
:max
– Float. The upper dose threshold for dose elements to be included in the resulting dose bin volume. -
:volume
– By default the BinVolume is created against the images of this DoseVolume. Optionally, an ImageSeries used by the ROI’s of this Study can be specified.
160 161 162 163 164 |
# File 'lib/rtkit/dose_volume.rb', line 160 def bin_volume(={}) raise ArgumentError, "Need at least one dose limit parameter. Neither :min nor :max was specified." unless [:min] or [:max] volume = [:volume] || self return BinVolume.from_dose(self, [:min], [:max], volume) end |
#distribution(roi = nil) ⇒ Object
Returns the dose distribution for a specified ROI (or entire volume) and a specified beam (or all beams).
Parameters
-
roi
– A specific ROI for which to evalute the dose in (if omitted, the entire volume is evaluted).
173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/rtkit/dose_volume.rb', line 173 def distribution(roi=nil) raise ArgumentError, "Invalid argument 'roi'. Expected ROI, got #{roi.class}." if roi && !roi.is_a?(ROI) raise ArgumentError, "Invalid argument 'roi'. The specified ROI does not have the same StructureSet parent as this DoseVolume." if roi && roi.struct != @dose_series.plan.struct if roi # Extract a binary volume from the ROI, based on this DoseVolume: bin_vol = roi.bin_volume(self) else # Create a binary volume which marks the entire dose volume: bin_vol = BinVolume.from_volume(self) end # Create a DoseDistribution from the BinVolume: dose_distribution = DoseDistribution.create(bin_vol) end |
#dose_arr ⇒ Object
Returns the 3D dose pixel NArray retrieved from the #narray method, multiplied with the scaling coefficient, which in effect yields a 3D dose array.
191 192 193 194 |
# File 'lib/rtkit/dose_volume.rb', line 191 def dose_arr # Convert integer array to float array and multiply: return narray.to_type(4) * @scaling end |
#hash ⇒ Object
Generates a Fixnum hash value for this instance.
198 199 200 |
# File 'lib/rtkit/dose_volume.rb', line 198 def hash state.hash end |
#image(*args) ⇒ Object
Returns the Image instance mathcing the specified SOP Instance UID (if an argument is used). If a specified UID doesn’t match, nil is returned. If no argument is passed, the first Image instance associated with the Volume is returned.
Parameters
-
uid_or_pos
– String/Float. The value of the SOP Instance UID element or the image position.
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/rtkit/dose_volume.rb', line 210 def image(*args) raise ArgumentError, "Expected one or none arguments, got #{args.length}." unless [0, 1].include?(args.length) if args.length == 1 if args.first.is_a?(Float) # Presumably an image position: return @image_positions[args.first] else # Presumably a uid string: return @associated_images[args.first && args.first.to_s] end else # No argument used, therefore we return the first Image instance: return @images.first end end |
#narray ⇒ Object
Builds a 3D dose pixel NArray from the dose images belonging to this DoseVolume. The array has shape [frames, columns, rows] and contains pixel values. To convert to dose values, the array must be multiplied with the scaling attribute.
231 232 233 234 235 236 237 238 239 |
# File 'lib/rtkit/dose_volume.rb', line 231 def narray if @images.length > 0 narr = NArray.int(@images.length, @images.first.columns, @images.first.rows) @images.each_index do |i| narr[i, true, true] = @images[i].narray end return narr end end |
#to_dose_volume ⇒ Object
Returns self.
253 254 255 |
# File 'lib/rtkit/dose_volume.rb', line 253 def to_dose_volume self end |