Hi everyone,
I'm trying to make a non-rigid registration to make point-to-point correspondences between the reference and my all meshes. I succeeded but it's really not perfect. I'm building the ssm of a scapula and I'd like the details, especially at the glenoid, to be precise enough.
From what I've understood from the tutorials, this happens at the level of the kernels, but I tested several combinations and chose the one that seemed best, but it's not great.
I'm attaching my code and a picture of what I can get as a result (scapula in pink is the reuslt of non-rigid registration).
Thank you in advance!
(ps: sorry for my english but i'm a french student.. :) )
Here my code :
val zeroMean = Field(EuclideanSpace3D, (_: Point[_3D]) => EuclideanVector.zeros[_3D])
val kernelCoarse = GaussianKernel3D(86*10)
val kernelFine = GaussianKernel3D(30*3)
val kernelfinal = kernelCoarse+kernelFine
val kernel = DiagonalKernel3D(kernelfinal, outputDim = 3)
val gp = GaussianProcess(zeroMean, kernel)
val interpolator = TriangleMeshInterpolator3D[EuclideanVector[_3D]]()
val lowRankGP = LowRankGaussianProcess.approximateGPCholesky(
reference,
gp,
relativeTolerance = 0.005,
interpolator = interpolator
)
val modelGroup = ui.createGroup("model")
val gpView = ui.addTransformation(modelGroup, lowRankGP, "gp")
def doRegistration(
lowRankGP: LowRankGaussianProcess[_3D, EuclideanVector[_3D]],
referenceMesh: TriangleMesh[_3D],
targetICP: TriangleMesh[_3D],
initialCoefficients: DenseVector[Double],
regParameters: RegistrationParameters): DenseVector[Double] = {
val transformationSpace = GaussianProcessTransformationSpace(lowRankGP)
val fixedImage = referenceMesh.operations.toDistanceImage
val movingImage = targetICP.operations.toDistanceImage
val sampler = FixedPointsUniformMeshSampler3D(referenceMesh, numberOfPoints = regParameters.numberOfSampledPoints)
val metric = MeanSquaresMetric(
fixedImage,
movingImage,
transformationSpace,
sampler)
val optimizer = LBFGSOptimizer(maxNumberOfIterations = regParameters.numberOfIterations)
val regularizer = L2Regularizer(transformationSpace)
val registration = Registration(
metric,
regularizer,
regularizationWeight = regParameters.regularizationWeight,
optimizer
)
val registrationIterator = registration.iterator(initialCoefficients)
val visualizingRegistrationIterator = for ((it, itnum) <- registrationIterator.zipWithIndex) yield {
//println(s"object value in iteration $itnum is ${it.value}")
gpView.coefficients = it.parameters
it
}
val registrationResult = visualizingRegistrationIterator.toSeq.last
registrationResult.parameters
}
val initialCoefficients = DenseVector.zeros[Double](lowRankGP.rank)
val allPoints = reference.pointSet.numberOfPoints
case class RegistrationParameters(regularizationWeight: Double, numberOfIterations: Int, numberOfSampledPoints: Int)
val registrationParameters = Seq(
RegistrationParameters(regularizationWeight = 1e-1, numberOfIterations = 50, numberOfSampledPoints = 1000),
RegistrationParameters(regularizationWeight = 1e-2, numberOfIterations = 50, numberOfSampledPoints = 2000),
RegistrationParameters(regularizationWeight = 1e-4, numberOfIterations = 100, numberOfSampledPoints = 4000),
RegistrationParameters(regularizationWeight = 1e-6, numberOfIterations = 100, numberOfSampledPoints = 10000)
)