Class: DicomS::Sequence
- Inherits:
-
Object
- Object
- DicomS::Sequence
- Includes:
- Support
- Defined in:
- lib/dicoms/sequence.rb
Overview
DICOM series containing a sequence of CT/MRI image slices.
The following metadata about the series is computed:
-
min: pixel value corresponding to the minimum output level
-
max: pixel value corresponding to the maximum output level
-
rescaled: 1 means that min and max are photometrically rescaled values; 0 means they are internal raw values.
-
slope, intercept: photometric rescaling parameters.
-
lim_min, lim_max: (raw) output enconding range limits
-
bits: bit-depth of the original pixel values
-
signed: 1-pixels values are signed 0-unsigned
-
firstx: first X coordinate (slice number) of the ROI
-
lastx: lastt X coordinate (slice number) of the ROI
-
firsty: first Y coordinate of the ROI
-
lasty: last Y coordinate of the ROI
-
lastz:lastt Z coordinate of the ROI
-
study_id, series_id: identification of the patient’s study/series
-
dx, dy, dz: voxel spacing (dx, dy is pixel spacing; dz is the slice spacing)
-
x, y, z: image position (in RCS; see below)
-
xaxis, yaxis, zaxis: each is a three-component vector defining an axis of the image orientation (see below) (encoded as comma-separated string)
-
slice_z: slice position
-
nx: number of columns
-
ny: number of rows
-
nz: number of slices
-
reverse_x 1 means the X axis is reversed (from RCS)
-
reverse_y 1 means the Y axis is reversed (from RCS)
-
reverse_< 1 means the Z axis is reversed (from RCS)
-
axial_sx scale factor: horizontal reduction of axial projections
-
axial_sy scale factor: vertical reduction of axial projections
-
coronal_sx scale factor: horizontal reduction of coronal projections
-
coronal_sy scale factor: vertical reduction of coronal projections
-
sagittal_sx scale factor: horizontal reduction of sagittal projections
-
sagittal_sy scale factor: vertical reduction of sagittal projections
Orientation of RCS (patient coordinate system) in relation to the DICOM sequence reference. This is given as three vectors xaxis yaxis and zaxis.
The RCS system consists of the axes X, Y, Z:
-
X increases from Right to Left of the patient
-
Y increases from the Anterior to the Posterior side
-
Z increases from the Inferior to the Superior side
(Inferior/Superior are sometimes referred to as Bottom/Top or Feet/Head)
The xaxis vector is an unitary vector in the X direction projected in the DICOM reference system x, y, z axes. Similarly, yaxis and zaxis are unitary vectors in the Y and Z directions projected into the DICO reference system.
The DICOM reference uses these axes:
-
x left to right pixel matrix column
-
y top to bottom pixel matrix row
-
z first to last slice
The most common orientation for CT is:
* xaxis: 1,0,0
* yaxis: 0,1,0
* zaxis: 0,0,-1
In this case, the X and Y axes are coincident with x an y of the DICOM reference and slices are ordered in decreasing Z value.
Instance Attribute Summary collapse
-
#files ⇒ Object
readonly
Returns the value of attribute files.
-
#image_cropping ⇒ Object
readonly
Returns the value of attribute image_cropping.
-
#metadata ⇒ Object
Returns the value of attribute metadata.
-
#strategy ⇒ Object
readonly
Returns the value of attribute strategy.
Instance Method Summary collapse
-
#check_series ⇒ Object
Check if the images belong to a single series.
- #dicom(i) ⇒ Object
- #dicom_image(dicom) ⇒ Object
-
#dicom_pixels(dicom, options = {}) ⇒ Object
To use the pixels to be directly saved to an image, use the ‘:unsigned` option to obtain usigned intensity values.
- #each(&blk) ⇒ Object
- #first ⇒ Object
-
#initialize(dicom_directory, options = {}) ⇒ Sequence
constructor
A new instance of Sequence.
- #last ⇒ Object
- #needs_reordering? ⇒ Boolean
- #reorder! ⇒ Object
- #save_jpg(dicom, filename) ⇒ Object
- #size ⇒ Object
- #transfer ⇒ Object
Methods included from Support
#assign_dicom_pixels, #cast_metadata, #decode_vector, #define_transfer, #dicom?, #dicom_bit_depth, #dicom_compression, #dicom_element_value, #dicom_name_pattern, #dicom_narray, #dicom_rescale_intercept, #dicom_rescale_slope, #dicom_signed?, #dicom_stored_bits, #dicom_window_center, #dicom_window_width, #encode_vector, #find_dicom_files, #keeping_path, #normalized_path, #output_file_name, #pixel_value_range, #single_dicom_metadata
Constructor Details
#initialize(dicom_directory, options = {}) ⇒ Sequence
Returns a new instance of Sequence.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/dicoms/sequence.rb', line 73 def initialize(dicom_directory, = {}) @roi = [:roi] @files = find_dicom_files(dicom_directory) @visitors = Array([:visit]) @visited = Array.new(@files.size) = nil @strategy = [:transfer] = Settings[version: 'DSPACK1'] # TODO: reuse existing metadata in options (via settings) if [:reorder] # don't trust the file ordering; use the instance number to ordering # this requires reading all the files in advance true else # if information about the series size (nx, ny, nz) # and the axis orientation (reverse_x, reverse_y, reverse_z) # is available here we can set the @roi now and avoid # processing slices outside it. (in that case the # metadata won't consider those slices, e.g. for minimum/maximum # pixel values) if [:nx] && [:ny] && [:nz] && .to_h.has_key?(:reverse_x) && .to_h.has_key?(:reverse_y) && .to_h.has_key?(:reverse_z) .merge!( nx: [:nx], ny: [:ny], nz: [:nz], reverse_x: [:reverse_x], reverse_y: [:reverse_y], reverse_z: [:reverse_z] ) set_cropping_volume! cropping_set = true end end set_cropping_volume! unless cropping_set end |
Instance Attribute Details
#files ⇒ Object (readonly)
Returns the value of attribute files.
114 115 116 |
# File 'lib/dicoms/sequence.rb', line 114 def files @files end |
#image_cropping ⇒ Object (readonly)
Returns the value of attribute image_cropping.
116 117 118 |
# File 'lib/dicoms/sequence.rb', line 116 def image_cropping @image_cropping end |
#metadata ⇒ Object
Returns the value of attribute metadata.
115 116 117 |
# File 'lib/dicoms/sequence.rb', line 115 def end |
#strategy ⇒ Object (readonly)
Returns the value of attribute strategy.
114 115 116 |
# File 'lib/dicoms/sequence.rb', line 114 def strategy @strategy end |
Instance Method Details
#check_series ⇒ Object
Check if the images belong to a single series
207 208 209 210 |
# File 'lib/dicoms/sequence.rb', line 207 def check_series visit_all @visited.reject { |name, study, series, instance| study == .study_id && series == .series_id }.empty? end |
#dicom(i) ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/dicoms/sequence.rb', line 128 def dicom(i) # TODO: support caching strategies for reading as DICOM objects: # no-caching, max-size cache, ... dicom = DICOM::DObject.read(@files[i]) sop_class = dicom['0002,0002'].value unless sop_class == '1.2.840.10008.5.1.4.1.1.2' raise "Unsopported SOP Class #{sop_class}" end # TODO: require known SOP Class: # (in tag 0002,0002, Media Storage SOP Class UID) visit dicom, i, *@visitors dicom end |
#dicom_image(dicom) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/dicoms/sequence.rb', line 165 def dicom_image(dicom) if dicom.is_a?(Magick::Image) image = dicom else if @strategy image = @strategy.image(dicom, .min, .max) else image = dicom.image end end if DICOM.image_processor == :mini_magick image.format('jpg') end if @image_cropping @image_cropping.inspect firstx, lastx, firsty, lasty = @image_cropping image.crop! firstx, firsty, lastx-firstx+1, lasty-firsty+1 end image end |
#dicom_pixels(dicom, options = {}) ⇒ Object
To use the pixels to be directly saved to an image, use the ‘:unsigned` option to obtain usigned intensity values. If the pixels are to be assigned as Dicom pixels (’Dicom#pixels=‘) they don’t need to be unsigned.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/dicoms/sequence.rb', line 190 def dicom_pixels(dicom, = {}) if @strategy pixels = @strategy.pixels(dicom, .min, .max) else pixels = dicom_narray(dicom, level: false, remap: true) end if @image_cropping firstx, lastx, firsty, lasty = @image_cropping pixels = pixels[firstx..lastx, firsty..lasty] end if [:unsigned] && .lim_min < 0 pixels.add! -.lim_min end pixels end |
#each(&blk) ⇒ Object
151 152 153 154 155 156 |
# File 'lib/dicoms/sequence.rb', line 151 def each(&blk) (0...@files.size).each do |i| dicom = dicom(i) visit dicom, i, blk end end |
#first ⇒ Object
143 144 145 |
# File 'lib/dicoms/sequence.rb', line 143 def first dicom(0) end |
#last ⇒ Object
147 148 149 |
# File 'lib/dicoms/sequence.rb', line 147 def last dicom(size-1) end |
#needs_reordering? ⇒ Boolean
219 220 221 222 223 |
# File 'lib/dicoms/sequence.rb', line 219 def needs_reordering? visit_all @visited.sort_by! { |name, study, series, instance| [study, series, instance] } @files != @visited.map { |name, study, series, instance| name } end |
#reorder! ⇒ Object
212 213 214 215 216 217 |
# File 'lib/dicoms/sequence.rb', line 212 def reorder! # This may invalidate dz and the cropped selection of slices visit_all @visited.sort_by! { |name, study, series, instance| [study, series, instance] } @files = @visited.map { |name, study, series, instance| name } end |
#save_jpg(dicom, filename) ⇒ Object
158 159 160 161 162 163 |
# File 'lib/dicoms/sequence.rb', line 158 def save_jpg(dicom, filename) keeping_path do image = dicom_image(dicom) image.write(filename) end end |
#size ⇒ Object
124 125 126 |
# File 'lib/dicoms/sequence.rb', line 124 def size @files.size end |
#transfer ⇒ Object
118 119 120 |
# File 'lib/dicoms/sequence.rb', line 118 def transfer @strategy end |