VarianAPIs / VelocityEngine

Python and C# Clients for Velocity Scripting API
7 stars 5 forks source link

volOps.createResampledPrimaryVolume : 'Unsupported operation' #28

Open mfizyczka opened 2 years ago

mfizyczka commented 2 years ago

I'm loading CT as primaryVolume and CBCT as secondaryVolume. Then I do registrations:

cbctRegistration = regOps.createNewRegistration('cbctRegistration')
rigidRegistrationSettings = velocity.DefaultRigidRegistrationSettings()
# PreprocessingFilterMethod: CBCTCorrectionSecondary = 4
rigidRegistrationSettings.preprocessingMethod = 4
regOps.performRigidRegistrationDICOM(rigidRegistrationSettings)
regOps.saveRegistration()

deformableRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
# PreprocessingFilterMethod: CBCTCorrectionSecondary = 4
deformableRegistrationSettings.preprocessingMethod = 4
# Deformable registration Type:
deformableRegistrationSettings.type = velocity.DeformableMultiPass
regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings)
regOps.saveRegistration()

With that registration I'm trying to resample CT (primary volume) to CBCT FOR: vCtVolumeId = volOps.createResampledPrimaryVolume(0, 'vCT') volOps.getErrorMessage() returns 'Unsupported operation' why is that?

aanghele commented 2 years ago

from the guide:

createResampledPrimaryVolume(elementOperation, name = “”, scalingCoefficient = 1.0) Description Performs the resampling of the specified element operation for the loaded primary volume An error will occur if the specified element operation must be performed on multiple volumes Returns the volume id of the created volume unless there is an error, in which -1 is returned The only elementOperation available for single volume resampling is VolumeResampleScale = 7

Are you trying to use the adaptive workflow to reshape the CT ? You can use createResampledVolume() with VolumeResampleReshape op , it will create the deform-back registration automatically.

mfizyczka commented 2 years ago

Thanks for the answer. I read this description before and it wasn't clear for me. I don't want to perform resampling on multiple volumes just on Primary volume. I understand now that what you meant here was that Secondary Volume cannot be loaded.

Indeed I want to create CT - CBCT(corrected) deformable registration and then use this registration to create synthetic CT.

If I understand this correctly deformed(CT-CBCT) registration is not equal to reversed deformed(CBCT-CT) registration. That is why I was looking for solution to use the deformed(CT-CBCT).

aanghele commented 2 years ago

When you use the Reshape operation, the system is designed to use the inverse deform. The assumption is that the deformable loaded when creating the synthetic CT is built on the rigid registration corresponding to the onlinematch ( or table shifts) because the rigid component also plays a part in the reshape. That is how the GUI workflow ACTOR works as well, there is no way to bypass using the inverse deform if you want to use the Reshape operation in Velocity.

afwaller commented 2 years ago

The reshape operation (create adaptive CT) is fairly complex. It can be manually executed using just volume operations (rigid resample, deformable resample, add, subtract) but this is considerably more time consuming and will introduce errors due to aliasing, floating point math, voxel boundary alignment issues, and multiple deformable registrations (which may disagree in some slight ways). Reshape has been optimized internally to provide the highest quality result and avoid these issues, but part of that optimization is that the reshape operation does internally use the inverse transform, and also requires that your table shifts (ONLINEMATCH) are baked into the deformable - it does not use a separate rigid registration object for this.

We can schedule a call if you would like to understand more about this function and the clinical background as well as technical reasons why it was implemented in this fashion. There is also some Varian IP around the internals of how the operation works.

mfizyczka commented 2 years ago

@aanghele @afwaller thank you for your answers and explanations.

I'd certainly like to understand more about the Reshape function and adaptive CT generation. It would be great if we can schedule a call. Thanks for the offer.

At this moment I have these questions:

If I aim to reproduce adaptive CT creation as is done with ACTOR Navigator (but without loading a plan) would it be done in that way (at this moment without resampling structures):

# load pCT as secondary:
primaryVolume = engine.loadPrimaryVolume(pCtId)
print('\t\tLoading pCT as primary volume.', engine.getErrorMessage())
# load CBCT as secondary:
secondaryVolume = engine.loadSecondaryVolume(cbctId)
print('\t\tLoading CBCT as secondary volume.', engine.getErrorMessage())

# select online match registration:
for r in primaryVolume.getLinkedRegistrations(): 
  if r.getTargetVolume().getVelocityId() == cbctId and 'ONLINEMATCH' in r.getName():
    #  registrationId = r.getVelocityId()
    cbctRegistration = engine.loadRegistration(r.getVelocityId())
    print('\t\tLoading pCT-CBCT ONLINEMATCH.', engine.getErrorMessage())

# perform deformable registration:
deformableRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
# PreprocessingFilterMethod: CBCTCorrectionSecondary = 4
deformableRegistrationSettings.preprocessingMethod = 4
# Deformable registration Type:
deformableRegistrationSettings.type = velocity.DeformableMultiPass
regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings)
print('\t\tCBCT to pCT deformable registration (MultiPass with CBCTCorrectionSecondary).', regOps.getErrorMessage())
regOps.saveRegistration()
print('\t\tSaving registration.', regOps.getErrorMessage())

# reshape pCT into CBCT FOR:
# VolumeResampleReshape = 9
vCtVolumeId = volOps.createResampledVolume(9, 'vCT' + str(i) + '_cbctCorrFOR_' + secondaryVolume.getAcquisitionDate(), 1.0)
print('\t\tResampling pCT to CBCT FOR (=creating vCT).', volOps.getErrorMessage())