Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended Multi Pass registration error #18

Open
mfizyczka opened this issue Feb 21, 2022 · 9 comments
Open

Extended Multi Pass registration error #18

mfizyczka opened this issue Feb 21, 2022 · 9 comments

Comments

@mfizyczka
Copy link

In some cases I'm getting this error for Extended MultiPass registration:
Exception has occurred: RuntimeError
Registration error. Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDBENDM1REU2MkYwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDIzMDBFNDQ3OTAwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDIzMDA1QjVDMEQwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiAyMjQ3NzAKICBEZWJ1ZzogT2ZmCiAgT2JqZWN0IE5hbWU6IAogIE9ic2VydmVyczogCiAgICBub25lCiAgU291cmNlOiAobm9uZSkKICBTb3VyY2Ugb3V0cHV0IG5hbWU6IChub25lKQogIFJlbGVhc2UgRGF0YTogT2ZmCiAgRGF0YSBSZWxlYXNlZDogRmFsc2UKICBHbG9iYWwgUmVsZWFzZSBEYXRhOiBPZmYKICBQaXBlbGluZU1UaW1lOiAwCiAgVXBkYXRlTVRpbWU6IDAKICBSZWFsVGltZVN0YW1wOiAwIHNlY29uZHMgCiAgTGFyZ2VzdFBvc3NpYmxlUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBCdWZmZXJlZFJlZ2lvbjogCiAgICBEaW1lbnNpb246IDIKICAgIEluZGV4OiBbMCwgMF0KICAgIFNpemU6IFs1MCwgNTBdCiAgUmVxdWVzdGVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBTcGFjaW5nOiBbMTQyNC42NywgMTQyNC42N10KICBPcmlnaW46IFswLCAwXQogIERpcmVjdGlvbjogCjEgMAowIDEKCiAgSW5kZXhUb1BvaW50TWF0cml4OiAKMTQyNC42NyAwCjAgMTQyNC42NwoKICBQb2ludFRvSW5kZXhNYXRyaXg6IAowLjAwMDcwMTkxNSAwCjAgMC4wMDA3MDE5MTUKCiAgSW52ZXJzZSBEaXJlY3Rpb246IAoxIDAKMCAxCgogIFBpeGVsQ29udGFpbmVyOiAKICAgIEltcG9ydEltYWdlQ29udGFpbmVyICgwMDAwMDIzMDBFOEFGRTgwKQogICAgICBSVFRJIHR5cGVpbmZvOiAgIGNsYXNzIGl0azo6SW1wb3J0SW1hZ2VDb250YWluZXI8dW5zaWduZWQgX19pbnQ2NCxkb3VibGU+CiAgICAgIFJlZmVyZW5jZSBDb3VudDogMQogICAgICBNb2RpZmllZCBUaW1lOiAyMjQ3NzEKICAgICAgRGVidWc6IE9mZgogICAgICBPYmplY3QgTmFtZTogCiAgICAgIE9ic2VydmVyczogCiAgICAgICAgbm9uZQogICAgICBQb2ludGVyOiAwMDAwMDIzMDBFODJGMzUwCiAgICAgIENvbnRhaW5lciBtYW5hZ2VzIG1lbW9yeTogdHJ1ZQogICAgICBTaXplOiAyNTAwCiAgICAgIENhcGFjaXR5OiAyNTAwCgoK

I can perform Extended MP registration in Velocity Application for the same case.
What does this error mean and how can I overcome it?

@aanghele
Copy link
Member

Can you attach some lines of code with what parameters you are changing in the registration settings object before you run it. A few questions:
-Are you setting an ROI and/or any other params
-Are you using DefaultBSplineDeformableRegistrationSettings or BSplineDeformableRegistrationSettings to run the registration
-Are you doing a rigid before the deformable in scripting ?

@mfizyczka
Copy link
Author

mfizyczka commented Feb 22, 2022

I'm using BSplineDeformableRegistrationSettings. I made a test with DefaultBSplineDeformableRegistrationSettings, but I'm not sure that I'm using Default Settings correctly. I cannot really check what are these default settings. I tried setting everything manually with values given in Velocity API manual as default values).

I have these functions to define settings:

def createRigidRegistrationSettingsObject(iRoiRegion = None,
  iPrimaryStartLevel=200, iPrimaryEndLevel=1700, iSecondaryStartLevel=200, iSecondaryEndLevel=1700,
  iPreProcessingMethod = 0, iPerformInitialAutoAlignment = True, 
  iDisableRotationsX = False, iDisableRotationsY = False, iDisableRotationsZ = False,
  iDisableTranslationsX = False, iDisableTranslationsY = False, iDisableTranslationsZ = False,
  iMaximumNumberOfIterations = 45, iMinimumStepLength = 0.0001, iMaximumStepLength = 7.0, 
  iSamplesDenominator = 10, iNumberOfHistogramBins = 25):
  
# Define Rigid Registration Settings
  regSettings = velocity.RigidRegistrationSettingsStructure()

  if iRoiRegion is not None: 
    regSettings.roiStart[0] = iRoiRegion.start[0]
    regSettings.roiStart[1] = iRoiRegion.start[1]
    regSettings.roiStart[2] = iRoiRegion.start[2]
    regSettings.roiEnd[0] = iRoiRegion.end[0]
    regSettings.roiEnd[1] = iRoiRegion.end[1]
    regSettings.roiEnd[2] = iRoiRegion.end[2]

  regSettings.primaryStartLevel = iPrimaryStartLevel
  regSettings.primaryEndLevel = iPrimaryEndLevel
  regSettings.secondaryStartLevel =  iSecondaryStartLevel
  regSettings.secondaryEndLevel = iSecondaryEndLevel

  regSettings.preProcessingMethod = iPreProcessingMethod
  regSettings.performInitialAutoAlignment = iPerformInitialAutoAlignment
  regSettings.disableRotationsX = iDisableRotationsX
  regSettings.disableRotationsY = iDisableRotationsY
  regSettings.disableRotationsZ = iDisableRotationsZ
  regSettings.disableTranslationsX = iDisableTranslationsX
  regSettings.disableTranslationsy = iDisableTranslationsY
  regSettings.disableTranslationsZ = iDisableTranslationsZ
  regSettings.maximumNumberOfIterations = iMaximumNumberOfIterations
  regSettings.minimumStepLength = iMinimumStepLength
  regSettings.maximumStepLength = iMaximumStepLength
  regSettings.samplesDenominator = iSamplesDenominator
  regSettings.numberOfHistogramBins = iNumberOfHistogramBins

  return regSettings
def createDeformableRegistrationSettingsObject(iRoiRegion = None,
  iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700,
  iPreProcessingMethod = 0, iNumberOfMultiResolutionLevels=3, iApplyBoundaryContinuityConstraints = False, iApplyTopologicalRegularizer = False,
  iGradientMagnitudeTolerance = 0.000000000000000000005, iGridCellSize = (5.0, 10.0, 15.0), iGridCellSizeType = 'n', 
  iMaximumNumberOfIterations = 30, iMaximumNumberOfConsecutiveOptimizerAttempts = 10, iMetricValuePercentageDifference = 0.0,
  iMinimumStepLength = 0.000001, iMaximumStepLength = 100.0, iNumberOfHistogramBins = 50, iRelaxationFactor = 0.9, iSamplesDenominator = 5,
  iTopologicalRegularizerDistanceLimitingCoefficient = velocity.VectorR3d(0.0)):

  # Define Deformable Registration Settings
  bsplineSettings = velocity.BSplineDeformableRegistrationSettingsStructure()

  # if roiRegion is None set it to overlap:
  if iRoiRegion is not None: 
    bsplineSettings.roiStart[0] = iRoiRegion.start[0]
    bsplineSettings.roiStart[1] = iRoiRegion.start[1]
    bsplineSettings.roiStart[2] = iRoiRegion.start[2]
    bsplineSettings.roiEnd[0] = iRoiRegion.end[0]
    bsplineSettings.roiEnd[1] = iRoiRegion.end[1]
    bsplineSettings.roiEnd[2] = iRoiRegion.end[2]

  # setting intensity range as in HPTC protocol (for CBCT?); values in HU (200HU-1700HU selects bones)
  # notebook p.77
  bsplineSettings.primaryStartLevel = iPrimaryStartLevel
  bsplineSettings.primaryEndLevel = iPrimaryEndLevel
  bsplineSettings.secondaryStartLevel = iSecondaryStartLevel
  bsplineSettings.secondaryEndLevel = iSecondaryEndLevel

  bsplineSettings.preprocessingMethod = iPreProcessingMethod
  bsplineSettings.numberOfMultiResolutionLevels = iNumberOfMultiResolutionLevels # so each vector setting should be length 3
  bsplineSettings.applyBoundaryContinuityConstraints = velocity.BoolList([iApplyBoundaryContinuityConstraints]*iNumberOfMultiResolutionLevels)
  bsplineSettings.applyTopologicalRegularizer = velocity.BoolList([iApplyTopologicalRegularizer]*iNumberOfMultiResolutionLevels)
  bsplineSettings.gradientMagnitudeTolerance = velocity.DoubleList([iGradientMagnitudeTolerance]*iNumberOfMultiResolutionLevels)
  bsplineSettings.gridCellSize = velocity.VectorR3dList(( velocity.VectorR3d(iGridCellSize[0]), velocity.VectorR3d(iGridCellSize[1]), velocity.VectorR3d(iGridCellSize[2]) ))
  bsplineSettings.gridCellSizeType = velocity.CharList([ord(iGridCellSizeType)]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumNumberOfIterations = velocity.IntList([iMaximumNumberOfIterations]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumNumberOfConsecutiveOptimizerAttempts = velocity.IntList([iMaximumNumberOfConsecutiveOptimizerAttempts]*iNumberOfMultiResolutionLevels)
  bsplineSettings.metricValuePercentageDifference = velocity.DoubleList([iMetricValuePercentageDifference]*iNumberOfMultiResolutionLevels)
  bsplineSettings.minimumStepLength = velocity.DoubleList([iMinimumStepLength]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumStepLength = velocity.DoubleList([iMaximumStepLength]*iNumberOfMultiResolutionLevels)
  bsplineSettings.numberOfHistogramBins = velocity.IntList([iNumberOfHistogramBins]*iNumberOfMultiResolutionLevels)
  bsplineSettings.relaxationFactor = velocity.DoubleList([iRelaxationFactor]*iNumberOfMultiResolutionLevels)

  bsplineSettings.samplesDenominator = velocity.IntList([iSamplesDenominator]*iNumberOfMultiResolutionLevels) # only 1/5 of pixels in ROI will be considered

  r3dZeroes = velocity.VectorR3d(0.0)
  bsplineSettings.topologicalRegularizerDistanceLimitingCoefficient = velocity.VectorR3dList([iTopologicalRegularizerDistanceLimitingCoefficient]*iNumberOfMultiResolutionLevels)

  return bsplineSettings

1. Running only Extended with AppluBoundaryContinuity set to False:

regisrtrationName = 'apiExt'
registration = regOps.createNewRegistration(regisrtrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))

overlapRegion = volOps.getVolumeOverlapRegionDICOM()

# RUN DEFORMABLE REGISTRATION
# velocity.DefaultBSplineDeformableRegistrationSettings
print('Performing deformable registration...')
deformableRegistrationSettitngs = createDeformableRegistrationSettingsObject(iRoiRegion = overlapRegion,
  iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700, 
  iNumberOfMultiResolutionLevels=5, iApplyBoundaryContinuityConstraints=False)
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

# changes are just in memory, save changes to the databases
orThrow(regOps.saveRegistration(), regOps)

Output:

Performing deformable registration...
Registration error.  Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDBGMkI2OUU4RTYwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDI2Njc2MThDNUYwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDI2Njc2QThEM0IwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiAxMjA1NQogIERlYnVnOiBPZmYKICBPYmplY3QgTmFtZTogCiAgT2JzZXJ2ZXJzOiAKICAgIG5vbmUKICBTb3VyY2U6IChub25lKQogIFNvdXJjZSBvdXRwdXQgbmFtZTogKG5vbmUpCiAgUmVsZWFzZSBEYXRhOiBPZmYKICBEYXRhIFJlbGVhc2VkOiBGYWxzZQogIEdsb2JhbCBSZWxlYXNlIERhdGE6IE9mZgogIFBpcGVsaW5lTVRpbWU6IDAKICBVcGRhdGVNVGltZTogMAogIFJlYWxUaW1lU3RhbXA6IDAgc2Vjb25kcyAKICBMYXJnZXN0UG9zc2libGVSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIEJ1ZmZlcmVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBSZXF1ZXN0ZWRSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIFNwYWNpbmc6IFsxNDI0LjY3LCAxNDI0LjY1XQogIE9yaWdpbjogWzAsIDBdCiAgRGlyZWN0aW9uOiAKMSAwCjAgMQoKICBJbmRleFRvUG9pbnRNYXRyaXg6IAoxNDI0LjY3IDAKMCAxNDI0LjY1CgogIFBvaW50VG9JbmRleE1hdHJpeDogCjAuMDAwNzAxOTE1IDAKMCAwLjAwMDcwMTkyNgoKICBJbnZlcnNlIERpcmVjdGlvbjogCjEgMAowIDEKCiAgUGl4ZWxDb250YWluZXI6IAogICAgSW1wb3J0SW1hZ2VDb250YWluZXIgKDAwMDAwMjY2MDAyOTY3RTApCiAgICAgIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbXBvcnRJbWFnZUNvbnRhaW5lcjx1bnNpZ25lZCBfX2ludDY0LGRvdWJsZT4KICAgICAgUmVmZXJlbmNlIENvdW50OiAxCiAgICAgIE1vZGlmaWVkIFRpbWU6IDEyMDU2CiAgICAgIERlYnVnOiBPZmYKICAgICAgT2JqZWN0IE5hbWU6IAogICAgICBPYnNlcnZlcnM6IAogICAgICAgIG5vbmUKICAgICAgUG9pbnRlcjogMDAwMDAyNjYwMDdGNjAwMAogICAgICBDb250YWluZXIgbWFuYWdlcyBtZW1vcnk6IHRydWUKICAgICAgU2l6ZTogMjUwMAogICAgICBDYXBhY2l0eTogMjUwMAoKCg
Traceback (most recent call last):
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 125, in <module>
    orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 35, in orThrow
    raise RuntimeError(e.getErrorMessage())
RuntimeError: Registration error.  Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDBGMkI2OUU4RTYwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDI2Njc2MThDNUYwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDI2Njc2QThEM0IwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiAxMjA1NQogIERlYnVnOiBPZmYKICBPYmplY3QgTmFtZTogCiAgT2JzZXJ2ZXJzOiAKICAgIG5vbmUKICBTb3VyY2U6IChub25lKQogIFNvdXJjZSBvdXRwdXQgbmFtZTogKG5vbmUpCiAgUmVsZWFzZSBEYXRhOiBPZmYKICBEYXRhIFJlbGVhc2VkOiBGYWxzZQogIEdsb2JhbCBSZWxlYXNlIERhdGE6IE9mZgogIFBpcGVsaW5lTVRpbWU6IDAKICBVcGRhdGVNVGltZTogMAogIFJlYWxUaW1lU3RhbXA6IDAgc2Vjb25kcyAKICBMYXJnZXN0UG9zc2libGVSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIEJ1ZmZlcmVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBSZXF1ZXN0ZWRSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIFNwYWNpbmc6IFsxNDI0LjY3LCAxNDI0LjY1XQogIE9yaWdpbjogWzAsIDBdCiAgRGlyZWN0aW9uOiAKMSAwCjAgMQoKICBJbmRleFRvUG9pbnRNYXRyaXg6IAoxNDI0LjY3IDAKMCAxNDI0LjY1CgogIFBvaW50VG9JbmRleE1hdHJpeDogCjAuMDAwNzAxOTE1IDAKMCAwLjAwMDcwMTkyNgoKICBJbnZlcnNlIERpcmVjdGlvbjogCjEgMAowIDEKCiAgUGl4ZWxDb250YWluZXI6IAogICAgSW1wb3J0SW1hZ2VDb250YWluZXIgKDAwMDAwMjY2MDAyOTY3RTApCiAgICAgIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbXBvcnRJbWFnZUNvbnRhaW5lcjx1bnNpZ25lZCBfX2ludDY0LGRvdWJsZT4KICAgICAgUmVmZXJlbmNlIENvdW50OiAxCiAgICAgIE1vZGlmaWVkIFRpbWU6IDEyMDU2CiAgICAgIERlYnVnOiBPZmYKICAgICAgT2JqZWN0IE5hbWU6IAogICAgICBPYnNlcnZlcnM6IAogICAgICAgIG5vbmUKICAgICAgUG9pbnRlcjogMDAwMDAyNjYwMDdGNjAwMAogICAgICBDb250YWluZXIgbWFuYWdlcyBtZW1vcnk6IHRydWUKICAgICAgU2l6ZTogMjUwMAogICAgICBDYXBhY2l0eTogMjUwMAoKCg

2. With default settings it works (or does it? - I run it again and now I have an error)

# RUN DEFORMABLE REGISTRATION
deformableRegistrationSettitngs = velocity.DefaultBSplineDeformableRegistrationSettings
print('Performing deformable registration...')
# deformableRegistrationSettitngs = createDeformableRegistrationSettingsObject(iRoiRegion = overlapRegion,
#   iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700, 
#   iNumberOfMultiResolutionLevels=5, iApplyBoundaryContinuityConstraints=False)
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

Output:

Performing rigid registration...

done
Performing deformable registration...

done

Second attempt

registrationName = 'apiExtCont'
registration = regOps.createNewRegistration(registrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))

overlapRegion = volOps.getVolumeOverlapRegionDICOM()

# RUN DEFORMABLE REGISTRATION
deformableRegistrationSettitngs = velocity.DefaultBSplineDeformableRegistrationSettings
# print('Performing deformable registration...')
# deformableRegistrationSettitngs = createDeformableRegistrationSettingsObject(iRoiRegion = overlapRegion,
#   iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700, 
#   iNumberOfMultiResolutionLevels=3, iApplyBoundaryContinuityConstraints=False)
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

print(f'Registration type: {registration.getType()}')

Output:

Traceback (most recent call last):
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 125, in <module>
    orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
TypeError: Wrong number or type of arguments for overloaded function 'RegistrationOperations_performBsplineRegistrationDICOM'.
  Possible C/C++ prototypes are:
    vsc::RegistrationOperations::performBsplineRegistrationDICOM(vsc::BSplineDeformableRegistrationSettingsStructure)
    vsc::RegistrationOperations::performBsplineRegistrationDICOM(vsc::DefaultBSplineDeformableRegistrationSettings const &)

3. Doing Rigid registration first doesn't help:

regisrtrationName = 'apiRegExt'
registration = regOps.createNewRegistration(regisrtrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))

overlapRegion = volOps.getVolumeOverlapRegionDICOM()

# RUN RIGID REGISTRATION

defaultRigidSettings = velocity.DefaultRigidRegistrationSettings
print('Performing rigid registration...')
rigidRegistrationSettings = createRigidRegistrationSettingsObject(iRoiRegion = overlapRegion,
  iPrimaryStartLevel=200, iPrimaryEndLevel=1700, iSecondaryStartLevel=200, iSecondaryEndLevel=1700)
orThrow(regOps.performRigidRegistrationDICOM(rigidRegistrationSettings), regOps)
print('done')

# RUN DEFORMABLE REGISTRATION
# deformableRegistrationSettitngs = velocity.DefaultBSplineDeformableRegistrationSettings
print('Performing deformable registration...')
deformableRegistrationSettitngs = createDeformableRegistrationSettingsObject(iRoiRegion = overlapRegion,
  iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700, 
  iNumberOfMultiResolutionLevels=5, iApplyBoundaryContinuityConstraints=False)
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

# changes are just in memory, save changes to the databases
orThrow(regOps.saveRegistration(), regOps)

Output:

Performing rigid registration...

done
Performing deformable registration...
Registration error.  Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDAxOEFCM0U4RDgwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDE5QUQzOTk1NDQwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDE5QUQ0MUM5MUQwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiA0Nzk0MgogIERlYnVnOiBPZmYKICBPYmplY3QgTmFtZTogCiAgT2JzZXJ2ZXJzOiAKICAgIG5vbmUKICBTb3VyY2U6IChub25lKQogIFNvdXJjZSBvdXRwdXQgbmFtZTogKG5vbmUpCiAgUmVsZWFzZSBEYXRhOiBPZmYKICBEYXRhIFJlbGVhc2VkOiBGYWxzZQogIEdsb2JhbCBSZWxlYXNlIERhdGE6IE9mZgogIFBpcGVsaW5lTVRpbWU6IDAKICBVcGRhdGVNVGltZTogMAogIFJlYWxUaW1lU3RhbXA6IDAgc2Vjb25kcyAKICBMYXJnZXN0UG9zc2libGVSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIEJ1ZmZlcmVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBSZXF1ZXN0ZWRSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIFNwYWNpbmc6IFsxNDI0LjY3LCAxNDI0LjY1XQogIE9yaWdpbjogWzAsIDBdCiAgRGlyZWN0aW9uOiAKMSAwCjAgMQoKICBJbmRleFRvUG9pbnRNYXRyaXg6IAoxNDI0LjY3IDAKMCAxNDI0LjY1CgogIFBvaW50VG9JbmRleE1hdHJpeDogCjAuMDAwNzAxOTE1IDAKMCAwLjAwMDcwMTkyNgoKICBJbnZlcnNlIERpcmVjdGlvbjogCjEgMAowIDEKCiAgUGl4ZWxDb250YWluZXI6IAogICAgSW1wb3J0SW1hZ2VDb250YWluZXIgKDAwMDAwMTlBREQwQUU1NTApCiAgICAgIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbXBvcnRJbWFnZUNvbnRhaW5lcjx1bnNpZ25lZCBfX2ludDY0LGRvdWJsZT4KICAgICAgUmVmZXJlbmNlIENvdW50OiAxCiAgICAgIE1vZGlmaWVkIFRpbWU6IDQ3OTQzCiAgICAgIERlYnVnOiBPZmYKICAgICAgT2JqZWN0IE5hbWU6IAogICAgICBPYnNlcnZlcnM6IAogICAgICAgIG5vbmUKICAgICAgUG9pbnRlcjogMDAwMDAxOUFERDc4RkJEMAogICAgICBDb250YWluZXIgbWFuYWdlcyBtZW1vcnk6IHRydWUKICAgICAgU2l6ZTogMjUwMAogICAgICBDYXBhY2l0eTogMjUwMAoKCg
Traceback (most recent call last):
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 125, in <module>
    orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 35, in orThrow
    raise RuntimeError(e.getErrorMessage())
RuntimeError: Registration error.  Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDAxOEFCM0U4RDgwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDE5QUQzOTk1NDQwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDE5QUQ0MUM5MUQwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiA0Nzk0MgogIERlYnVnOiBPZmYKICBPYmplY3QgTmFtZTogCiAgT2JzZXJ2ZXJzOiAKICAgIG5vbmUKICBTb3VyY2U6IChub25lKQogIFNvdXJjZSBvdXRwdXQgbmFtZTogKG5vbmUpCiAgUmVsZWFzZSBEYXRhOiBPZmYKICBEYXRhIFJlbGVhc2VkOiBGYWxzZQogIEdsb2JhbCBSZWxlYXNlIERhdGE6IE9mZgogIFBpcGVsaW5lTVRpbWU6IDAKICBVcGRhdGVNVGltZTogMAogIFJlYWxUaW1lU3RhbXA6IDAgc2Vjb25kcyAKICBMYXJnZXN0UG9zc2libGVSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIEJ1ZmZlcmVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBSZXF1ZXN0ZWRSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIFNwYWNpbmc6IFsxNDI0LjY3LCAxNDI0LjY1XQogIE9yaWdpbjogWzAsIDBdCiAgRGlyZWN0aW9uOiAKMSAwCjAgMQoKICBJbmRleFRvUG9pbnRNYXRyaXg6IAoxNDI0LjY3IDAKMCAxNDI0LjY1CgogIFBvaW50VG9JbmRleE1hdHJpeDogCjAuMDAwNzAxOTE1IDAKMCAwLjAwMDcwMTkyNgoKICBJbnZlcnNlIERpcmVjdGlvbjogCjEgMAowIDEKCiAgUGl4ZWxDb250YWluZXI6IAogICAgSW1wb3J0SW1hZ2VDb250YWluZXIgKDAwMDAwMTlBREQwQUU1NTApCiAgICAgIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbXBvcnRJbWFnZUNvbnRhaW5lcjx1bnNpZ25lZCBfX2ludDY0LGRvdWJsZT4KICAgICAgUmVmZXJlbmNlIENvdW50OiAxCiAgICAgIE1vZGlmaWVkIFRpbWU6IDQ3OTQzCiAgICAgIERlYnVnOiBPZmYKICAgICAgT2JqZWN0IE5hbWU6IAogICAgICBPYnNlcnZlcnM6IAogICAgICAgIG5vbmUKICAgICAgUG9pbnRlcjogMDAwMDAxOUFERDc4RkJEMAogICAgICBDb250YWluZXIgbWFuYWdlcyBtZW1vcnk6IHRydWUKICAgICAgU2l6ZTogMjUwMAogICAgICBDYXBhY2l0eTogMjUwMAoKCg

4. Without Rigid, changing ApplyBoundaryContinuityConstraints=True

print('Performing deformable registration...')
deformableRegistrationSettitngs = createDeformableRegistrationSettingsObject(iRoiRegion = overlapRegion,
  iPrimaryStartLevel=-250, iPrimaryEndLevel=1700, iSecondaryStartLevel=-250, iSecondaryEndLevel=1700, 
  iNumberOfMultiResolutionLevels=5, iApplyBoundaryContinuityConstraints=True)
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

Output:

Performing deformable registration...

done

@aanghele
Copy link
Member

aanghele commented Feb 22, 2022

if you want to do an extended pass with default settings you have to set this

deformableRegistrationSettitngs = velocity.DefaultBSplineDeformableRegistrationSettings()
deformableRegistrationSettitngs.type = velocity.DeformableExtendedPass
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)

otherwise the default is multipass.

Hard to tell why the manual settings don't work in your case. In the default settings structure , some params like primary/secondary startLevel and endLevel are chosen dynamically based on the current volumes loaded, other settings are fixed.
When the ROI is not specified, it always uses the intersection , so you don't need to pass the overlapping region.

@mfizyczka
Copy link
Author

I get this error now with the above code:

# RUN DEFORMABLE REGISTRATION
deformableRegistrationSettitngs = velocity.DefaultBSplineDeformableRegistrationSettings
deformableRegistrationSettitngs = velocity.DeformableExtendedPass
print('Performing deformable registration...')
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
print('done')

Output:

Performing deformable registration...
Traceback (most recent call last):
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\mainTargetPropagation.py", line 127, in <module>
    orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettitngs), regOps)
TypeError: Wrong number or type of arguments for overloaded function 'RegistrationOperations_performBsplineRegistrationDICOM'.
  Possible C/C++ prototypes are:
    vsc::RegistrationOperations::performBsplineRegistrationDICOM(vsc::BSplineDeformableRegistrationSettingsStructure)
    vsc::RegistrationOperations::performBsplineRegistrationDICOM(vsc::DefaultBSplineDeformableRegistrationSettings const &)

I tried to do the Extended registration in GUI with similar primary/secondary start/endLevels and it worked.
There is always AutoAlignement registration in GUI is it used by other registrations?
What are the default fixed settings used in GUI?

@jakecobb
Copy link
Contributor

Small error there, it's assigning the type velocity.DefaultBSplineDeformableRegistrationSettings not creating an instance of it. Then the second assignment should be to the type field, please try this modification:

# RUN DEFORMABLE REGISTRATION
deformableRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
deformableRegistrationSettings.type = velocity.DeformableExtendedPass
print('Performing deformable registration...')
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings), regOps)
print('done')

@mfizyczka
Copy link
Author

Ok, I think we made the same mistake with @aanghele :-)
This indeed works (I still have to check if it gives the same result as obtained in GUI).

Is it possible to create instance of default parameters and then change things which one can change in GUI?

  • primary/secondary start/endLevel
  • roi Region
  • Applying AutoAlignement (for Rigid)
  • Applying BoundaryContinuityCondition
  • Grid Settings (for Deformable): Coarse / Fine (how they relate to numbers in API?)

@aanghele
Copy link
Member

For registrations if you use the default settings you can only control:

  • roi Region
  • InitialAutoAlignment-(for Rigid) This option is equivalent to the check-box in the UI, not to be confused with the 'AutoAlignment' registration
  • pre processing methods (like MR correction, etc.)
  • type ( deformable)

At this time the user cannot enable/disable BoundaryContinuityCondition -when using the default settings, this can be considered for a future release.
Grid Settings (for Deformable): Coarse / Fine (how they relate to numbers in API?) - not available at the moment with default settings.

Default settings includes some proprietary logic (that we cannot share more details about) and it's not just fixed values.

@mfizyczka
Copy link
Author

mfizyczka commented Feb 24, 2022

I used the code below to perform MultiPass registrations. In both options with Default settings - just using two functions, I didn't change any of the settings. I'd expect to see exactly the same result. I unloaded primary and secondary Volumes to ensure that registration would be unloaded as well. However I still get Velocity Id for those volumes as well as for registration. I don't know how to check what objects are loaded at the moment. I also did a test while running just one option and having other one commented and the result was similar - i.e. in GUI I see different contours.

# DEFAULT REGISTRATION SETTINGS (MultiPass)
# load Volumes:
loadVolumesAndStructures('CT[Accession N.52]', 'CT[Accession N.55]')
deformableDefaultRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
print('\ndeformableDafaultRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()')
printRegistrationSettings('DefaultDeformable', deformableDefaultRegistrationSettings)
# create registration and perform registration:
registrationName = 'apiTestMP'
registration = regOps.createNewRegistration(registrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))
orThrow(regOps.performBsplineRegistrationDICOM(deformableDefaultRegistrationSettings), regOps)
registration = regOps.saveRegistration()
orThrow(registration, regOps)
# create a new structure set on the primary volume:
targetSetName = registrationName
targetSet = strOps.createStructureSet(targetSetName, True)
orThrow(targetSet, strOps)
# propagate structures:
orThrow(strOps.copyStructuresToPrimary([ctv5425.getVelocityId(), ctv7000.getVelocityId()], targetSet.getVelocityId()), strOps)
# save set:
orThrow(strOps.saveStructureSet(targetSet.getVelocityId()), strOps)
# unload volumes:
orThrow(engine.unloadPrimaryVolume(), engine)
orThrow(engine.unloadSecondaryVolume(), engine)
primaryVolume = engine.getPrimaryVolume()
secondaryVolume = engine.getSecondaryVolume()

# DEFINE (Multi Pass) DEFORMABLE REGISTRATION SETTINGS
# load Volumes:
loadVolumesAndStructures('CT[Accession N.52]', 'CT[Accession N.55]')
deformableRegistrationSettings = velocity.BSplineDeformableRegistrationSettingsStructure()
# deformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=3)
print('\ndeformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=3)')
printRegistrationSettings('Deformable', deformableRegistrationSettings)
# create registration and perform registration:
registrationName = 'apiTestMP2'
registration = regOps.createNewRegistration(registrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings), regOps)
registration = regOps.saveRegistration()
orThrow(registration, regOps)
# create a new structure set on the primary volume:
targetSetName = registrationName
targetSet = strOps.createStructureSet(targetSetName, True)
orThrow(targetSet, strOps)
# propagate structures:
orThrow(strOps.copyStructuresToPrimary([ctv5425.getVelocityId(), ctv7000.getVelocityId()], targetSet.getVelocityId()), strOps)
# save set:
orThrow(strOps.saveStructureSet(targetSet.getVelocityId()), strOps)
# unload volumes:
orThrow(engine.unloadPrimaryVolume(), engine)
orThrow(engine.unloadSecondaryVolume(), engine)

Output:

deformableDafaultRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
Default Deformable Registration Settings:
        Type: 3
        ROI Region: start [0.0, 0.0, 0.0], end [0.0, 0.0, 0.0]
        Preprocessing Method: 0

deformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=3)
Deformable Registration Settings:
        ROI Region: start [0.0, 0.0, 0.0], end [0.0, 0.0, 0.0]
        Primary Volume Levels: [0.0, 65535.0]
        Secondary Volume Levels: [0.0, 65535.0]
        Preprocessing Method: 0
        Number Of Multi Resolution Levels: 3
        Apply Boundary Continuity Constraints: [False, False, False]
        Apply Topological Regularizer: [False, False, False]
        Gradient Magnitude Tolerance: [5e-21, 5e-21, 5e-21]
        Grid Cell Size: [[5.0, 5.0, 5.0], [10.0, 10.0, 10.0], [15.0, 15.0, 15.0]]
        Grid Cell Size Type: ['n', 'n', 'n']
        Maximum Number Of Iterations: [30, 30, 30]
        Maximum Number Of Consecutive Optimizer Attempts: [10, 10, 10]
        Metric Value Percentage Difference: [0.0, 0.0, 0.0]
        Minimum Step Length: [1e-06, 1e-06, 1e-06]
        Maximum Step Length: [100.0, 100.0, 100.0]
        Number Of Histogram Bins: [50, 50, 50]
        Relaxation Factor: [0.9, 0.9, 0.9]
        Samples Denominator: [5, 5, 5]
        Topological Regularizer Distance Limiting Coefficient: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]

In GUI:
apiTestMP_vs_apiTestMP2

Additional functions used in the code above

def loadVolumesAndStructures(pCtName, rCtName):
  # load primary volume - volume with originally delineated structures
  primaryVolumeUID = patientVolumes[rCtName][1]
  orThrow(engine.loadPrimaryVolumeByUID(primaryVolumeUID))
  global primaryVolume
  primaryVolume = engine.getPrimaryVolume()

  # load secondary volume - to this volume structures will be progressed
  secondaryVolumeUID = patientVolumes[pCtName][1]
  orThrow(engine.loadSecondaryVolumeByUID(secondaryVolumeUID))
  global secondaryVolume
  secondaryVolume = engine.getSecondaryVolume()

  # create dictionary of StructureSets on primaryVolume
  secondaryVolumeStructureSets = {}
  for ss in secondaryVolume.getStructureSets(): secondaryVolumeStructureSets[ss.getName()] = [ss.getVelocityId(), ss.getInstanceUID()]

  # load secondary set and structures:
  secondarySetName = 'RS: Unapproved'
  secondarySet  = next(s for s in secondaryVolume.getStructureSets() if s.getName() == secondarySetName)
  global ctv7000
  ctv7000 = next(s for s in secondarySet.getStructures() if s.getName() == 'CTV_7000')
  global ctv5425
  ctv5425 = next(s for s in secondarySet.getStructures() if s.getName() == 'CTV_5425')

  return True
def printDeformableRegistrationSettings(iBsplineSettings):  
  
  print(f'Deformable Registration Settings:')
  print(f'\tROI Region: start {[iBsplineSettings.roiStart[i] for i in (0,1,2)]}, end {[iBsplineSettings.roiEnd[i] for i in (0,1,2)]}')
  print(f'\tPrimary Volume Levels: [{iBsplineSettings.primaryStartLevel}, {iBsplineSettings.primaryEndLevel}]')
  print(f'\tSecondary Volume Levels: [{iBsplineSettings.secondaryStartLevel}, {iBsplineSettings.secondaryEndLevel}]')
  print(f'\tPreprocessing Method: {iBsplineSettings.preprocessingMethod}')
  print(f'\tNumber Of Multi Resolution Levels: {iBsplineSettings.numberOfMultiResolutionLevels}')
  print(f'\tApply Boundary Continuity Constraints: {[iBsplineSettings.applyBoundaryContinuityConstraints[i] for i in range(0, len(iBsplineSettings.applyBoundaryContinuityConstraints))]}')
  print(f'\tApply Topological Regularizer: {[iBsplineSettings.applyTopologicalRegularizer[i] for i in range(0, len(iBsplineSettings.applyTopologicalRegularizer))]}')
  print(f'\tGradient Magnitude Tolerance: {[iBsplineSettings.gradientMagnitudeTolerance[i] for i in range(0, len(iBsplineSettings.gradientMagnitudeTolerance))]}')
  print(f'\tGrid Cell Size: {[[iBsplineSettings.gridCellSize[i][k] for k in range(0,3)] for i in range(0, len(iBsplineSettings.gridCellSize))]}')
  print(f'\tGrid Cell Size Type: {[iBsplineSettings.gridCellSizeType[i] for i in range(0, len(iBsplineSettings.gridCellSizeType))]}')
  print(f'\tMaximum Number Of Iterations: {[iBsplineSettings.maximumNumberOfIterations[i] for i in range(0, len(iBsplineSettings.maximumNumberOfIterations))]}')
  print(f'\tMaximum Number Of Consecutive Optimizer Attempts: {[iBsplineSettings.maximumNumberOfConsecutiveOptimizerAttempts[i] for i in range(0, len(iBsplineSettings.maximumNumberOfConsecutiveOptimizerAttempts))]}')
  print(f'\tMetric Value Percentage Difference: {[iBsplineSettings.metricValuePercentageDifference[i] for i in range(0, len(iBsplineSettings.metricValuePercentageDifference))]}')
  print(f'\tMinimum Step Length: {[iBsplineSettings.minimumStepLength[i] for i in range(0, len(iBsplineSettings.minimumStepLength))]}')
  print(f'\tMaximum Step Length: {[iBsplineSettings.maximumStepLength[i] for i in range(0, len(iBsplineSettings.maximumStepLength))]}')
  print(f'\tNumber Of Histogram Bins: {[iBsplineSettings.numberOfHistogramBins[i] for i in range(0, len(iBsplineSettings.numberOfHistogramBins))]}')
  print(f'\tRelaxation Factor: {[iBsplineSettings.relaxationFactor[i] for i in range(0, len(iBsplineSettings.relaxationFactor))]}')
  print(f'\tSamples Denominator: {[iBsplineSettings.samplesDenominator[i] for i in range(0, len(iBsplineSettings.samplesDenominator))]}')
  print(f'\tTopological Regularizer Distance Limiting Coefficient: {[[iBsplineSettings.topologicalRegularizerDistanceLimitingCoefficient[j][k] for k in range(0,3)] for j in range(0, len(iBsplineSettings.topologicalRegularizerDistanceLimitingCoefficient))]}')

  return True

def printDefaultDeformableRegistrationSettings(iBsplineSettings):  
  
  print(f'Default Deformable Registration Settings:')
  print(f'\tType: {iBsplineSettings.type}')
  print(f'\tROI Region: start {[iBsplineSettings.roiStart[i] for i in (0,1,2)]}, end {[iBsplineSettings.roiEnd[i] for i in (0,1,2)]}')
  print(f'\tPreprocessing Method: {iBsplineSettings.preprocessingMethod}')

  return True

def printRegistrationSettings(iRegistrationStringType, iRegistrationSettings):

  allowedTypes = ['Deformable', 'DefaultDeformable', 'Rigid']

  if iRegistrationStringType not in allowedTypes:
    raise Exception(f'These are allowed iRegistrationStringTypes: {allowedTypes}')

  else:
    if iRegistrationStringType == 'Deformable': printDeformableRegistrationSettings(iRegistrationSettings)
    elif iRegistrationStringType == 'DefaultDeformable': printDefaultDeformableRegistrationSettings(iRegistrationSettings)
    elif iRegistrationStringType == 'Rigid': printRegistrationSettings(iRegistrationSettings)

  return True

@mfizyczka
Copy link
Author

mfizyczka commented Feb 24, 2022

I also used similar approach to check the performance of Extended MultiPass Registration. Comparing registration settings here with those of MultiPass registration (see https://github.com/VarianAPIs/VelocityEngine/issues/18#issuecomment-1050042297 for code and output), I don't see what might be causing a problem, and I'm using parameters given in API manual as default ones. Please note that I made similar tests for BSpline and MultiPass and I didn't get the error. Still the results were somehow different between the two methods as shown in comment above.

function used to generate registration settings:

def createDeformableRegistrationSettingsObject(iRoiRegion = None,
  iPrimaryStartLevel=None, iPrimaryEndLevel=None, iSecondaryStartLevel=None, iSecondaryEndLevel=None,
  iPreProcessingMethod = 0, iNumberOfMultiResolutionLevels=3, iApplyBoundaryContinuityConstraints = False, iApplyTopologicalRegularizer = False,
  iGradientMagnitudeTolerance = 0.000000000000000000005, iGridCellSize = (5.0, 10.0, 15.0), iGridCellSizeType = 'n', 
  iMaximumNumberOfIterations = 30, iMaximumNumberOfConsecutiveOptimizerAttempts = 10, iMetricValuePercentageDifference = 0.0,
  iMinimumStepLength = 0.000001, iMaximumStepLength = 100.0, iNumberOfHistogramBins = 50, iRelaxationFactor = 0.9, iSamplesDenominator = 5,
  iTopologicalRegularizerDistanceLimitingCoefficient = velocity.VectorR3d(0.0)):  

  # Define Deformable Registration Settings
  bsplineSettings = velocity.BSplineDeformableRegistrationSettingsStructure()

  # if roiRegion is None set it to overlap:
  if iRoiRegion is not None: 
    bsplineSettings.roiStart[0] = iRoiRegion.start[0]
    bsplineSettings.roiStart[1] = iRoiRegion.start[1]
    bsplineSettings.roiStart[2] = iRoiRegion.start[2]
    bsplineSettings.roiEnd[0] = iRoiRegion.end[0]
    bsplineSettings.roiEnd[1] = iRoiRegion.end[1]
    bsplineSettings.roiEnd[2] = iRoiRegion.end[2]

  # setting intensity range as in HPTC protocol (for CBCT?); values in HU (200HU-1700HU selects bones)
  # notebook p.77
  if iPrimaryStartLevel is not None: bsplineSettings.primaryStartLevel = iPrimaryStartLevel
  if iPrimaryEndLevel is not None: bsplineSettings.primaryEndLevel = iPrimaryEndLevel
  if iSecondaryStartLevel is not None: bsplineSettings.secondaryStartLevel = iSecondaryStartLevel
  if iSecondaryEndLevel is not None: bsplineSettings.secondaryEndLevel = iSecondaryEndLevel

  bsplineSettings.preprocessingMethod = iPreProcessingMethod
  bsplineSettings.numberOfMultiResolutionLevels = iNumberOfMultiResolutionLevels # so each vector setting should be length 3
  bsplineSettings.applyBoundaryContinuityConstraints = velocity.BoolList([iApplyBoundaryContinuityConstraints]*iNumberOfMultiResolutionLevels)
  bsplineSettings.applyTopologicalRegularizer = velocity.BoolList([iApplyTopologicalRegularizer]*iNumberOfMultiResolutionLevels)
  bsplineSettings.gradientMagnitudeTolerance = velocity.DoubleList([iGradientMagnitudeTolerance]*iNumberOfMultiResolutionLevels)
  bsplineSettings.gridCellSize = velocity.VectorR3dList(( velocity.VectorR3d(iGridCellSize[0]), velocity.VectorR3d(iGridCellSize[1]), velocity.VectorR3d(iGridCellSize[2]) ))
  bsplineSettings.gridCellSizeType = velocity.CharList([ord(iGridCellSizeType)]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumNumberOfIterations = velocity.IntList([iMaximumNumberOfIterations]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumNumberOfConsecutiveOptimizerAttempts = velocity.IntList([iMaximumNumberOfConsecutiveOptimizerAttempts]*iNumberOfMultiResolutionLevels)
  bsplineSettings.metricValuePercentageDifference = velocity.DoubleList([iMetricValuePercentageDifference]*iNumberOfMultiResolutionLevels)
  bsplineSettings.minimumStepLength = velocity.DoubleList([iMinimumStepLength]*iNumberOfMultiResolutionLevels)
  bsplineSettings.maximumStepLength = velocity.DoubleList([iMaximumStepLength]*iNumberOfMultiResolutionLevels)
  bsplineSettings.numberOfHistogramBins = velocity.IntList([iNumberOfHistogramBins]*iNumberOfMultiResolutionLevels)
  bsplineSettings.relaxationFactor = velocity.DoubleList([iRelaxationFactor]*iNumberOfMultiResolutionLevels)

  bsplineSettings.samplesDenominator = velocity.IntList([iSamplesDenominator]*iNumberOfMultiResolutionLevels) # only 1/5 of pixels in ROI will be considered

  r3dZeroes = velocity.VectorR3d(0.0)
  bsplineSettings.topologicalRegularizerDistanceLimitingCoefficient = velocity.VectorR3dList([iTopologicalRegularizerDistanceLimitingCoefficient]*iNumberOfMultiResolutionLevels)

  return bsplineSettings

Code to run Extended MP registrations:

# DEFAULT REGISTRATION SETTINGS (Extended MultiPass)
# load Volumes:
loadVolumesAndStructures('CT[Accession N.52]', 'CT[Accession N.55]')
deformableDefaultRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()
deformableDefaultRegistrationSettings.type = velocity.DeformableExtendedPass
# deformableDefaultRegistrationSettings.type = velocity.DeformableMultiPass
# deformableDefaultRegistrationSettings.type = velocity.DeformableSinglePass
print('\ndeformableDafaultRegistrationSettings = velocity.DefaultBSplineDeformableRegistrationSettings()')
printRegistrationSettings('DefaultDeformable', deformableDefaultRegistrationSettings)
# create registration and perform registration:
registrationName = 'apiDefSetMPo'
# registrationName = 'apiTestMP'
# print(registrationName)
registration = regOps.createNewRegistration(registrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))
orThrow(regOps.performBsplineRegistrationDICOM(deformableDefaultRegistrationSettings), regOps)
registration = regOps.saveRegistration()
orThrow(registration, regOps)
# create a new structure set on the primary volume:
targetSetName = registrationName
targetSet = strOps.createStructureSet(targetSetName, True)
orThrow(targetSet, strOps)
# propagate structures:
orThrow(strOps.copyStructuresToPrimary([ctv5425.getVelocityId(), ctv7000.getVelocityId()], targetSet.getVelocityId()), strOps)
# save set:
orThrow(strOps.saveStructureSet(targetSet.getVelocityId()), strOps)
# unload volumes:
orThrow(engine.unloadPrimaryVolume(), engine)
orThrow(engine.unloadSecondaryVolume(), engine)

# DEFINE (Extended Multi Pass) DEFORMABLE REGISTRATION SETTINGS
# load Volumes:
loadVolumesAndStructures('CT[Accession N.52]', 'CT[Accession N.55]')
# deformableRegistrationSettings = velocity.BSplineDeformableRegistrationSettingsStructure()
deformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=5)
print('\ndeformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=5)')
printRegistrationSettings('Deformable', deformableRegistrationSettings)
# create registration and perform registration:
registrationName = 'apiDefEMP'
# registrationName = 'apiTestMP2'
# print(registrationName)
registration = regOps.createNewRegistration(registrationName)
orThrow(registration, regOps)
orThrow(engine.loadRegistration(registration.getVelocityId()))
orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings), regOps)
registration = regOps.saveRegistration()
orThrow(registration, regOps)
# create a new structure set on the primary volume:
targetSetName = registrationName
targetSet = strOps.createStructureSet(targetSetName, True)
orThrow(targetSet, strOps)
# propagate structures:
orThrow(strOps.copyStructuresToPrimary([ctv5425.getVelocityId(), ctv7000.getVelocityId()], targetSet.getVelocityId()), strOps)
# save set:
orThrow(strOps.saveStructureSet(targetSet.getVelocityId()), strOps)
# unload volumes:
orThrow(engine.unloadPrimaryVolume(), engine)
orThrow(engine.unloadSecondaryVolume(), engine)

Output:

Default Deformable Registration Settings:
        Type: 5
        ROI Region: start [0.0, 0.0, 0.0], end [0.0, 0.0, 0.0]
        Preprocessing Method: 0

deformableRegistrationSettings = createDeformableRegistrationSettingsObject(iNumberOfMultiResolutionLevels=5)
Deformable Registration Settings:
        ROI Region: start [0.0, 0.0, 0.0], end [0.0, 0.0, 0.0]
        Primary Volume Levels: [0.0, 65535.0]
        Secondary Volume Levels: [0.0, 65535.0]
        Preprocessing Method: 0
        Number Of Multi Resolution Levels: 5
        Apply Boundary Continuity Constraints: [False, False, False, False, False]
        Apply Topological Regularizer: [False, False, False, False, False]
        Gradient Magnitude Tolerance: [5e-21, 5e-21, 5e-21, 5e-21, 5e-21]
        Grid Cell Size: [[5.0, 5.0, 5.0], [10.0, 10.0, 10.0], [15.0, 15.0, 15.0]]
        Grid Cell Size Type: ['n', 'n', 'n', 'n', 'n']
        Maximum Number Of Iterations: [30, 30, 30, 30, 30]
        Maximum Number Of Consecutive Optimizer Attempts: [10, 10, 10, 10, 10]
        Metric Value Percentage Difference: [0.0, 0.0, 0.0, 0.0, 0.0]
        Minimum Step Length: [1e-06, 1e-06, 1e-06, 1e-06, 1e-06]
        Maximum Step Length: [100.0, 100.0, 100.0, 100.0, 100.0]
        Number Of Histogram Bins: [50, 50, 50, 50, 50]
        Relaxation Factor: [0.9, 0.9, 0.9, 0.9, 0.9]
        Samples Denominator: [5, 5, 5, 5, 5]
        Topological Regularizer Distance Limiting Coefficient: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
Traceback (most recent call last):
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\testExtendedMultiPassInvestigation.py", line 138, in <module>
    orThrow(regOps.performBsplineRegistrationDICOM(deformableRegistrationSettings), regOps)
  File "d:\IMAGINATION\#VelocityEngine\PythonScripting\Registrations\testExtendedMultiPassInvestigation.py", line 36, in orThrow
    raise RuntimeError(e.getErrorMessage())
RuntimeError: Registration error.  Additional details: Cml0azo6RXhjZXB0aW9uT2JqZWN0ICgwMDAwMDAwMjMyRkU4RDgwKQpMb2NhdGlvbjogInVua25vd24iIApGaWxlOiBDOlxQcm9kdWN0c1x2c2Ncc3JjXHZzYy9hbGdvcml0aG1zL1ZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYy50CkxpbmU6IDExODIKRGVzY3JpcHRpb246IGl0azo6RVJST1I6IHZzY1N0cnVjdHVyZUd1aWRlZE1ldHJpYygwMDAwMDE0NDZDQzQyNzMwKTogSm9pbnQgUERGIHN1bW1lZCB0byB6ZXJvCkltYWdlICgwMDAwMDE0NDA3NDBFOTAwKQogIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbWFnZTxkb3VibGUsMj4KICBSZWZlcmVuY2UgQ291bnQ6IDIKICBNb2RpZmllZCBUaW1lOiA1NTY4OQogIERlYnVnOiBPZmYKICBPYmplY3QgTmFtZTogCiAgT2JzZXJ2ZXJzOiAKICAgIG5vbmUKICBTb3VyY2U6IChub25lKQogIFNvdXJjZSBvdXRwdXQgbmFtZTogKG5vbmUpCiAgUmVsZWFzZSBEYXRhOiBPZmYKICBEYXRhIFJlbGVhc2VkOiBGYWxzZQogIEdsb2JhbCBSZWxlYXNlIERhdGE6IE9mZgogIFBpcGVsaW5lTVRpbWU6IDAKICBVcGRhdGVNVGltZTogMAogIFJlYWxUaW1lU3RhbXA6IDAgc2Vjb25kcyAKICBMYXJnZXN0UG9zc2libGVSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIEJ1ZmZlcmVkUmVnaW9uOiAKICAgIERpbWVuc2lvbjogMgogICAgSW5kZXg6IFswLCAwXQogICAgU2l6ZTogWzUwLCA1MF0KICBSZXF1ZXN0ZWRSZWdpb246IAogICAgRGltZW5zaW9uOiAyCiAgICBJbmRleDogWzAsIDBdCiAgICBTaXplOiBbNTAsIDUwXQogIFNwYWNpbmc6IFsxNDI0LjY3LCAxNDI0LjY3XQogIE9yaWdpbjogWzAsIDBdCiAgRGlyZWN0aW9uOiAKMSAwCjAgMQoKICBJbmRleFRvUG9pbnRNYXRyaXg6IAoxNDI0LjY3IDAKMCAxNDI0LjY3CgogIFBvaW50VG9JbmRleE1hdHJpeDogCjAuMDAwNzAxOTE1IDAKMCAwLjAwMDcwMTkxNQoKICBJbnZlcnNlIERpcmVjdGlvbjogCjEgMAowIDEKCiAgUGl4ZWxDb250YWluZXI6IAogICAgSW1wb3J0SW1hZ2VDb250YWluZXIgKDAwMDAwMTQ0NkY3QTk2QzApCiAgICAgIFJUVEkgdHlwZWluZm86ICAgY2xhc3MgaXRrOjpJbXBvcnRJbWFnZUNvbnRhaW5lcjx1bnNpZ25lZCBfX2ludDY0LGRvdWJsZT4KICAgICAgUmVmZXJlbmNlIENvdW50OiAxCiAgICAgIE1vZGlmaWVkIFRpbWU6IDU1NjkwCiAgICAgIERlYnVnOiBPZmYKICAgICAgT2JqZWN0IE5hbWU6IAogICAgICBPYnNlcnZlcnM6IAogICAgICAgIG5vbmUKICAgICAgUG9pbnRlcjogMDAwMDAxNDQ2Rjg4NEYyMAogICAgICBDb250YWluZXIgbWFuYWdlcyBtZW1vcnk6IHRydWUKICAgICAgU2l6ZTogMjUwMAogICAgICBDYXBhY2l0eTogMjUwMAoKCg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants