Synthetic data

Synthetic images

The SyntheticImage class enables the creation of images containing simple geometric shapes.

synthetic image with a sphere and a cube

Creating a synthetic image

To create an empty image, load the SyntheticImage class and specify the desired image shape in order (x, y, z), e.g.

from skrt.simulation import SyntheticImage

sim = SyntheticImage((250, 250, 50))

The following arguments can be used to adjust the image’s properties:

  • voxel_size: voxel sizes in mm in order (x, y, z); default (1, 1, 1).

  • origin: position of the top-left voxel in mm; default (0, 0, 0).

  • intensity: value of the background voxels of the image.

  • noise_std: standard deviation of Gaussian noise to apply to the image. This noise will also be added on top of any shapes. (Can be changed later by altering the sim.noise_std property).

Adding shapes

The SyntheticImage object has various methods for adding geometric shapes. Each shape has the following arguments:

  • intensity: intensity value with which to fill the voxels of this shape.

  • above: if True, this shape will be overlaid on top of all existing shapes; otherwise, it will be added below all other shapes.

The available shapes and their specific arguments are:

  • Sphere: sim.add_sphere(radius, centre=None)

    • radius: radius of the sphere in mm.

    • centre: position of the centre of the sphere in mm (if None, the sphere will be placed in the centre of the image).

  • Cuboid: sim.add_cuboid(side_length, centre=None)

    • side_length: side length in mm. Can either be a single value (to create a cube) or a list of the (x, y, z) side lengths.

    • centre: position of the centre of the cuboid in mm (if None, the cuboid will be placed in the centre of the image).

  • Cube: sim.add_cube(side_length, centre=None)

    • Same as add_cuboid.

  • Cylinder: sim.add_cylinder(radius, length, axis='z', centre=None)

    • radius: radius of the cylinder in mm.

    • length: length of the cylinder in mm.

    • axis: either 'x', 'y', or 'z'; direction along which the length of the cylinder should lie.

    • centre: position of the centre of the cylinder in mm (if None, the cylinder will be placed in the centre of the image).

  • Grid: sim.add_grid(spacing, thickness=1, axis=None)

    • spacing: grid spacing in mm. Can either be a single value, or list of (x, y, z) spacings.

    • thickenss: gridline thickness in mm. Can either be a single value, or list of (x, y, z) thicknesses.

    • axis: if None, gridlines will be created in all three directions; if set to 'x', 'y', or 'z', grids will only be created in the plane orthogonal to the chosen axis, such that a solid grid runs through the image along that axis.

To remove all shapes from the image, run

sim.reset()

Plotting

The SyntheticImage class inherits from the Image class, and can thus be plotted in the same way by calling

sim.plot()

along with any of the arguments available to the Image plotting method.

Rotations and translations

Rotations and translations can be applied to the image using:

sim.translate(dx, dy, dz)

or

sim.rotate(pitch, yaw, roll)

Rotations and translations can be removed by running

sim.reset_transforms()

Getting the image array

To obtain a NumPy array containing the image data, run

array = sim.get_data()

This array will contain all of the added shapes, as well as having any rotations, translations, and noise applied.

Saving

The synthetic image can be written to an image file by running

sim.write(outname)

The output name outname can be:

  • A path ending in .nii or .nii.gz: image will be written to a nifti file.

  • A path ending in .npy: image will be written to a binary NumPy file.

  • A path to a directory: image will be written to dicom files (one file per slice) inside the directory.

The write function can also take any of the arguments of the Image.write() function.

Adding structures

When shapes are added to the image, they can also be set as ROIs. This allows you to:

  • Plot them as contours or masks on top of the image;

  • Access a StructureSet object containing the ROIs;

  • Write ROIs out separately as masks or as a dicom structure set file.

Single ROIs

To assign a shape as an ROI, you can either give it a name upon creation, e.g.:

sim.add_sphere(50, name='my_sphere')

or set the is_roi property to True (the ROI will then be given an automatic named based on its shape type):

sim.add_sphere(50, is_roi=True)

When sim.plot() is called, its ROIs will automatically be plotted as contours. Some useful extra options to the plot function are:

  • roi_plot_type: set plot type to any of the valid ROI plotting types (mask, contour, filled, centroid, filled centroid).

  • centre_on_roi: name of ROI on which the plotted image should be centred.

  • roi_legend: set to True to draw a legend containing the strutcure names.

Grouped shapes

Multiple shapes can be combined to create a single ROI. To do this, set the group argument to some string when creating shapes. Any shapes created with the same group name will be added to this group.

E.g. to create a single ROI called “two_cubes” out of two cubes centred at different positions, run:

sim.add_cube(10, centre=(5, 5, 5), group='two_cubes')
sim.add_cube(10, centre=(7, 7, 5)), group='two_cubes')

Getting ROIs

To get a StructureSet object containing all of the ROIs belonging to the image, run:

structure_set = sim.get_structure_set()

You can also access a single ROI as an ROI object by running:

roi = sim.get_roi(name)

Saving ROIs

When the SyntheticImage.write() function is called, the ROIs belonging to that image will also be written. If the provided outname is that of a nifti or NumPy file, the ROIs will be written to nifti or Numpy files, respectively, inside a directory with the same name as outname but with the extension removed.

Synthetic Patient objects

The Patient class can be used to create a custom patient object from scratch, rather than loading a prexisting patient.

To do this, first create a blank Patient object with your chosen ID:

from skrt import Patient

p = Patient("my_id")

Studies can then be added to this object. Optional arguments for adding a study are:

  • subdir: a custom subdirectory in which the study will be nested when the Patient tree is written;

  • timestamp: a custom timestamp (if not set, this will be automatically generated)

  • images: a list of Image objects to associate with this study (note, Images can also be added to the Study later)

  • image_type: the type of image correspoding to the Images in images, if used (e.g. CT); this will determine the name of the directory in which the images are saved when the Patient tree is written.

E.g. to add one study containing a single synthetic image with one ROI:

from skrt.simulation import SyntheticImage

im = SyntheticImage((100, 100, 30))
im.add_sphere(radius=10, name="my_sphere")

p.add_study("my_study", images=[im], image_type="MR")

The patient tree can then be written out:

p.write(outdir="some_dir")

This will create a patient directory somedir/my_id containing the added study and its corresponding image and structure set.