Class: RTKIT::Slice

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

Overview

Contains DICOM data and methods related to an Image Slice, in which a set of contours are defined.

Relations

  • A Slice is characterized by a SOP Instance UID, which relates it to an Image.

  • A ROI has many Slices, as derived from the Structure Set.

  • A Slice has many Contours.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sop_uid, roi) ⇒ Slice

Creates a new Slice instance.

Parameters

  • sop_uid – The SOP Instance UID reference for this slice.

  • contour_item – An array of contour items from the Contour Sequence in ROI Contour Sequence, belonging to the same slice.

  • roi – The ROI instance that this Slice belongs to.

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rtkit/slice.rb', line 53

def initialize(sop_uid, roi)
  raise ArgumentError, "Invalid argument 'sop_uid'. Expected String, got #{sop_uid.class}." unless sop_uid.is_a?(String)
  raise ArgumentError, "Invalid argument 'roi'. Expected ROI, got #{roi.class}." unless roi.is_a?(ROI)
  # Key attributes:
  @contours = Array.new
  @uid = sop_uid
  @roi = roi
  # Set up the Image reference:
  @image = roi.frame.image(@uid)
  # Register ourselves with the ROI:
  @roi.add_slice(self)
end

Instance Attribute Details

#contoursObject (readonly)

An array containing the Contours defined for this Slice.



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

def contours
  @contours
end

#imageObject (readonly)

The Slice’s Image reference.



16
17
18
# File 'lib/rtkit/slice.rb', line 16

def image
  @image
end

#roiObject (readonly)

The ROI that the Slice belongs to.



18
19
20
# File 'lib/rtkit/slice.rb', line 18

def roi
  @roi
end

#uidObject (readonly)

The Referenced SOP Instance UID.



20
21
22
# File 'lib/rtkit/slice.rb', line 20

def uid
  @uid
end

Class Method Details

.create_from_items(sop_uid, contour_items, roi) ⇒ Object

Creates a new Slice instance from an array of contour items belonging to a single slice of a particular ROI. This method also creates and connects any child structures as indicated in the items (e.g. Contours). Returns the Slice.

Parameters

  • sop_uid – The SOP Instance UID reference for this slice.

  • contour_item – An array of contour items from the Contour Sequence in ROI Contour Sequence, belonging to the same slice.

  • roi – The ROI instance that this Slice belongs to.

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rtkit/slice.rb', line 32

def self.create_from_items(sop_uid, contour_items, roi)
  raise ArgumentError, "Invalid argument 'sop_uid'. Expected String, got #{sop_uid.class}." unless sop_uid.is_a?(String)
  raise ArgumentError, "Invalid argument 'contour_items'. Expected Array, got #{contour_items.class}." unless contour_items.is_a?(Array)
  raise ArgumentError, "Invalid argument 'roi'. Expected ROI, got #{roi.class}." unless roi.is_a?(ROI)
  # Create the Slice instance:
  slice = self.new(sop_uid, roi)
  # Create the Contours belonging to the ROI in this Slice:
  contour_items.each do |contour_item|
    Contour.create_from_item(contour_item, slice)
  end
  return slice
end

Instance Method Details

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

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



68
69
70
71
72
# File 'lib/rtkit/slice.rb', line 68

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

#add_contour(contour) ⇒ Object

Adds a Contour instance to this Slice.

Raises:

  • (ArgumentError)


78
79
80
81
# File 'lib/rtkit/slice.rb', line 78

def add_contour(contour)
  raise ArgumentError, "Invalid argument 'contour'. Expected Contour, got #{contour.class}." unless contour.is_a?(Contour)
  @contours << contour unless @contours.include?(contour)
end

#areaObject

Calculates the area defined by the contours of this slice. Returns a float value, in units of millimeters squared.



86
87
88
# File 'lib/rtkit/slice.rb', line 86

def area
  bin_image.area
end

#attach_to(series) ⇒ Object

Attaches a Slice to an Image instance belonging to the specified ImageSeries, by setting the Image reference of the Slice to an Image instance which matches the coordinates of the Slice’s Contour(s). Raises an exception if a suitable match is not found for the Slice.

Notes

This method can be useful when you have multiple segmentations based on the same image series from multiple raters (perhaps as part of a comparison study), and the rater’s software has modified the UIDs of the original image series, so that the references of the returned Structure Set does not match your original image series. This method uses coordinate information to calculate plane equations, which allows it to identify the corresponding image slice even in the case of slice geometry being non-perpendicular with respect to the patient geometry (direction cosine values != [0,1]).

Raises:

  • (ArgumentError)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rtkit/slice.rb', line 104

def attach_to(series)
  raise ArgumentError, "Invalid argument 'series'. Expected ImageSeries, got #{series.class}." unless series.is_a?(Series)
  # Do not bother to attempt this change if we have an image reference and this image instance already belongs to the series:
  if @image && !series.image(@image.uid) or !@image
    # Query the ImageSeries for an Image instance that matches the Plane of this Slice:
    matched_image = series.match_image(plane)
    if matched_image
      @image = matched_image
      @uid = matched_image.uid
    else
      raise "No matching Image was found for this Slice."
    end
  end
end

#bin_image(source_image = @image) ⇒ Object

Creates a binary segmented image, from the contours defined for this slice, applied to the referenced Image instance. Returns an BinImage instance, containing a 2d NArray with dimensions: columns*rows

Parameters

  • source_image – The image on which the binary volume will be applied (defaults to the referenced image, but may be e.g. a dose ‘image’).



126
127
128
129
130
131
132
133
134
135
# File 'lib/rtkit/slice.rb', line 126

def bin_image(source_image=@image)
  raise "Referenced ROI Slice Image is missing from the dataset. Unable to construct image." unless @image
  bin_img = BinImage.new(NArray.byte(source_image.columns, source_image.rows), source_image)
  # Delineate and fill for each contour, then create the final image:
  @contours.each_with_index do |contour, i|
    x, y, z = contour.coords
    bin_img.add(source_image.binary_image(x, y, z))
  end
  return bin_img
end

#hashObject

Generates a Fixnum hash value for this instance.



139
140
141
# File 'lib/rtkit/slice.rb', line 139

def hash
  state.hash
end

#planeObject

Returns the Plane corresponding to this Slice. The plane is calculated from coordinates belonging to this instance, and an error is raised if not enough Coordinates are present (at least 3 required).



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rtkit/slice.rb', line 147

def plane
  # Such a change is only possible if the Slice instance has a Contour with at least three Coordinates:
  raise "This Slice does not contain a Contour. Plane determination is not possible." if @contours.length == 0
  raise "This Slice does not contain a Contour with at least 3 Coordinates. Plane determination is not possible." if @contours.first.coordinates.length < 3
  # Get three coordinates from our Contour:
  contour = @contours.first
  num_coords = contour.coordinates.length
  c1 = contour.coordinates.first
  c2 = contour.coordinates[num_coords / 3]
  c3 = contour.coordinates[2 * num_coords / 3]
  return Plane.calculate(c1, c2, c3)
end

#posObject

Returns the position of this slice, which in effect is the pos_slice attribute of the referenced image.



163
164
165
# File 'lib/rtkit/slice.rb', line 163

def pos
  return @image ? @image.pos_slice : nil
end

#to_sliceObject

Returns self.



169
170
171
# File 'lib/rtkit/slice.rb', line 169

def to_slice
  self
end