dicom3d package¶
Root dicom3d module implementing Section, Series, Dataset class objects
-
class
dicom3d.
Section
(series, coordinateMapping)[source]¶ Bases:
object
This class manages a section of the volumetrical scan, able to produce a planar image of the datasets intersecting it
Examples
- To build a section, you can use:
>>> section = Section.from_plane(series, plane, origin)
- To get the image corresponding wiith this section:
>>> section.image()
- To use the local coordinate system:
>>> point = section.to_mm(x,y) >>> x,y = section.to_pixel(point)
-
dpi
¶ Dots per inch property. Similar with pixel_density propery, except that it calculates the density per square inch, not per millimeter.
Returns: a tuple of floats representing the density on X and Y axis Return type: tuple
-
static
from_dataset
(dataset)[source]¶ Constructs a section from a single DICOM dataset
Parameters: - dataset (Dataset) – planar DICOM dataset
- () (origin) – world coordinates of section center
Returns: constructed section object
Return type: Important
This function will construct a pseudo-series which will contain a single dataset. The pseudo-series can be accesses via series class member
>>> section = dicom3d.Section.from_dataset(dataset) >>> series = section.series >>> series.count() 1 >>> series.first() == series.last() True
-
static
from_plane
(series, plane, origin, orientation=True)[source]¶ Creates a section from a dicom3d.Plane and an origin point that will act as section’s center
Parameters: Raises: Exception
– when intersection errors are detectedReturns: constructed section object
Return type:
-
image
(size)[source]¶ Constructs the image corresponding to this section and return an numpy array, describing the image
Parameters: size (tuple) – tuple of float or integer width,height values (see notes)
Raises: ValueError
– when input of unknown type is receivedException
– on intersection errors
Note
If the size argument is a tuple of integers, then it will be treated as width and height in pixels of the resulting image. If it’s a tuple of floats, then it will be considered to be the width and height in millimeters for each for the area covered by the resulting image.
Returns: numpy array of the constructed image Return type: numpy.array
-
pixel_density
¶ It is the opposite of the pixel_spacing property and describes how many pixels are per square millimeter.
Returns: a tuple of floats representing the density on X and Y axis Return type: tuple
-
pixel_spacing
¶ Property describing the distance in millimeters between section’s pixels
Returns: a tuple of floats describing the X and Y spacing Return type: tuple
-
class
dicom3d.
Series
(datasets, check_homogeneity=True)[source]¶ Bases:
object
Class responsible for managing a volumetric scan, comprised by a list of successive datasets
Note
- When constructed, this class performs the following operations
- sorts the given datasets by ZLocation
- wraps the datasets in dicom3d.Dataset class
- checks the series for spacial homogeneity
Attention
Homogeneity check is required by this class to make sure the assumptions it makes over the volumetric scan, are correct. These assumptions are related to space contiguity between datasets and consistent density and size among datasets
Important
- A series is homogeneous if:
- all datasets are continuous on the Z axis (no gaps)
- each dataset has identical values for these attributes
- SliceThickness
- PixelSpacing
- Rows
- Columns
- ImagePositionPatient
- ImageOrientationPatient
-
at
(where)[source]¶ This is a wrapper function for ease of use over at_index and at_z functions.
Parameters: where (int, float, tuple, Point) – if where is an integer is treated like an index, else is considered to be a Z location Returns: the corresponding dicom3d.Dataset object Return type: Dataset Examples
>>> dataset = series.at(1.0) # gets dataset at 0.1 Z coordinate >>> dataset = series.at(1) # gets dataset at index 1 >>> dataset = series.at(Point(5,5,2)) # gets dataset at 2.0 Z coordinate
-
at_index
(index)[source]¶ Returns the dataset at the corresponding index or None if index is out of bounds.
Parameters: index (int) – dataset index in series Returns: the dicom3d.Dataset object at index Return type: Dataset
-
at_z
(z_loc)[source]¶ Returns the dataset that intersects the given Z location in world coordinates
Important
If homogeneity test was disabled for this series, this function will raise an exception
Parameters: z_loc (float) – value describing location on the Z axis Returns: the corresponding dicom3d.Dataset object Return type: Dataset
-
cache
()[source]¶ Builds a three-dimensional numpy array from all pixel data from datasets.
Important
Reserved for future use!
Returns: numpy array of the pixel data Return type: numpy.array
-
find_dataset
(z_loc)[source]¶ Despite Series.at_z method, this one doesn’t require homogenuity test to be ran If will effectively search though the list to find the corresponding dataset, instead of calculating the index based on Z-bounds and dataset thickness.
Parameters: z_loc (float) – value describing location on the Z axiss Returns: index of the corresponding dataset or -1 if not found Return type: int
-
first
()[source]¶ Retrives the first dataset from series. The first dataset is located at the bottom of the Z segment, therefore it will have the lowest Z coordinate value.
Returns: a dicom3d.Dataset object Return type: Dataset
-
static
fix_z_duplicates
(datasets)[source]¶ Attempts to curate a list of datasets that has datasets duplicated on the Z axis
- Args:s
- datasets (list): list of pydicom.dataset.Dataset objects
Important
This code is experimental and is used to fix some series that fail the homogeneity test.
-
static
from_dataset
(dataset)[source]¶ Constructs a series from a single dataset. Helpful if you want to build section images from planar datasets
Parameters: dataset (Dataset) – planar DICOM dataset Returns: resulted series object Return type: Series
-
static
from_directory
(path, pattern='*.dcm', check_homogeneity=True)[source]¶ Constructs a series from a directory of DICOM files
Parameters: - path (str) – path to the directory continaing the DICOM files
- pattern (str, optional) – Wildcard pattern of DIICOM files, default is “*.dcm”
- check_homogeneity (bool, optional) – Homogeneity test, default is True
Returns: a dicom3d.Series object
Return type: [Series]
-
last
()[source]¶ Retrives the last dataset from series. The last dataset is located at the top of the Z segment, therefore it will have the highest Z coordinate value.
Returns: a dicom3d.Dataset object Return type: Dataset
-
middle
()[source]¶ Retrives the dataset from series that is on the middle of the Z segment.
Returns: a dicom3d.Dataset object Return type: Dataset
-
z_bounds
()[source]¶ Returns a tuple representing the world Z coordinates of the volumetric scan, including the top dataset and its thickness.
Important
If homogeneity test was disabled for this series, this function will raise an exception
Returns: a tuple of float values representing the Z bounds Return type: tuple Examples
>>> z_start, z_end = series.z_bounds() >>> print("Series starts from %.1f to %.1f mm on the Z axis" % (z_start, z_end) )
-
class
dicom3d.
Dataset
(dataset, series, index)[source]¶ Bases:
object
Wrapper class over the pydicom.dataset.Dataset class that provides additional methods for manipulating a dataset, including a local coordinate system to map pixel locations over world coordinates
-
ZLocation
¶ Property describing dataset’s Z coordinate in world space in millimeters units
Attention
According to DICOM standard the SliceLocation attrbute is defined as:
The relative position of the image plane expressed in mm. This information is relative to an unspecified implementation specific reference point.
This makes SliceLocation attribute unreliable for ordering or finding datasets in world space, as it’s possible to indicate a Z coordinate not related to the one obtained via dataset’s LocalCoordinateSystem, thus not related to the ImagePositionPatient standard attribute.
Returns: Z coordinate Return type: float Examples
>>> # will return pydicom's SliceLocation attribute value >>> series.first().SliceLocation "205.7" >>> # will return dicom3d.Dataset's attribute >>> series.first().ZLocation -205.7 >>> # notice the dataset's value of Z coordinate for the center point >>> # which is obtained via 'ImagePositionPatient' attribute >>> series.first().center() x:-2.65 y:-184.74 z:-205.70
-
bottomleft
()[source]¶ Returns the corresponding world coordinates for the local (0, Rows-1) point
Returns: bottom-left point in world coordinates Return type: Point
-
bottomright
()[source]¶ Returns the corresponding world coordinates for the local (Columns-1, Rows-1) point
Returns: bottom-right point in world coordinates Return type: Point
-
center
()[source]¶ Returns the center of the dataset in world coordinates measured in millimeter units
Returns: center of the dataset Return type: Point
-
intersects
(what)[source]¶ Checks if the given parameter intersects the dataset
- The first positonal parameter, can be of type:
- float - which is considered to be a Z coordinate
- tuple - which is considered to be a (x,y) coordinate
- plane - plane object
Parameters: what (float, Point, tuple, Plane) – object to test intersection against Returns: True if intersection was detected or False otherwise Return type: bool Examples
>>> # check intersection with a Z world coordinate >>> dataset.intersects(10.0) >>> # check intersection with (X,Y) world coordinate >>> dataset.intersects((10.0,30.0)) >>> # check intersection with a fully-defined point >>> dataset.intersects((10.0, 30.0, 10.0)) >>> dataset.intersects(dicom3d.Point(10,30,10)) # same effect >>> # check intersection with a given plane >>> dataset.intersects(dicom3d.Plane.from_axes("xy"))
-
intersects_point
(pt)[source]¶ Verifies if this dataset intersects a given point in world coordinates
Parameters: pt (Point, tuple) – point or tuple describing world coordinates Returns: True point intersects dataset, False otherwise Return type: bool
-
next
()[source]¶ Returns the next dataset from the series it belongs to, or None if last
Returns: next dataset object Return type: Dataset Examples
>>> # one way of navigating forward through datasets >>> dataset = series.first() >>> while(dataset is not None): >>> dataset = dataset.next()
-
plane
()[source]¶ Constructs a plane corresponding to this dataset
Returns: plane object Return type: Plane Examples
>>> # plane equation for first dataset >>> series.first().plane() 0.00X + 0.00Y + 1.00Z = -296.70
-
plane_intersection
(plane)[source]¶ Verifies intersection of this dataset with a given plane and returns a list of two far-most points on the sides of the dataset, where it touches the plane.
Returns: list of two dicom3d.Point objects Return type: [list]
-
prev
()[source]¶ Returns the previous dataset from the series it belongs to, or None if first
Returns: previous dataset object Return type: Dataset Examples
>>> # one way of navigating backwards through datasets >>> dataset = series.last() >>> while(dataset is not None): >>> dataset = dataset.prev()
-
to_mm
(x, y)[source]¶ Converts the local pixel coordinates to world coordinates measured in units of millimeters
Parameters: - x (int) – value on the X axis
- y (int) – value on the Y axis
Returns: transformed three-dimensional point representing world coordinates
Return type: Examples
>>> dataset = series.first() >>> pt1 = dataset.to_mm(10,10) # world coords for pixel at ( 10, 10) >>> pt2 = dataset.to_mm(100,100) # world coords for pixel at (100,100) >>> print("Distance from pixel (10,10) to (100,100) is %.1f mm" % ( pt1.distance(pt2))) Distance from pixel (10,10) to (100,100) is 89.2 mm
-
to_pixel
(coords)[source]¶ Converts the given point from world coordinates in millimeter units, to local coordinates, in pixels.
Parameters: coords (tuple, Point) – point describing world coordinates Returns: transformed two-dimensional point representing local coordinates Return type: tuple
-
topleft
()[source]¶ Returns the corresponding world coordinates for the local (0,0) point
Returns: top-left point in world coordinates Return type: Point Examples
>>> first = series.first() >>> first.topleft() x:-182.15 y:-364.24 z:-296.70 >>> # one way of getting dataset's width in millimeters >>> first.topleft().distance(first.topright()) 358.298828125
-
-
class
dicom3d.
Plane
(a=0, b=0, c=0, d=0)[source]¶ Bases:
object
This class provides support for the mathematical operations required to construct and manipulate planes
-
a
¶ For a plane described by equation ‘ax + by + cx = d’, this property modifies the ‘a’ component of the plane
-
angle
(p)[source]¶ Calculates the angle made by the given plane with another one
Parameters: p (Plane) – plane argument to calculate angle with Returns: resulted angle in radians Return type: float Note
This function actually calculates the angle made by the two plane’s normal vectors
-
b
¶ For a plane described by equation ‘ax + by + cx = d’, this property modifies the ‘b’ component of the plane
-
c
¶ For a plane described by equation ‘ax + by + cx = d’, this property modifies the ‘c’ component of the plane
-
equals
(p)[source]¶ Checks if a plane is equal to another
Parameters: p (Plane) – argument plane to check equality Returns: True if equation is equal or False otherwise Return type: bool Examples
>>> plane1 = Plane.from_axes("xy") >>> plane2 = Plane.from_coords((0,0,0), (0,0,1)) >>> plane2.equals(plane1) True >>> plane2.equals(plane1.move((0,0,1))) False
-
static
from_axes
(axes)[source]¶ Constructs a vector from two axis
Parameters: axes (str) – string defining the two axis (“xy”,”xz” or “yz”) Raises: ValueError
– on invalid axis definitionReturns: resulting plane object Return type: Plane Examples
>>> oxy = Plane.from_axes("xy") >>> oxz = Plane.from_axes("xz") >>> oyz = Plane.from_axes("yz") >>> degrees(oxz.angle(oxy)) 90.0
-
static
from_coords
(origin, target)[source]¶ Constructs a plane from a vector described by two points in space
Note
The resulted plane’s normal vector will be trimmed to be a unit vector
Parameters: Returns: resulting plane object
Return type: Examples
>>> plane1 = Plane.from_axes("xz") >>> plane2 = Plane.from_coords((0,0,0),(0,1,0)) >>> plane1.equals(plane2) True
-
static
from_normal
(normal, d=0)[source]¶ Constructs a plane from a normal vector and the d component.
Parameters: - normal (Vector) – normal vector
- d (int, optional) – d component of the plane, defaults to 0.
Returns: resulting plane object
Return type:
-
intersects
(point)[source]¶ Verifies if a given point intersects the current plane
Parameters: point (tuple, Point) – point argument to check intersection with Returns: True if intersects plane or False otherwise Return type: bool
-
move
(point)[source]¶ Returns a plane from the current one, translated to a given point
Note
This function will modify only the d component of the plane
Parameters: point (tuple, Point) – point to translate plane to Returns: resulting plane object Return type: Plane
-
parallel
(p, tolerance=0.0001)[source]¶ Checks if this plane is parallel to a given one within a given range of tolerance
Parameters: - p (Plane) – plane argument to check parallelism
- tolerance (float, optional) – tolerance value, defaults to 1.e-4
Returns: True if parallel or False otherwise
Return type: bool
Examples
>>> plane1 = Plnae.from_axes("xy") # OXY plane >>> plane2 = plane1.move((0,0,10)) # move plane to this point >>> plane1 0.00X + 0.00Y + 1.00Z = 0.00 >>> plane2 0.00X + 0.00Y + 1.00Z = 10.00 >>> plane1.parallel(plane2) True
-
resolve
(point)[source]¶ Resolves the X,Y or Z component of the given point based on current plane equation
Parameters: point (tuple, Point) – point to resolve Returns: resulting Point Return type: Point Examples
To find the Z component of a point that lies on the plane and has only the X and Y components defined:
>>> plane = Plane.from_axes("xy").rotate("y",radians(30)) >>> _,_,z = plane.resolve((10,10,None)) >>> print("Resolved point is X:10 Y:10 Z:%.2f" % (z)) Resolved point is X:10 Y:10 Z:-5.77
-
rotate
(by, angle)[source]¶ Returns a plane from the current one, with the normal vector rotated about an axis or another vector, by a given angle.
Parameters: - by (str,Vector) – axis definition (“x”,”y” or “z”) or vector object
- angle (float) – angle measured in radians
Returns: resulting plane object
Return type:
-
-
class
dicom3d.
Vector
(i=0, j=0, k=0)[source]¶ Bases:
object
Class responsible for providing support for vectorial algebra
-
angle
(vector)[source]¶ Calculates the angle in radians, between this vector and the one passed as argument
Parameters: vector (Vector) – argument vector Returns: angle measured in radians Return type: float
-
div
(v)[source]¶ Divides a vector by a scalar value
Parameters: v (float, int) – scalar value to divide by Returns: resulting vector object Return type: Vector
-
dot
(v)[source]¶ Calculates the dot product of a vector with a given one
Parameters: v (Vector) – dot product argument Returns: resulting vector object Return type: Vector
-
equals
(v)[source]¶ Verifies if a vector is identical with the given one
Parameters: v (Vector) – vector to verify equality with Returns: True if equal, False otherwise Return type: bool
-
static
from_axis
(axis)[source]¶ Constructs a vector from a given Axis definition
Parameters: axis (str) – axis name (“x”, “y” or “z”) Raises: ValueError
– when an invalid axis name is passedReturns: resulting vector Return type: Vector
-
static
from_coords
(origin, target)[source]¶ Constructs a vector from two points in space
Parameters: Returns: resulting vector object
Return type:
-
static
from_numpy
(array)[source]¶ Constructs a vector from a numpy array of shape (3,1)
Parameters: array (numpy.array) – numpy array to import data from Returns: resulting vector object Return type: Vector
-
static
from_plane
(plane)[source]¶ Copies the plane normal vector
Parameters: plane (Plane) – plane argument Returns: resulting vector object Return type: Vector
-
i
¶ Property describing the i component of the vector
-
invert
()[source]¶ Returns a vector pointing in the opposite direction
Returns: resulting vector object Return type: Vector
-
j
¶ Property describing the j component of the vector
-
k
¶ Property describing the k component of the vector
-
mul
(v)[source]¶ Multiplies a vector with a scalar value
Parameters: v (float, int) – scalar value to multiply by Returns: resulting vector object Return type: Vector
-
numpy
()[source]¶ Returns the corresponding numpy array for this vector
Returns: corresponding numpy array Return type: numpy.array
-
rotate
(by, angle)[source]¶ Wrapper function to construct rotated vectors, transparently using dicom3d.Vector.rotate_by_axis or dicom3d.Vector.rotate_by_vector, depending on the arguments given.
Parameters: - by (str, Vector) – axis definition (“x”, “y” or “z”) or vector object
- angle (float) – angle measured in radians
Raises: ValueError
– if an invalid axis name is passed as argumentReturns: rotated vector object
Return type:
-
rotate_by_axis
(axis, angle)[source]¶ Construct a vector that represents the current one rotated about a given axis
Parameters: - axis (str) – axis name definition (“x”, “y” or “z”)
- angle (float) – angle measured in radians
Raises: ValueError
– if an invalid axis name is passedReturns: rotated vector object
Return type:
-
rotate_by_vector
(vector, angle)[source]¶ Construct a vector that represents the current one rotated around a given vector
Parameters: - vector (Vector) – pivot vector to perform rotation about
- angle (float) – angle measured in radians
Returns: rotated vector object
Return type:
-
-
class
dicom3d.
Point
(x, y, z)[source]¶ Bases:
object
Class implementing support for point operations in three dimensional world coordinates
-
distance
(to)[source]¶ Calculates the distance from this point to the given one
Parameters: to (Point, float) – end point to calculate distance to Returns: distance to the given point Return type: float
-
-
class
dicom3d.
LocalCoordinateSystem
(origin, x_vector, y_vector, scaling=(1, 1))[source]¶ Bases:
object
Class responsible for transforming local coordinates in a cartesian space to world three dimensional coordinations. A Local Coordinate System is defined by two axis vectors (one describing the X axis, the other one the Y axis in the cartesian bi-dimensional space) and an origin for the (0,0) point.
The scaling factor is optional, but useful when the world you are mapping to has a different density than the local cartesian system you are using.
-
copy
()[source]¶ Creates a copy of itself
Returns: resulting coordinate system Return type: LocalCoordinateSystem
-
measure
(point_from, point_to)[source]¶ Measures the distance from point_from to point_to in world coordinates or local coordinates.
When measuring for local cartesian coordinates the result will be the distance from the coresponding transformed world coordindates and viceversa. When measuring distance for world coordinates, the result will be the distance in local coordinates.
Raises: ValueError
– inconsistent dimensions given (e.g. 2D point paired with 3D point)ValueError
– invalid input (e.g. not a 2D point nor 3D point)
Returns: measured distance in local or world coordinates
Return type: float
Examples
>>> # asuming we have a *dicom3d.Dataset* object >>> pt1, pt2 = dataset.to_mm(0,0), dataset.to_mm(10,10) >>> # this will measure the distance in mm between the two points >>> pt1.distance(pt2) 4.419417382415922 >>> # which is ecquivalent with this short form >>> dataset.transform.measure((0,0),(10,10)) 4.419417382415922 >>> # for measuring the opposite, distance in pixels >>> # for the segment defined by the two points >>> dataset.transform.measure(pt1,pt2) 14.142135623730951 >>> # which is equivalent to how we calculate the diagonal >>> # if we knew the corresponding local points >>> np.sqrt(10**2 + 10**2) 14.142135623730951
-
move
(by, distance)[source]¶ Translate this local coordinate system’s origin by moving it along a given vector and by a given distance
Parameters: - by (str, Vector) – axis name (“x”, “y” or “z”) or vector object describing direction of translation
- distance (float) – value describing distance
Returns: the translated coordinate system
Return type: Examples
>>> section.transform.origin x:-73.91 y:-81.20 z:6.64 >>> # move on the x axis 10 mm >>> section.tranform.move("x", 10.0).origin x:-63.91 y:-81.20 z:6.64 >>> # move on XY diagonal >>> vector = Vector.from_axis("x").rotate("z", radians(45)) >>> section.transform.move(vector, 10.0).origin x:-66.84 y:-74.13 z:6.64
-
rotate
(by, angle)[source]¶ Rotates this coordinate system X and Y axes about a vector or an axis and returns the newly modified coordinate system
Parameters: - by (str, Vector) – axis definition (“x”, “y” or “z”) or vector object
- angle (float) – angle measured in radians
Returns: the rotated coordinate system
Return type: Examples
>>> section.transform.x_vector i:1.00 j:0.00 k:0.00 >>> section.transform.rotate("z",radians(45)).x_vector i:0.71 j:0.71 k:0.00
-
scale
(by)[source]¶ Modify the scaling factor of the current coordinate system and construct another one with the resulting scaling factor
Parameters: by (float, tuple) – value or tuple of values describing the scaling factor Returns: the scaled coordinate system Return type: LocalCoordinateSystem Examples
>>> transform1 = section.transform.copy() >>> transform2 = transform.scale(1/2) >>> dist1 = transform1.to_world(0,0).distance(transform1.to_world(10,10)) >>> dist2 = transform2.to_world(0,0).distance(transform2.to_world(10,10)) >>> print("Distance before scale: %.1f after: %.1f" % (dist1, dist2)) Distance before scale: 4.4 after: 2.2
-
to_local
(coords)[source]¶ Transforms the givel world three dimensional coordinates to local cartesian coordinates
Parameters: coords (Point, tuple) – world three dimensional coordinates Returns: tuple of the resulting cartesian coordinates in float Return type: tuple
-
to_world
(x, y)[source]¶ Transform local cartesian coordinates (x and y) to three dimesnional world coordinates
Parameters: - x (float, int) – value of cartesian x coordinate
- y (float, int) – value of cartesian y coordinate
Returns: point object describing resulting coordinates
Return type: Examples
>>> transform = section.transfrom >>> transform.to_world(0,0) x:-73.91 y:-81.20 z:6.64 >>> transform.to_world(10,10) x:-70.78 y:-78.08 z:6.6 >>> dist = transform.to_world(10,10).distance( transform.to_world(0,0) ) >>> print("From (0,0) to (10,10) distance is: %.1f mm" % (dist)) From (0,0) to (10,10) distance is: 4.4 mm
-
update
()[source]¶ For each direct modification made to this coordinate system, a call to this function is required to update the transformation matrix
Examples
Assuming you decide to set a new origin point:
>>> lcs = LocalCoordinateSystem( Vector.from_axis("x), Vector.from_axis("y"), Point(0,0,0)) >>> lcs.origin = Point(10,10,0) >>> lcs.update() >>> # now you can safely transform from and to cartesian space >>> pt = lcs.to_world(0,0) >>> print("Origin:", pt)
-
-
dicom3d.
degrees
(radians)[source]¶ Converts the given angle from radians to degrees
Parameters: radians (float) – angle in radians Returns: resulting angle in degrees Return type: float
-
dicom3d.
radians
(degrees)[source]¶ Converts a given angle from degrees to radians
Parameters: degrees (float) – angle in degrees Returns: resulting angle in radians Return type: float
Subpackages¶
Submodules¶
dicom3d.dicomdir module¶
-
class
dicom3d.dicomdir.
DiicomDir
[source]¶ Bases:
object
-
find
(record_attrs=None, study_attrs=None, series_attrs=None)[source]¶ finds records, studies and series based on a set of given attributes for each
-
find_series
(studies, attrs)[source]¶ finds series based on a dictionary of attributes, from a list of given studies
-