CTL  0.6.1
Computed Tomography Library
Public Types | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
CTL::CompositeVolume Class Reference

The CompositeVolume class is a container to hold multiple volume datasets of any type from the CTL. More...

#include <compositevolume.h>

Public Types

using SubVolPtr = CopyableUniquePtr< SpectralVolumeData >
 

Public Member Functions

template<class Volume , class... Volumes>
 CompositeVolume (Volume &&volume, Volumes &&... otherVolumes)
 Constructs a CompositeVolume and adds all data passed to the constructor as sub-volumes. More...
 
 CompositeVolume (const CompositeVolume &volume)=default
 
 CompositeVolume (CompositeVolume &&volume)=default
 
CompositeVolumeoperator= (const CompositeVolume &volume)=default
 
CompositeVolumeoperator= (CompositeVolume &&volume)=default
 
const std::vector< SubVolPtr > & data () const
 
std::vector< SubVolPtr > & data ()
 
bool isEmpty () const
 
std::unique_ptr< SpectralVolumeDatamuVolume (uint volIdx, float centerEnergy, float binWidth) const
 
uint nbSubVolumes () const
 
const SpectralVolumeDatasubVolume (uint volIdx) const
 
SpectralVolumeDatasubVolume (uint volIdx)
 
void addSubVolume (SpectralVolumeData volume)
 
void addSubVolume (std::unique_ptr< SpectralVolumeData > volume)
 
void addSubVolume (const AbstractDynamicVolumeData &volume)
 
void addSubVolume (CompositeVolume &&volume)
 
void addSubVolume (const CompositeVolume &volume)
 
template<class Volume , class... Volumes>
void addSubVolumes (Volume &&volume, Volumes &&... otherVolumes)
 Adds all data passed to this function as sub-volumes of the CompositeVolume. More...
 

Private Member Functions

void addSubVolumes () const
 

Static Private Member Functions

template<class Volume , class... Volumes>
static uint getTotalNbSubVolumes (const Volume &volume, const Volumes &... otherVolumes)
 
template<class Volume >
static constexpr uint getTotalNbSubVolumes (const Volume &volume)
 
static uint getTotalNbSubVolumes (const CompositeVolume &volume)
 

Private Attributes

std::vector< SubVolPtr_subVolumes
 the managed sub-volumes.
 

Detailed Description

The CompositeVolume class is a container to hold multiple volume datasets of any type from the CTL.

This class can hold multiple volume datasets of SpectralVolumeData or its subclasses. More precisely, an instance of CompositeVolume can consume (copy or move)

When used with a projector, the CompositeVolume object must be passed to AbstractProjector::projectComposite(). This results in computation of projections considering all sub-volumes held by the CompositeVolume object (with all their individual properties, such as spectral information or temporal dynamics; given that appropriate projector extensions are in use).

Sub-volume are added to the container using addSubVolume(). Alternatively, the CompositeVolume can be created directly using a constructor and passing to it all sub-volumes that shall be added.

All sub-volumes may differ in any arbitrary property, for example:

The following code example shows one possibility to construct a volume consisting of a cube filled with extinction value 0.02/mm and two balls, a smaller one with 0.05/mm and a slightly larger one with 0.1/mm. We want the first ball to be positioned slightly in negative y-direction and the second one in the opposite direction.

// Construct the composite volume already containing the cube volume.
CompositeVolume volume(VoxelVolume<float>::cube(150, 1.0f, 0.02f));
// We now construct the two ball volumes.
auto subVolume1 = VoxelVolume<float>::ball(10.0f, 1.0f, 0.05f);
auto subVolume2 = VoxelVolume<float>::ball(25.0f, 1.0f, 0.10f);
// Here, we shift the ball volumes to the desired positions.
subVolume1.setVolumeOffset(0.0f, -20.0f, 0.0f);
subVolume2.setVolumeOffset(0.0f, 30.0f, 0.0f);
// Now, we add the two balls as sub-volumes to our final volume.
volume.addSubVolume(std::move(subVolume1));
volume.addSubVolume(std::move(subVolume2));

We can now create a projection image from this composite with the following example code:

// First, we need to define an acquisition setup (with a CT system and the number of views; 10 in this case)
AcquisitionSetup setup(CTSystemBuilder::createFromBlueprint(blueprints::GenericCarmCT(DetectorBinning::Binning4x4)), 10);
// We also need to specify the acquisition geometry, here we set a simple short scan trajectory
setup.applyPreparationProtocol(protocols::ShortScanTrajectory(750.0f));
// Now, we create our projector, here we simply use the standard pipeline.
auto projector = makeProjector<StandardPipeline>();
// Pass the acquisition setup to the projector and create the projections:
projector->configure(setup);
auto projections = projector->projectComposite(volume);
First view of the projections generated with the above example.

The same can be done with spectral volumes as well. It is also possible to mix both types as shown in the following example. Note, however, that these mixtures are currently (v. 0.3.1) only supported in the non-linear case of SpectralEffectsExtension (which is used for example with the StandardPipeline in No_Approximation preset).

// Our starting volume remains the same. This is the sub-volume without spectral information.
CompositeVolume volume(VoxelVolume<float>::cube(150, 1.0f, 0.02f));
// We now create two balls with spectral information (one representing blood, the other bone).
auto subVolume1 = SpectralVolumeData::ball(10.0f, 1.0f, 1.0f, attenuationModel(database::Composite::Blood));
auto subVolume2 = SpectralVolumeData::ball(25.0f, 1.0f, 1.0f, attenuationModel(database::Composite::Bone_Cortical));
// Again, the shift to the desired positions...
subVolume1.setVolumeOffset(0.0f, -20.0f, 0.0f);
subVolume2.setVolumeOffset(0.0f, 30.0f, 0.0f);
// ... and adding to the final volume.
volume.addSubVolume(std::move(subVolume1));
volume.addSubVolume(std::move(subVolume2));
// In the projection code, we only change the setting for the standard pipeline to 'No_Approximation'...
AcquisitionSetup setup(CTSystemBuilder::createFromBlueprint(blueprints::GenericCarmCT(DetectorBinning::Binning4x4)), 10);
setup.applyPreparationProtocol(protocols::ShortScanTrajectory(750.0f));
//... here comes the changed line:
auto projector = makeProjector<StandardPipeline>(StandardPipeline::No_Approximation);
projector->configure(setup);
auto projections = projector->projectComposite(volume);
First view of the projections generated with the example for mixed volumes.

Constructor & Destructor Documentation

◆ CompositeVolume()

template<class Volume , class... Volumes>
CTL::CompositeVolume::CompositeVolume ( Volume &&  volume,
Volumes &&...  otherVolumes 
)
explicit

Constructs a CompositeVolume and adds all data passed to the constructor as sub-volumes.

Data passed to this constructor can be any number of volume objects of any of the following types:

Examples:

// SpectralVolumeData - pass a water cube
CompositeVolume volume(SpectralVolumeData::cube(50, 1.0f, 1.0f, attenuationModel(database::Composite::Water)));
// VoxelVolume (i.e. representing attenuation coefficients)
CompositeVolume volume2(VoxelVolume<float>::ball(20.0f, 1.0f, 0.05f)); // this uses implicit cast to SpectralVolumeData
// dynamic volume - cube that increases in attenuation by 0.01/mm per millisecond
CompositeVolume volume3(LinearDynamicVolume(0.01f, 0.0f, { 100, 100, 100 }, { 1.0f, 1.0f, 1.0f }));
// CompositeVolume and SpectralVolumeData - one CompositeVolume (containing two balls) as well as a single cube volume
CompositeVolume volume4(CompositeVolume {
SpectralVolumeData::ball(15.0f, 1.0f, 1.0f, attenuationModel(database::Composite::Blood)),
SpectralVolumeData::ball(15.0f, 1.0f, 1.1f, attenuationModel(database::Composite::Blood))
},
SpectralVolumeData::cube(100, 1.0f, 1.0f, attenuationModel(database::Composite::Water)));

Member Function Documentation

◆ addSubVolume() [1/5]

void CTL::CompositeVolume::addSubVolume ( SpectralVolumeData  volume)

Adds volume as aub-volume to this instance.

Example:

// add a water cube
volume.addSubVolume(SpectralVolumeData::cube(50, 1.0f, 1.0f, attenuationModel(database::Composite::Water)));
// we can also add a plain VoxelVolume (i.e. representing attenuation coefficients)
volume.addSubVolume(VoxelVolume<float>::ball(20.0f, 1.0f, 0.05f)); // this uses implicit cast to SpectralVolumeData

◆ addSubVolume() [2/5]

void CTL::CompositeVolume::addSubVolume ( std::unique_ptr< SpectralVolumeData volume)

Adds volume as aub-volume to this instance.

◆ addSubVolume() [3/5]

void CTL::CompositeVolume::addSubVolume ( const AbstractDynamicVolumeData volume)

Adds volume as aub-volume to this instance. The volume will be cloned.

Example:

// define a simple dynamic volume: cube that increases in attenuation by 0.01/mm per millisecond
LinearDynamicVolume dynamicVol(0.01f, 0.0f, { 100, 100, 100 }, { 1.0f, 1.0f, 1.0f });
// add it as sub-volume
volume.addSubVolume(dynamicVol);

◆ addSubVolume() [4/5]

void CTL::CompositeVolume::addSubVolume ( CompositeVolume &&  volume)

Adds all sub-volumes of volume to this instance.

Example:

CompositeVolume volume; // our final volume
// We first add a water cube to the volume
volume.addSubVolume(SpectralVolumeData::cube(100, 1.0f, 1.0f, attenuationModel(database::Composite::Water)));
// We now add another composite, consisting of two testicle balls.
volume.addSubVolume(CompositeVolume(SpectralVolumeData::ball(15.0f, 1.0f, 1.0f, attenuationModel(database::Composite::Testis)),
SpectralVolumeData::ball(15.0f, 1.0f, 1.1f, attenuationModel(database::Composite::Testis))));
// If necessary, we can now shift individual sub-volumes slightly around the center, e.g. like that:
volume.subVolume(1).setVolumeOffset(-20.0f, 0.0f, 0.0f); // shifts ball 1 towards a negative x position
volume.subVolume(2).setVolumeOffset( 20.0f, 0.0f, 0.0f); // shifts ball 2 towards a positive x position

◆ addSubVolume() [5/5]

void CTL::CompositeVolume::addSubVolume ( const CompositeVolume volume)

Adds all sub-volumes of volume to this instance. All sub-volumes will be cloned.

Example:

CompositeVolume volume; // our final volume
// We first add a water cube to the volume
volume.addSubVolume(SpectralVolumeData::cube(100, 1.0f, 1.0f, attenuationModel(database::Composite::Water)));
// We now construct another composite, consisting of two testicle balls.
CompositeVolume subComposite {
SpectralVolumeData::ball(15.0f, 1.0f, 1.0f, attenuationModel(database::Composite::Testis)),
SpectralVolumeData::ball(15.0f, 1.0f, 1.1f, attenuationModel(database::Composite::Testis))
};
// We shift both sub-volumes slightly around the center.
subComposite.subVolume(0).setVolumeOffset(-20.0f, 0.0f, 0.0f);
subComposite.subVolume(1).setVolumeOffset( 20.0f, 0.0f, 0.0f);
// Now, we can add the composite containing the two balls to our final volume (which already holds the water cube).
volume.addSubVolume(subComposite);

◆ addSubVolumes()

template<class Volume , class... Volumes>
void CTL::CompositeVolume::addSubVolumes ( Volume &&  volume,
Volumes &&...  otherVolumes 
)

Adds all data passed to this function as sub-volumes of the CompositeVolume.

Data passed to this method can be any number of volume objects of any of the following types:

◆ data() [1/2]

const std::vector< CompositeVolume::SubVolPtr > & CTL::CompositeVolume::data ( ) const

Returns a constant reference to the data managed by this instance.

◆ data() [2/2]

std::vector< CompositeVolume::SubVolPtr > & CTL::CompositeVolume::data ( )

Returns a (modifiably) reference to the data managed by this instance.

◆ getTotalNbSubVolumes() [1/3]

template<class Volume , class... Volumes>
uint CTL::CompositeVolume::getTotalNbSubVolumes ( const Volume &  volume,
const Volumes &...  otherVolumes 
)
staticprivate

Returns the total number of (sub-)volumes that is passed.

◆ getTotalNbSubVolumes() [2/3]

template<class Volume >
constexpr uint CTL::CompositeVolume::getTotalNbSubVolumes ( const Volume &  volume)
staticprivate

Handles all non-composite volume types. Returns one, accordingly.

◆ getTotalNbSubVolumes() [3/3]

uint CTL::CompositeVolume::getTotalNbSubVolumes ( const CompositeVolume volume)
inlinestaticprivate

Handels CompositeVolume input to getTotalNbSubVolumes(). Returns the number of (sub-)volumes in volume.

◆ isEmpty()

bool CTL::CompositeVolume::isEmpty ( ) const

Returns true if this instance has no sub-volumes.

◆ muVolume()

std::unique_ptr< SpectralVolumeData > CTL::CompositeVolume::muVolume ( uint  volIdx,
float  centerEnergy,
float  binWidth 
) const

Convenience method; returns the sub-volume at position volIdx transformed to attenuation values corresponding to the energy bin specified by centerEnergy and binWidth. Same as: subVolume(volIdx).muVolume(centerEnergy, binWidth)

Does not perform out-of-range checks.

See also
SpectralVolumeData::muVolume().

◆ nbSubVolumes()

uint CTL::CompositeVolume::nbSubVolumes ( ) const

Returns the number of sub-volumes in this instance.

◆ subVolume() [1/2]

const SpectralVolumeData & CTL::CompositeVolume::subVolume ( uint  volIdx) const

Returns a constant reference to the sub-volume at position volIdx.

Does not perform out-of-range checks.

◆ subVolume() [2/2]

SpectralVolumeData & CTL::CompositeVolume::subVolume ( uint  volIdx)

Returns a (modifiable) reference to the sub-volume at position volIdx.

Does not perform out-of-range checks.


The documentation for this class was generated from the following files: