Unstructured Deformations to Model Basipetal Growth

Import relevant Python modules.

import sys
sys.path.append("../../")
import math
import copy
import pickle

import torch

import matplotlib.pyplot as plt

import imodal

imodal.Utilities.set_compute_backend('torch')
torch.set_default_dtype(torch.float32)

We load the data

with open("../../data/basipetal.pickle", 'rb') as f:
    data = pickle.load(f)

shape_source = torch.tensor(data['shape_source']).type(torch.get_default_dtype())
shape_target = torch.tensor(data['shape_target']).type(torch.get_default_dtype())
dots_source = torch.tensor(data['dots_source'], dtype=torch.get_default_dtype())
dots_target = torch.tensor(data['dots_target'], dtype=torch.get_default_dtype())


aabb_source = imodal.Utilities.AABB.build_from_points(shape_source)
aabb_target = imodal.Utilities.AABB.build_from_points(shape_target)

Unstructured growth using the curve information

Intitialization

Plot source and target.

plt.title("Source and target")
plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), color='red')

plt.axis('equal')
plt.show()
Source and target

We now sample the points that will be used by the local translations module for unstructured growth.

# Build AABB (Axis Aligned Bounding Box) around the source shape and uniformly
# sample points for the growth module.


points_density = 0.05

points_translations = imodal.Utilities.fill_area_uniform_density(imodal.Utilities.area_shape, aabb_source.scale(1.3), points_density, shape=1.3*shape_source)

Plot points of the local translations module.

plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
plt.plot(points_translations[:, 0].numpy(), points_translations[:, 1].numpy(), 'o', color='blue')
plt.axis('equal')
plt.show()
plot leaf basipetal unstructured

Create the deformation model which only consists of one Translations deformation module.

Create and initialize local translations module.

sigma = 3./points_density**(1/2)
translations = imodal.DeformationModules.Translations(2, points_translations.shape[0], sigma, gd=points_translations)

Define deformables used by the registration model.

deformable_shape_source = imodal.Models.DeformablePoints(shape_source)
deformable_shape_target = imodal.Models.DeformablePoints(shape_target)

Registration

Define the registration model.

model = imodal.Models.RegistrationModel(
    [deformable_shape_source],
    [translations],
    [imodal.Attachment.VarifoldAttachment(2, [20., 120.])],
    lam=10.)

Fitting using Torch LBFGS optimizer.

shoot_solver = 'euler'
shoot_it = 10

costs = {}
fitter = imodal.Models.Fitter(model, optimizer='torch_lbfgs')
fitter.fit([deformable_shape_target], 2, costs=costs, options={'shoot_solver': shoot_solver, 'shoot_it': shoot_it, 'line_search_fn': 'strong_wolfe'})

Out:

Starting optimization with method torch LBFGS, using solver euler with 10 iterations.
Initial cost={'deformation': 0.0, 'attach': 182832.109375}
1e-10
Evaluated model with costs=182832.109375
Evaluated model with costs=179701.38137418032
Evaluated model with costs=167029.2038526535
Evaluated model with costs=156970.70640945435
Evaluated model with costs=129281.19460296631
Evaluated model with costs=304576.125
Evaluated model with costs=69574.68975830078
Evaluated model with costs=54175.95245361328
Evaluated model with costs=42579.201171875
Evaluated model with costs=12281.86767578125
Evaluated model with costs=5417.4791259765625
Evaluated model with costs=2907.400390625
Evaluated model with costs=2257.356201171875
Evaluated model with costs=1935.48583984375
Evaluated model with costs=830857.34375
Evaluated model with costs=1854.342041015625
Evaluated model with costs=1828.0673828125
Evaluated model with costs=1822.04052734375
Evaluated model with costs=1797.1142578125
Evaluated model with costs=521929.9423828125
Evaluated model with costs=1797.47412109375
Evaluated model with costs=1797.44189453125
Evaluated model with costs=1797.1142578125
================================================================================
Time: 2.789819064000767
Iteration: 0
Costs
deformation=1538.4228515625
attach=258.69140625
Total cost=1797.1142578125
1e-10
Evaluated model with costs=1797.1142578125
Evaluated model with costs=521929.9423828125
Evaluated model with costs=1797.47412109375
Evaluated model with costs=1797.44189453125
Evaluated model with costs=1797.1142578125
================================================================================
Time: 3.3891153300028236
Iteration: 1
Costs
deformation=1538.4228515625
attach=258.69140625
Total cost=1797.1142578125
================================================================================
Optimisation process exited with message: Convergence achieved.
Final cost=1797.1142578125
Model evaluation count=28
Time elapsed = 3.389471719001449

Results visualization

Compute optimized deformation trajectory.

intermediates = {}
with torch.autograd.no_grad():
    deformed = model.compute_deformed(shoot_solver, shoot_it, intermediates=intermediates)
    deformed_shape = deformed[0][0]

translations_controls = [control[1] for control in intermediates['controls']]

Plot results.

plt.subplot(1, 3, 1)
plt.title("Source")
plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), '-', color='black')
plt.axis(aabb_target.totuple())
plt.axis('equal')

plt.subplot(1, 3, 2)
plt.title("Deformed source")
plt.plot(deformed_shape[:, 0], deformed_shape[:, 1], '-', color='blue')
plt.axis(aabb_target.totuple())
plt.axis('equal')

plt.subplot(1, 3, 3)
plt.title("Deformed source and target")
plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), '-', color='red')
plt.plot(deformed_shape[:, 0], deformed_shape[:, 1], '-', color='blue')
plt.axis(aabb_target.totuple())
plt.axis('equal')

plt.tight_layout()
plt.show()
Source, Deformed source, Deformed source and target

Recompute the learned deformation trajectory this time with the grid deformation to visualize growth.

# Reset the local translations module with the learned initialization manifold.
translations.manifold.fill(model.init_manifold[1])

aabb_source.scale_(1.2)
# Define the deformation grid.
square_size = 1.
grid_resolution = [math.floor(aabb_source.width/square_size),
                   math.floor(aabb_source.height/square_size)]

deformable_source = imodal.Models.DeformablePoints(shape_source)
deformable_grid = imodal.Models.DeformableGrid(aabb_source, grid_resolution)
deformable_source.silent_module.manifold.fill_cotan(model.init_manifold[0].cotan)

controls = [[control[1]] for control in intermediates['controls']]

# Shoot.
intermediates = {}
with torch.autograd.no_grad():
    imodal.Models.deformables_compute_deformed([deformable_source, deformable_grid], [translations], shoot_solver, shoot_it, controls=controls, intermediates=intermediates)

Plot the growth trajectory.

indices = [0, 3, 7, 10]

plt.figure(figsize=[10.*len(indices), 10.])
for i, index in enumerate(indices):
    state = intermediates['states'][index]
    ax = plt.subplot(1, len(indices), i + 1)
    deformable_grid.silent_module.manifold.fill_gd(state[1].gd)
    grid_x, grid_y = deformable_grid.silent_module.togrid()
    imodal.Utilities.plot_grid(ax, grid_x, grid_y, color='xkcd:light blue', lw=0.4)

    plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
    plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), color='red')
    plt.plot(state[0].gd[:, 0].numpy(), state[0].gd[:, 1].numpy())

    plt.axis('equal')
    plt.axis('off')

plt.tight_layout()
plt.show()
plot leaf basipetal unstructured

Unstructured growth model using curve and dots informations

Initialization

Plot source and target.

plt.title("Source and target")
plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
plt.plot(dots_source[:, 0].numpy(), dots_source[:, 1].numpy(), '.', color='black')
plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), color='red')
plt.plot(dots_target[:, 0].numpy(), dots_target[:, 1].numpy(), '.', color='red')

plt.axis('equal')
plt.show()
Source and target

We now sample the points that will be used by the local translations module.

# Build AABB (Axis Aligned Bounding Box) around the source shape and uniformly
# sample points for the growth module.
points_density = 0.05

aabb_source = imodal.Utilities.AABB.build_from_points(shape_source)

points_translations = imodal.Utilities.fill_area_uniform_density(imodal.Utilities.area_shape, aabb_source.scale(1.3), points_density, shape=1.3*shape_source)

Plot geometrical descriptor of the local translations module.

plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
plt.plot(points_translations[:, 0].numpy(), points_translations[:, 1].numpy(), 'o', color='blue')
plt.axis('equal')
plt.show()
plot leaf basipetal unstructured

Create and initialize local translations module.

sigma = 3./points_density**(1/2)
translations = imodal.DeformationModules.Translations(2, points_translations.shape[0], sigma, gd=points_translations)

Define deformables used by the registration model.

deformable_shape_source = imodal.Models.DeformablePoints(shape_source)
deformable_shape_target = imodal.Models.DeformablePoints(shape_target)
deformable_dots_source = imodal.Models.DeformablePoints(dots_source)
deformable_dots_target = imodal.Models.DeformablePoints(dots_target)

Registration

Define the registration model.

model = imodal.Models.RegistrationModel(
    [deformable_shape_source, deformable_dots_source],
    [translations],
    [imodal.Attachment.VarifoldAttachment(2, [20, 120.]),
     imodal.Attachment.EuclideanPointwiseDistanceAttachment(10.)],
    lam=10.)

Fitting using Torch LBFGS optimizer.

shoot_solver = 'euler'
shoot_it = 10

costs = {}
fitter = imodal.Models.Fitter(model, optimizer='torch_lbfgs')
fitter.fit([deformable_shape_target, deformable_dots_target], 50, costs=costs, options={'shoot_solver': shoot_solver, 'shoot_it': shoot_it, 'line_search_fn': 'strong_wolfe'})

Out:

Starting optimization with method torch LBFGS, using solver euler with 10 iterations.
Initial cost={'deformation': 0.0, 'attach': 260650.3125}
1e-10
Evaluated model with costs=260650.3125
Evaluated model with costs=257162.85886867344
Evaluated model with costs=241777.5296883583
Evaluated model with costs=118299.703125
Evaluated model with costs=142469.24853515625
Evaluated model with costs=91831.74267578125
Evaluated model with costs=84515.73797607422
Evaluated model with costs=87440.89465332031
Evaluated model with costs=81865.4970703125
Evaluated model with costs=81149.18273925781
Evaluated model with costs=75754.69885253906
Evaluated model with costs=61147.25695800781
Evaluated model with costs=47160.357421875
Evaluated model with costs=108048.39453125
Evaluated model with costs=40211.732666015625
Evaluated model with costs=28642.213623046875
Evaluated model with costs=25995.533935546875
Evaluated model with costs=24178.60888671875
Evaluated model with costs=21795.709350585938
Evaluated model with costs=18810.078125
Evaluated model with costs=16886.185302734375
Evaluated model with costs=16451.287109375
Evaluated model with costs=100116.37170410156
Evaluated model with costs=16337.872802734375
Evaluated model with costs=15726.703247070312
================================================================================
Time: 3.6096217459999025
Iteration: 0
Costs
deformation=1507.1446533203125
attach=14219.55859375
Total cost=15726.703247070312
1e-10
Evaluated model with costs=15726.703247070312
Evaluated model with costs=15232.046752929688
Evaluated model with costs=14453.909423828125
Evaluated model with costs=15007.512451171875
Evaluated model with costs=14433.239013671875
Evaluated model with costs=14296.302734375
Evaluated model with costs=14281.444946289062
Evaluated model with costs=14170.8896484375
Evaluated model with costs=12959.585205078125
Evaluated model with costs=12739.507202148438
Evaluated model with costs=12687.0556640625
Evaluated model with costs=12601.591796875
Evaluated model with costs=12477.247436523438
Evaluated model with costs=12324.508056640625
Evaluated model with costs=12025.943481445312
Evaluated model with costs=11591.653442382812
Evaluated model with costs=11463.57958984375
Evaluated model with costs=11291.584106445312
Evaluated model with costs=11433.396118164062
Evaluated model with costs=11285.421020507812
Evaluated model with costs=11261.66943359375
Evaluated model with costs=11260.155029296875
Evaluated model with costs=11238.599609375
Evaluated model with costs=11233.166259765625
Evaluated model with costs=10909.42041015625
================================================================================
Time: 7.170835379998607
Iteration: 1
Costs
deformation=1630.66943359375
attach=9278.7509765625
Total cost=10909.42041015625
1e-10
Evaluated model with costs=10909.42041015625
Evaluated model with costs=10760.473754882812
Evaluated model with costs=10723.598266601562
Evaluated model with costs=10649.3251953125
Evaluated model with costs=10611.262451171875
Evaluated model with costs=10559.218627929688
Evaluated model with costs=11076.683227539062
Evaluated model with costs=10530.7607421875
Evaluated model with costs=10446.40185546875
Evaluated model with costs=10205.652587890625
Evaluated model with costs=9752.00146484375
Evaluated model with costs=9520.787109375
Evaluated model with costs=9389.342041015625
Evaluated model with costs=9147.64111328125
Evaluated model with costs=8922.420776367188
Evaluated model with costs=8884.953735351562
Evaluated model with costs=8860.11376953125
Evaluated model with costs=8814.686157226562
Evaluated model with costs=8762.84521484375
Evaluated model with costs=8676.981201171875
Evaluated model with costs=8413.5673828125
Evaluated model with costs=8206.728637695312
Evaluated model with costs=8068.78125
================================================================================
Time: 10.445969016000163
Iteration: 2
Costs
deformation=1695.3193359375
attach=6373.4619140625
Total cost=8068.78125
1e-10
Evaluated model with costs=8068.78125
Evaluated model with costs=7960.908447265625
Evaluated model with costs=7922.5640869140625
Evaluated model with costs=7868.310302734375
Evaluated model with costs=7791.7198486328125
Evaluated model with costs=7621.8438720703125
Evaluated model with costs=7420.255126953125
Evaluated model with costs=7181.497802734375
Evaluated model with costs=6991.524658203125
Evaluated model with costs=6891.751708984375
Evaluated model with costs=6825.6275634765625
Evaluated model with costs=6786.7158203125
Evaluated model with costs=6758.8505859375
Evaluated model with costs=6738.1510009765625
Evaluated model with costs=6707.679443359375
Evaluated model with costs=6673.4010009765625
Evaluated model with costs=6616.98046875
Evaluated model with costs=6558.87548828125
Evaluated model with costs=6503.7864990234375
Evaluated model with costs=6447.520263671875
Evaluated model with costs=6350.9755859375
================================================================================
Time: 13.474108162998164
Iteration: 3
Costs
deformation=1740.82861328125
attach=4610.14697265625
Total cost=6350.9755859375
1e-10
Evaluated model with costs=6350.9755859375
Evaluated model with costs=6286.5196533203125
Evaluated model with costs=6241.5653076171875
Evaluated model with costs=444768.513671875
Evaluated model with costs=6199.3372802734375
Evaluated model with costs=6186.8814697265625
Evaluated model with costs=6176.735107421875
Evaluated model with costs=6172.128173828125
Evaluated model with costs=6179.0970458984375
Evaluated model with costs=6170.550537109375
Evaluated model with costs=6180.369873046875
Evaluated model with costs=6169.0860595703125
Evaluated model with costs=6171.8260498046875
Evaluated model with costs=6168.0667724609375
Evaluated model with costs=6168.3201904296875
Evaluated model with costs=6168.435302734375
Evaluated model with costs=6170.990234375
Evaluated model with costs=6167.8515625
Evaluated model with costs=6288.00341796875
Evaluated model with costs=6169.5419921875
Evaluated model with costs=6169.677978515625
Evaluated model with costs=6167.8515625
Evaluated model with costs=6167.8515625
Evaluated model with costs=6167.8515625
================================================================================
Time: 16.951740858999983
Iteration: 4
Costs
deformation=1805.99365234375
attach=4361.85791015625
Total cost=6167.8515625
1e-10
Evaluated model with costs=6167.8515625
Evaluated model with costs=6288.00341796875
Evaluated model with costs=6169.5419921875
Evaluated model with costs=6169.677978515625
Evaluated model with costs=6167.8515625
Evaluated model with costs=6167.8515625
Evaluated model with costs=6167.8515625
================================================================================
Time: 17.94131602699781
Iteration: 5
Costs
deformation=1805.99365234375
attach=4361.85791015625
Total cost=6167.8515625
================================================================================
Optimisation process exited with message: Convergence achieved.
Final cost=6167.8515625
Model evaluation count=125
Time elapsed = 17.941671292999672

Result visualization

Compute optimized deformation trajectory.

Plot results.

plt.subplot(1, 3, 1)
plt.title("Source")
plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), '-', color='black')
plt.plot(dots_source[:, 0].numpy(), dots_source[:, 1].numpy(), '.', color='black')
plt.axis('equal')

plt.subplot(1, 3, 2)
plt.title("Deformed source")
plt.plot(deformed_shape[:, 0], deformed_shape[:, 1], '-', color='blue')
plt.plot(deformed_dots[:, 0], deformed_dots[:, 1], '.', color='blue')
plt.axis('equal')

plt.subplot(1, 3, 3)
plt.title("Deformed source and target")
plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), '-', color='red')
plt.plot(dots_target[:, 0].numpy(), dots_target[:, 1].numpy(), '.', color='red')
plt.plot(deformed_shape[:, 0], deformed_shape[:, 1], '-', color='blue')
plt.plot(deformed_dots[:, 0], deformed_dots[:, 1], '.', color='blue')
plt.axis('equal')

plt.tight_layout()
plt.show()
Source, Deformed source, Deformed source and target

Recompute the learned deformation trajectory this time with the grid deformation to visualize growth.

# Reset the local translations module with the learned initialization manifold.
translations.manifold.fill(model.init_manifold[2])

aabb_source.scale_(1.2)
# Define the deformation grid.
square_size = 1.
grid_resolution = [math.floor(aabb_source.width/square_size),
                   math.floor(aabb_source.height/square_size)]

deformable_source = imodal.Models.DeformablePoints(shape_source)
deformable_dots_source = imodal.Models.DeformablePoints(dots_source)
deformable_grid = imodal.Models.DeformableGrid(aabb_source, grid_resolution)

deformable_source.silent_module.manifold.fill_cotan(model.init_manifold[0].cotan)
deformable_dots_source.silent_module.manifold.fill_cotan(model.init_manifold[1].cotan)

controls = [[control[2]] for control in intermediates['controls']]

# Shoot.
intermediates = {}
with torch.autograd.no_grad():
    imodal.Models.deformables_compute_deformed([deformable_source, deformable_dots_source, deformable_grid], [translations], shoot_solver, shoot_it, controls=controls, intermediates=intermediates)

Plot the growth trajectory.

indices = [0, 3, 7, 10]

plt.figure(figsize=[10.*len(indices), 10.])
for i, index in enumerate(indices):
    state = intermediates['states'][index]
    ax = plt.subplot(1, len(indices), i + 1)

    deformable_grid.silent_module.manifold.fill_gd(state[2].gd)
    grid_x, grid_y = deformable_grid.silent_module.togrid()
    imodal.Utilities.plot_grid(ax, grid_x, grid_y, color='xkcd:light blue', lw=0.4)

    plt.plot(shape_source[:, 0].numpy(), shape_source[:, 1].numpy(), color='black')
    plt.plot(shape_target[:, 0].numpy(), shape_target[:, 1].numpy(), color='red')
    plt.plot(state[0].gd[:, 0].numpy(), state[0].gd[:, 1].numpy(), color='blue')
    plt.plot(state[1].gd[:, 0].numpy(), state[1].gd[:, 1].numpy(), '.', color='blue')

    plt.axis('equal')
    plt.axis('off')

plt.tight_layout()
plt.show()
plot leaf basipetal unstructured

Total running time of the script: ( 0 minutes 23.560 seconds)

Gallery generated by Sphinx-Gallery