Repository: KitwareMedical/HASI (language: python)

Issue:
ENH: Add mesh registration via point sets
Adds Python classes for mesh-to-mesh registration via point set entropy metrics. Includes pytest and examples coverage of new functionality.

Depends on #39 .


Discussion / hints:
Also please rebase on current master. I just merged the other PR.
Rebase complete.

> See [ITK's data documentation](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Documentation/Data.md) for alternative approach.

Would there be any issues with using content links to the publicly accessible [Girder directory](https://data.kitware.com/#collection/5dcc6691e3566bda4b802172/folder/5f9daa3750a41e3d1924d870) of MicroCT meshes?

Fix patch:
diff --git a/examples/MeshToMeshRegistration.ipynb b/examples/MeshToMeshRegistration.ipynb
index c98649d..134db9a 100644
--- a/examples/MeshToMeshRegistration.ipynb
+++ b/examples/MeshToMeshRegistration.ipynb
@@ -8,7 +8,7 @@
     "\n",
     "ITK natively supports image-to-image registration, which is a common operation for medical images with symmetry. Another common method of storing 3D volumetric data is to represent volume surfaces with meshes. In this example we seek to register two meshes using various metrics and optimization techniques built on top of ITK.\n",
     "\n",
-    "Registration classes are defined in the HASI `registration` submodule and built on top of the ITK Python wrapping. The `MeanSquaresRegistrar` and `DiffeoRegistrar` classes apply registration techniques to images derived from mesh inputs. Mesh registration is carried out with each class in this notebook on sample bone femur mesh data in the `examples/Data` folder. "
+    "Registration classes are defined in the Python `hasi` submodule and built on top of the ITK Python wrapping. The `MeanSquaresRegistrar` and `DiffeoRegistrar` classes apply registration techniques to images derived from mesh inputs, while the `PointSetEntropyRegistrar` aims to register meshes via point set metrics. Mesh registration is carried out with each class in this notebook on sample bone femur mesh data in the `examples/Data` folder."
    ]
   },
   {
@@ -23,7 +23,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -37,7 +37,7 @@
     "import itk\n",
     "from itkwidgets import view, checkerboard, compare\n",
     "from ipywidgets import FloatProgress, Label, HBox, VBox, FloatText, ColorPicker, Button\n",
-    "PATTERN_COUNT = 10\n",
+    "PATTERN_COUNT = 5\n",
     "\n",
     "module_path = os.path.abspath(os.path.join('..'))\n",
     "\n",
@@ -47,49 +47,66 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
-    "os.makedirs('Data', exist_ok=True)"
+    "os.makedirs('Input', exist_ok=True)\n",
+    "os.makedirs('Output', exist_ok=True)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [],
    "source": [
-    "FIXED_MESH_FILE = 'Data/901-L-mesh.vtk'\n",
-    "MOVING_MESH_FILE = 'Data/901-R-mesh.vtk'\n",
+    "meshes = ['901','902','906','907','908','915','916','917','918']\n",
+    "MESH_TO_USE = meshes[0]\n",
+    "\n",
+    "TARGET_MESH_FILE = f'Input/{MESH_TO_USE}-R-mesh.vtk'\n",
+    "# Future update will replace with smaller template\n",
+    "TEMPLATE_MESH_FILE = f'Input/template-901-L.obj'\n",
     "\n",
-    "MEANSQUARES_OUTPUT_FILE = 'Data/901-meansquares-registered.vtk'\n",
-    "DIFFEO_OUTPUT_FILE = 'Data/901-diffeo-registered.vtk'"
+    "MEANSQUARES_OUTPUT_FILE = f'Output/{MESH_TO_USE}-meansquares-registered.obj'\n",
+    "DIFFEO_OUTPUT_FILE = f'Output/{MESH_TO_USE}-diffeo-registered.obj'\n",
+    "POINTSET_OUTPUT_FILE = f'Output/{MESH_TO_USE}-pointset-registered.obj'"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
     "# Download meshes\n",
-    "if not os.path.exists(FIXED_MESH_FILE):\n",
-    "    url = 'https://data.kitware.com/api/v1/file/5f9daaae50a41e3d1924dae1/download'\n",
-    "    urlretrieve(url, FIXED_MESH_FILE)\n",
-    "if not os.path.exists(MOVING_MESH_FILE):\n",
+    "if not os.path.exists(TARGET_MESH_FILE):\n",
     "    url = 'https://data.kitware.com/api/v1/file/5f9daaba50a41e3d1924dae9/download'\n",
-    "    urlretrieve(url, MOVING_MESH_FILE)"
+    "    urlretrieve(url, TARGET_MESH_FILE)\n",
+    "if not os.path.exists(TEMPLATE_MESH_FILE):\n",
+    "    url = 'https://data.kitware.com/api/v1/file/60762a4b2fa25629b9bbefef/download'\n",
+    "    urlretrieve(url, TEMPLATE_MESH_FILE)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "template_mesh = itk.meshread(TEMPLATE_MESH_FILE, itk.F)\n",
+    "target_mesh = itk.meshread(TARGET_MESH_FILE, itk.F)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
-    "fixed_mesh = itk.meshread(FIXED_MESH_FILE, itk.F)\n",
-    "moving_mesh = itk.meshread(MOVING_MESH_FILE, itk.F)"
+    "itk.meshwrite(target_mesh,'Input/901-R-mesh.obj')"
    ]
   },
   {
@@ -103,43 +120,28 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "28896761f6a94485b95131a6c102765a",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'numberOfComponents': 3, 'd…"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [],
    "source": [
-    "view(geometries=[fixed_mesh,moving_mesh])"
+    "#view(geometries=[template_mesh,target_mesh])"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Mesh-To-Image Conversion in the Base Class\n",
-    "Mesh registration classes inheriting from `MeshToMeshRegistrar` implement unique registration algorithms. The base class includes common definitions for 3D mesh-to-mesh registration, abstract methods, and a mesh-to-image conversion method.\n",
+    "## Mesh-To-Image Conversion in the Base Class\n",
+    "Python registration classes inheriting from `MeshToMeshRegistrar` implement unique registration algorithms. The base class includes common definitions for 3D mesh-to-mesh registration, abstract methods, and a mesh-to-image conversion method.\n",
+    "\n",
+    "The `mesh_to_image` function takes in a 3D mesh and converts it into an ITK 3D image object. The spacing, origin, and size of the 3D image may be calculated from the minimum bounding box of the mesh or set from a reference image.\n",
     "\n",
-    "The `mesh_to_image` function takes in a 3D mesh and converts it into an ITK 3D image object. The spacing, origin, and size of the 3D image may be calculated from the minimum bounding box of the mesh or set from a reference image."
+    "In this case the target mesh occupies a slightly larger region than the template mesh so we create the target image first and then create the template image with the same image size, origin, and spacing."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 7,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -149,30 +151,64 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "target_image = registrar.mesh_to_image(target_mesh)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
    "metadata": {},
    "outputs": [],
    "source": [
-    "fixed_img = registrar.mesh_to_image(fixed_mesh)\n",
-    "moving_img = registrar.mesh_to_image(moving_mesh, fixed_img)"
+    "template_image = registrar.mesh_to_image(template_mesh, target_image)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Comparing the meshes generated from the given meshes, we see that the two bone images are generally similar but do not exactly align. Registration will translate one mesh so that the two bones better coincide."
+    "Comparing the meshes generated from the given meshes, we see that the two bone images are generally similar but do not exactly line up together. Registration will translate one mesh so that the two bones better coincide."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "615313a2a584448fb0d8ddec1713256e",
+       "model_id": "0612bf8c5c4a408eab4e569f462e95c9",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "compare(template_image,target_image)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "fd9e4b980c5248f19d292fbf5f4fb60a",
        "version_major": 2,
        "version_minor": 0
       },
@@ -185,7 +221,37 @@
     }
    ],
    "source": [
-    "checkerboard(fixed_img, moving_img, pattern=PATTERN_COUNT)"
+    "checkerboard(template_image, target_image, pattern=PATTERN_COUNT)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Point set downsizing in the Base Class\n",
+    "\n",
+    "The base `MeshToMeshRegistrar` class also provides functionality for uniform random point set sampling from a given mesh, primarily used to improve performance for point set based registration of dense meshes. Note that uniform random sampling may not be suitable for all shapes, in which case application-specific resampling should be carried out externally prior to registration."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "target_points_reduced = \\\n",
+    "    registrar.randomly_sample_mesh_points(mesh=target_mesh, sampling_rate=0.01)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "#view(geometries=[target_mesh],point_sets=[target_points_reduced])"
    ]
   },
   {
@@ -194,14 +260,14 @@
    "source": [
     "## Run Mean Squares Image Registration\n",
     "\n",
-    "The `MeanSquaresRegistrar` class converts meshes to images and runs [Broyden–Fletcher–Goldfarb–Shanno Optimization](https://itk.org/Doxygen/html/classitk_1_1LBFGSBOptimizerv4.html) on a `BSplineTransform` to iteratively reduce the mean square error. The resulting transform is then applied to resample the target mesh into the template mesh domain.\n",
+    "The `MeanSquaresRegistrar` class converts meshes to images and runs [Broyden-Fletcher-Goldfarb-Shanno Optimization](https://itk.org/Doxygen/html/classitk_1_1LBFGSBOptimizerv4.html) on a [BSplineTransform](https://itk.org/Doxygen/html/classitk_1_1BSplineTransform.html) to iteratively reduce the mean square error. The resulting transform is then applied to resample the target mesh into the template mesh domain.\n",
     "\n",
     "Progress is shown with an itkwidgets display via hooks into the ITK event-observer system. The resultant mesh is returned as an object in the Python environment and may be optionally written out to a file. Iteration updates may also be printed to the output window with the optional `verbose` flag."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -210,7 +276,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -220,7 +286,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 20,
    "metadata": {
     "scrolled": true
    },
@@ -228,7 +294,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "e10ad99a2bec41bf8b19052f51398255",
+       "model_id": "b77252f35e4543eab60bffe42e99c492",
        "version_major": 2,
        "version_minor": 0
       },
@@ -255,7 +321,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
@@ -264,7 +330,7 @@
        "0"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 21,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -277,7 +343,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 22,
    "metadata": {
     "scrolled": true
    },
@@ -286,374 +352,333 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "0 0.03902562455535499 0.0\n",
-      "0 0.02843709659649114 0.0\n",
-      "0 0.02843709659649114 0.0\n",
-      "1 0.021534717551505798 0.0009582783977029718\n",
-      "1 0.021534717551505798 0.0009582783977029718\n",
-      "2 0.01790224911093285 0.00043193967453070587\n",
-      "2 0.01790224911093285 0.00043193967453070587\n",
-      "3 0.01568735406387658 0.00024653588676924737\n",
-      "3 0.01568735406387658 0.00024653588676924737\n",
-      "4 0.012572812905498177 0.0001938980902412675\n",
-      "4 0.012572812905498177 0.0001938980902412675\n",
-      "5 0.010982249945285367 0.00015319597818792382\n",
-      "5 0.010982249945285367 0.00015319597818792382\n",
-      "6 0.010363658471730493 0.0001203197280705292\n",
-      "6 0.010363658471730493 0.0001203197280705292\n",
-      "7 0.00917110184613044 0.00012346212100002512\n",
-      "7 0.00917110184613044 0.00012346212100002512\n",
-      "8 0.008587382362441122 0.00010581326627687776\n",
-      "8 0.008587382362441122 0.00010581326627687776\n",
-      "9 0.007903788433334932 0.00023582429403319085\n",
-      "9 0.007903788433334932 0.00023582429403319085\n",
-      "10 0.007710042007798568 7.71329623659586e-05\n",
-      "10 0.007710042007798568 7.71329623659586e-05\n",
-      "11 0.007482638458656705 4.18199997737327e-05\n",
-      "11 0.007482638458656705 4.18199997737327e-05\n",
-      "12 0.007261037845424188 4.0518726529937375e-05\n",
-      "12 0.007261037845424188 4.0518726529937375e-05\n",
-      "13 0.0069838930620213305 0.00010325512656737245\n",
-      "13 0.0069838930620213305 0.00010325512656737245\n",
-      "14 0.006775251306971731 7.584635194441443e-05\n",
-      "14 0.006775251306971731 7.584635194441443e-05\n",
-      "15 0.006355717666034258 5.642267287740276e-05\n",
-      "15 0.006355717666034258 5.642267287740276e-05\n",
-      "16 0.00605591520403088 4.4467828658758887e-05\n",
-      "16 0.00605591520403088 4.4467828658758887e-05\n",
-      "17 0.005546450809680826 3.832565498285056e-05\n",
-      "17 0.005546450809680826 3.832565498285056e-05\n",
-      "18 0.006020691821988377 7.224933937291222e-05\n",
-      "18 0.0055103815315709756 7.224933937291222e-05\n",
-      "18 0.005510042630306807 7.224933937291222e-05\n",
-      "18 0.005359306087959403 7.224933937291222e-05\n",
-      "18 0.005359306087959403 7.224933937291222e-05\n",
-      "19 0.005091258598095609 0.00010635345122411626\n",
-      "19 0.005091258598095609 0.00010635345122411626\n",
-      "20 0.004942380095530081 3.906880820044698e-05\n",
-      "20 0.004942380095530081 3.906880820044698e-05\n",
-      "21 0.004772486002234065 6.209735577514633e-05\n",
-      "21 0.004772486002234065 6.209735577514633e-05\n",
-      "22 0.005073728140916828 6.96641364787321e-05\n",
-      "22 0.004754424549211469 6.96641364787321e-05\n",
-      "22 0.004754253317430925 6.96641364787321e-05\n",
-      "22 0.004683312841520785 6.96641364787321e-05\n",
-      "22 0.004683312841520785 6.96641364787321e-05\n",
-      "23 0.0044377783076356 0.00015876436412595073\n",
-      "23 0.0044377783076356 0.00015876436412595073\n",
-      "24 0.004346719199258853 3.922685876182858e-05\n",
-      "24 0.004346719199258853 3.922685876182858e-05\n",
-      "25 0.004245378783895223 3.218043515895407e-05\n",
-      "25 0.004245378783895223 3.218043515895407e-05\n",
-      "26 0.004043692960664408 2.9715624871160453e-05\n",
-      "26 0.004043692960664408 2.9715624871160453e-05\n",
-      "27 0.004116597816232508 3.2846854107938547e-05\n",
-      "27 0.0040229456953386296 3.2846854107938547e-05\n",
-      "27 0.0040229456953386296 3.2846854107938547e-05\n",
-      "28 0.0038701512473396484 3.15627783694908e-05\n",
-      "28 0.0038701512473396484 3.15627783694908e-05\n",
-      "29 0.0038313307486668394 1.808431931883811e-05\n",
-      "29 0.0038313307486668394 1.808431931883811e-05\n",
-      "30 0.0037465535617471333 1.8267591090029966e-05\n",
-      "30 0.0037465535617471333 1.8267591090029966e-05\n",
-      "31 0.003758170749469634 2.343205039930289e-05\n",
-      "31 0.0037273752303717167 2.343205039930289e-05\n",
-      "31 0.0037273752303717167 2.343205039930289e-05\n",
-      "32 0.00363999816669316 2.8180534674389877e-05\n",
-      "32 0.00363999816669316 2.8180534674389877e-05\n",
-      "33 0.0035557200277517333 3.842058274608217e-05\n",
-      "33 0.0035557200277517333 3.842058274608217e-05\n",
-      "34 0.003493559518933686 6.148418237432861e-05\n",
-      "34 0.003493559518933686 6.148418237432861e-05\n",
-      "35 0.0034061605422970576 2.2149645180712496e-05\n",
-      "35 0.0034061605422970576 2.2149645180712496e-05\n",
-      "36 0.0032820873989475737 1.9279884083262686e-05\n",
-      "36 0.0032820873989475737 1.9279884083262686e-05\n",
-      "37 0.0031888716935002705 3.987843487735065e-05\n",
-      "37 0.0031888716935002705 3.987843487735065e-05\n",
-      "38 0.0030630301286621382 8.212527733154436e-05\n",
-      "38 0.0030630301286621382 8.212527733154436e-05\n",
-      "39 0.0030401866066476365 4.199840031001318e-05\n",
-      "39 0.0030401866066476365 4.199840031001318e-05\n",
-      "40 0.0030249310714235344 1.7332281811427526e-05\n",
-      "40 0.0030249310714235344 1.7332281811427526e-05\n",
-      "41 0.0030089595781744444 1.3328746122580835e-05\n",
-      "41 0.0030089595781744444 1.3328746122580835e-05\n",
-      "42 0.002973013833204376 2.2975476146425022e-05\n",
-      "42 0.002973013833204376 2.2975476146425022e-05\n",
-      "43 0.0029111852719252347 3.100588320946631e-05\n",
-      "43 0.0029111852719252347 3.100588320946631e-05\n",
-      "44 0.002860401643157572 5.012292487314528e-05\n",
-      "44 0.002860401643157572 5.012292487314528e-05\n",
-      "45 0.0028371264786411976 2.0380894403904924e-05\n",
-      "45 0.0028371264786411976 2.0380894403904924e-05\n",
-      "46 0.0028085067233335485 1.83091467147082e-05\n",
-      "46 0.0028085067233335485 1.83091467147082e-05\n",
-      "47 0.00277147502415173 1.5946395185479406e-05\n",
-      "47 0.00277147502415173 1.5946395185479406e-05\n",
-      "48 0.002739581460333074 3.298229749934517e-05\n",
-      "48 0.002739581460333074 3.298229749934517e-05\n",
-      "49 0.0027100685733047005 2.4501879032113878e-05\n",
-      "49 0.0027100685733047005 2.4501879032113878e-05\n",
-      "50 0.0026916985931069682 1.3166048601013102e-05\n",
-      "50 0.0026916985931069682 1.3166048601013102e-05\n",
-      "51 0.002676920485963997 1.3486107901034476e-05\n",
-      "51 0.002676920485963997 1.3486107901034476e-05\n",
-      "52 0.002674836904654953 1.3403952825531695e-05\n",
-      "52 0.002666607132351189 1.3403952825531695e-05\n",
-      "52 0.002666607132351189 1.3403952825531695e-05\n",
-      "53 0.0026583993248833495 1.870107386824799e-05\n",
-      "53 0.0026583993248833495 1.870107386824799e-05\n",
-      "54 0.00264810694812382 1.0840588643959346e-05\n",
-      "54 0.00264810694812382 1.0840588643959346e-05\n",
-      "55 0.0026250857121154205 1.177356109809702e-05\n",
-      "55 0.0026250857121154205 1.177356109809702e-05\n",
-      "56 0.0025911801875077418 2.0327162745975005e-05\n",
-      "56 0.0025911801875077418 2.0327162745975005e-05\n",
-      "57 0.0027079458232019188 1.919115020820825e-05\n",
-      "57 0.0025901895164457977 1.919115020820825e-05\n",
-      "57 0.002590180586424058 1.919115020820825e-05\n",
-      "57 0.002594759313265061 1.919115020820825e-05\n",
-      "57 0.0025854752605495306 1.919115020820825e-05\n",
-      "57 0.0025854752605495306 1.919115020820825e-05\n",
-      "58 0.002552327393469563 2.137138094677914e-05\n",
-      "58 0.002552327393469563 2.137138094677914e-05\n",
-      "59 0.002524197573786071 1.535683814510517e-05\n",
-      "59 0.002524197573786071 1.535683814510517e-05\n",
-      "60 0.002494475717634838 1.3472671239414138e-05\n",
-      "60 0.002494475717634838 1.3472671239414138e-05\n",
-      "61 0.002551462155966145 1.6962010469438536e-05\n",
-      "61 0.0024932134588946725 1.6962010469438536e-05\n",
-      "61 0.0024932040248302183 1.6962010469438536e-05\n",
-      "61 0.00248835145915565 1.6962010469438536e-05\n",
-      "61 0.002482543144498161 1.6962010469438536e-05\n",
-      "61 0.002482543144498161 1.6962010469438536e-05\n",
-      "62 0.002474839940059309 1.4920989491775313e-05\n",
-      "62 0.002474839940059309 1.4920989491775313e-05\n",
-      "63 0.0024547341967899507 1.243933258417565e-05\n",
-      "63 0.0024547341967899507 1.243933258417565e-05\n",
-      "64 0.0024340608416923023 9.59609396263446e-06\n",
-      "64 0.0024340608416923023 9.59609396263446e-06\n",
-      "65 0.0023953898293690126 1.2096061729030633e-05\n",
-      "65 0.0023953898293690126 1.2096061729030633e-05\n",
-      "66 0.002519469857290448 1.7000664300794257e-05\n",
-      "66 0.002394196784712445 1.7000664300794257e-05\n",
-      "66 0.0023941855869142694 1.7000664300794257e-05\n",
-      "66 0.0023992244032024525 1.7000664300794257e-05\n",
-      "66 0.0023893467207391846 1.7000664300794257e-05\n",
-      "66 0.0023893467207391846 1.7000664300794257e-05\n",
-      "67 0.0023581226849768155 1.7608336078114826e-05\n",
-      "67 0.0023581226849768155 1.7608336078114826e-05\n",
-      "68 0.0023388262973852336 1.3930111248998687e-05\n",
-      "68 0.0023388262973852336 1.3930111248998687e-05\n",
-      "69 0.0023529530595837577 1.131353366019851e-05\n",
-      "69 0.002338314165920189 1.131353366019851e-05\n",
-      "69 0.0023383032237725794 1.131353366019851e-05\n",
-      "69 0.002336612205619547 1.131353366019851e-05\n",
-      "69 0.002336612205619547 1.131353366019851e-05\n",
-      "70 0.0023279292661326934 2.5910579274460008e-05\n",
-      "70 0.0023279292661326934 2.5910579274460008e-05\n",
-      "71 0.0023197612728630976 1.0915666639408057e-05\n",
-      "71 0.0023197612728630976 1.0915666639408057e-05\n",
-      "72 0.0023125019380547994 9.835062761827748e-06\n",
-      "72 0.0023125019380547994 9.835062761827748e-06\n",
-      "73 0.0022991581963031724 1.7375352194814344e-05\n",
-      "73 0.0022991581963031724 1.7375352194814344e-05\n",
-      "74 0.002321345264600723 1.807701734048209e-05\n",
-      "74 0.0022985031405156086 1.807701734048209e-05\n",
-      "74 0.0022984976243167143 1.807701734048209e-05\n",
-      "74 0.0022959660329646206 1.807701734048209e-05\n",
-      "74 0.0022959660329646206 1.807701734048209e-05\n",
-      "75 0.0022800230133267875 2.3305198719106537e-05\n",
-      "75 0.0022800230133267875 2.3305198719106537e-05\n",
-      "76 0.0022732525238883636 1.0757626337439042e-05\n",
-      "76 0.0022732525238883636 1.0757626337439042e-05\n",
-      "77 0.002265468229387971 7.135154455189065e-06\n",
-      "77 0.002265468229387971 7.135154455189065e-06\n",
-      "78 0.0022547339352808637 1.603059631430486e-05\n",
-      "78 0.0022547339352808637 1.603059631430486e-05\n",
-      "79 0.0024544079486279353 1.8103223542683583e-05\n",
-      "79 0.0022544271109302366 1.8103223542683583e-05\n",
-      "79 0.002254424011252207 1.8103223542683583e-05\n",
-      "79 0.002287497353621487 1.8103223542683583e-05\n",
-      "79 0.002254126990637648 1.8103223542683583e-05\n",
-      "79 0.0022541208913516198 1.8103223542683583e-05\n",
-      "79 0.0022545767819664394 1.8103223542683583e-05\n",
-      "79 0.0022510691524390736 1.8103223542683583e-05\n",
-      "79 0.0022510691524390736 1.8103223542683583e-05\n",
-      "80 0.002230527943907003 2.810385872915433e-05\n",
-      "80 0.002230527943907003 2.810385872915433e-05\n",
-      "81 0.0021976259865897083 2.2247079517571763e-05\n",
-      "81 0.0021976259865897083 2.2247079517571763e-05\n",
-      "82 0.0021744382531630373 1.1687534612439894e-05\n",
-      "82 0.0021744382531630373 1.1687534612439894e-05\n",
-      "83 0.0021581964410112096 6.686895895295929e-06\n",
-      "83 0.0021581964410112096 6.686895895295929e-06\n",
-      "84 0.0021543229988330195 1.3279081700020026e-05\n",
-      "84 0.0021543229988330195 1.3279081700020026e-05\n",
-      "85 0.0021373552267960018 2.750042931646833e-05\n",
-      "85 0.0021373552267960018 2.750042931646833e-05\n",
-      "86 0.0021244748310922613 1.4589883928863175e-05\n",
-      "86 0.0021244748310922613 1.4589883928863175e-05\n",
-      "87 0.002110044257923805 9.68040711477424e-06\n",
-      "87 0.002110044257923805 9.68040711477424e-06\n",
-      "88 0.002184134928329491 1.3825248712848794e-05\n",
-      "88 0.0021097600451277787 1.3825248712848794e-05\n",
-      "88 0.0021097576655066735 1.3825248712848794e-05\n",
-      "88 0.002118930873315078 1.3825248712848794e-05\n",
-      "88 0.0021092958793023564 1.3825248712848794e-05\n",
-      "88 0.0021092958793023564 1.3825248712848794e-05\n",
-      "89 0.0021003082477032914 1.2875634001890585e-05\n",
-      "89 0.0021003082477032914 1.2875634001890585e-05\n",
-      "90 0.0020941712715128523 1.547334965033804e-05\n",
-      "90 0.0020941712715128523 1.547334965033804e-05\n",
-      "91 0.0020784875187255217 1.558028545512928e-05\n",
-      "91 0.0020784875187255217 1.558028545512928e-05\n",
-      "92 0.0020595501310483417 7.822934770409636e-06\n",
-      "92 0.0020595501310483417 7.822934770409636e-06\n",
-      "93 0.0020503050243808434 1.5823913160640335e-05\n",
-      "93 0.0020503050243808434 1.5823913160640335e-05\n",
-      "94 0.002039702068476176 1.8062570661327828e-05\n",
-      "94 0.002039702068476176 1.8062570661327828e-05\n",
-      "95 0.002034078004249004 8.76673028115691e-06\n",
-      "95 0.002034078004249004 8.76673028115691e-06\n",
-      "96 0.0020299461789864397 8.702207955318158e-06\n",
-      "96 0.0020299461789864397 8.702207955318158e-06\n",
-      "97 0.0020267325840052945 6.075248743332279e-06\n",
-      "97 0.0020267325840052945 6.075248743332279e-06\n",
-      "98 0.002022251768585389 1.3847887646787197e-05\n",
-      "98 0.002022251768585389 1.3847887646787197e-05\n",
-      "99 0.0020205468452258314 8.425171308272492e-06\n",
-      "99 0.0020205468452258314 8.425171308272492e-06\n",
-      "100 0.002010895422609264 6.43118883142622e-06\n",
-      "100 0.002010895422609264 6.43118883142622e-06\n",
-      "101 0.0020045332008143952 7.240055405719292e-06\n",
-      "101 0.0020045332008143952 7.240055405719292e-06\n",
-      "102 0.0019999391640292672 7.103693857572517e-06\n",
-      "102 0.0019999391640292672 7.103693857572517e-06\n",
-      "103 0.0019955147196199542 6.992593579285208e-06\n",
-      "103 0.0019955147196199542 6.992593579285208e-06\n",
-      "104 0.001983867035144281 7.387944056119959e-06\n",
-      "104 0.001983867035144281 7.387944056119959e-06\n",
-      "105 0.001981224219217234 9.467601925367484e-06\n",
-      "105 0.001981224219217234 9.467601925367484e-06\n",
-      "106 0.0019753462237094323 1.3244939594795944e-05\n",
-      "106 0.0019753462237094323 1.3244939594795944e-05\n",
-      "107 0.001972277219068784 1.555239417597789e-05\n",
-      "107 0.001972277219068784 1.555239417597789e-05\n",
-      "108 0.0019702515965765023 5.8645580720034086e-06\n",
-      "108 0.0019702515965765023 5.8645580720034086e-06\n",
-      "109 0.0019567183361210907 4.807814321735326e-06\n",
-      "109 0.0019567183361210907 4.807814321735326e-06\n",
-      "110 0.0020168918105899097 4.860064700114653e-06\n",
-      "110 0.001956472569382396 4.860064700114653e-06\n",
-      "110 0.001956467954326453 4.860064700114653e-06\n",
-      "110 0.001961488462500127 4.860064700114653e-06\n",
-      "110 0.0019555548127838064 4.860064700114653e-06\n",
-      "110 0.0019555548127838064 4.860064700114653e-06\n",
-      "111 0.0019404478808388173 4.782446853180894e-06\n",
-      "111 0.0019404478808388173 4.782446853180894e-06\n",
-      "112 0.0019306501042011706 9.33022212847401e-06\n",
-      "112 0.0019306501042011706 9.33022212847401e-06\n",
-      "113 0.0019230117986230354 7.484430373170417e-06\n",
-      "113 0.0019230117986230354 7.484430373170417e-06\n",
-      "114 0.0019173097246110255 6.257832655028487e-06\n",
-      "114 0.0019173097246110255 6.257832655028487e-06\n",
-      "115 0.0019145094122031412 7.503925508633168e-06\n",
-      "115 0.0019145094122031412 7.503925508633168e-06\n",
-      "116 0.0019096780343795037 1.2773918274613476e-05\n",
-      "116 0.0019096780343795037 1.2773918274613476e-05\n",
-      "117 0.0019048472957784235 7.408598547299024e-06\n",
-      "117 0.0019048472957784235 7.408598547299024e-06\n",
-      "118 0.001899930340368125 9.20598492953695e-06\n",
-      "118 0.001899930340368125 9.20598492953695e-06\n",
-      "119 0.0018988236200967767 8.406479294815173e-06\n",
-      "119 0.0018988236200967767 8.406479294815173e-06\n",
-      "120 0.0018972664638394338 1.1083617968791284e-05\n",
-      "120 0.0018972664638394338 1.1083617968791284e-05\n",
-      "121 0.0018962166639435688 4.245199140073017e-06\n",
-      "121 0.0018962166639435688 4.245199140073017e-06\n",
-      "122 0.0018933424995486274 3.4004210312599835e-06\n",
-      "122 0.0018933424995486274 3.4004210312599835e-06\n",
-      "123 0.0018891191420629865 8.687897867220789e-06\n",
-      "123 0.0018891191420629865 8.687897867220789e-06\n",
-      "124 0.0018820928084651973 1.2272115459887223e-05\n",
-      "124 0.0018820928084651973 1.2272115459887223e-05\n",
-      "125 0.0018955151880697327 1.7738558855247366e-05\n",
-      "125 0.0018817173058631967 1.7738558855247366e-05\n",
-      "125 0.0018817143413631815 1.7738558855247366e-05\n",
-      "125 0.001879545600235979 1.7738558855247366e-05\n",
-      "125 0.001879545600235979 1.7738558855247366e-05\n",
-      "126 0.0018735506232271221 2.0004120885681104e-05\n",
-      "126 0.0018735506232271221 2.0004120885681104e-05\n",
-      "127 0.0018718782355501733 5.8215538191835145e-06\n",
-      "127 0.0018718782355501733 5.8215538191835145e-06\n",
-      "128 0.0018702973250177472 4.929291181167768e-06\n",
-      "128 0.0018702973250177472 4.929291181167768e-06\n",
-      "129 0.0018679682057376416 4.396303867365583e-06\n",
-      "129 0.0018679682057376416 4.396303867365583e-06\n",
-      "130 0.0018655448140049242 4.3220408402449e-06\n",
-      "130 0.0018655448140049242 4.3220408402449e-06\n",
-      "131 0.0018634139997990387 1.4114105177649158e-05\n",
-      "131 0.0018634139997990387 1.4114105177649158e-05\n",
-      "132 0.0018622232106561458 6.675300035208331e-06\n",
-      "132 0.0018622232106561458 6.675300035208331e-06\n",
-      "133 0.0018609574982324088 5.9905721302628676e-06\n",
-      "133 0.0018609574982324088 5.9905721302628676e-06\n",
-      "134 0.0018580405964623032 7.793738075736936e-06\n",
-      "134 0.0018580405964623032 7.793738075736936e-06\n",
-      "135 0.0018619647082023106 6.21355527878094e-06\n",
-      "135 0.0018579380424125793 6.21355527878094e-06\n",
-      "135 0.0018579354526270543 6.21355527878094e-06\n",
-      "135 0.0018581819152827506 6.21355527878094e-06\n",
-      "135 0.0018578250026771094 6.21355527878094e-06\n",
-      "135 0.0018578250026771094 6.21355527878094e-06\n",
-      "136 0.0018561265960633036 5.262116183299268e-06\n",
-      "136 0.0018561265960633036 5.262116183299268e-06\n",
-      "137 0.0018541785149490267 4.266601313887413e-06\n",
-      "137 0.0018541785149490267 4.266601313887413e-06\n",
-      "138 0.0018488759253997083 5.7777829698971234e-06\n",
-      "138 0.0018488759253997083 5.7777829698971234e-06\n"
+      "0 0.49874914874144727 0.0\n",
+      "0 0.35646806992164465 0.0\n",
+      "0 0.35646806992164465 0.0\n",
+      "1 0.10295348512391408 0.0026620884996106735\n",
+      "1 0.10295348512391408 0.0026620884996106735\n",
+      "2 0.08035788007325083 0.0009668692767732778\n",
+      "2 0.08035788007325083 0.0009668692767732778\n",
+      "3 0.07187943515785958 0.00031890859179923886\n",
+      "3 0.07187943515785958 0.00031890859179923886\n",
+      "4 0.038170146192536496 0.00037037996170112954\n",
+      "4 0.038170146192536496 0.00037037996170112954\n",
+      "5 0.028223556307958524 0.0006233894309459988\n",
+      "5 0.028223556307958524 0.0006233894309459988\n",
+      "6 0.02590328552918505 0.0002853482012446442\n",
+      "6 0.02590328552918505 0.0002853482012446442\n",
+      "7 0.025198775406897213 0.0001970344038145016\n",
+      "7 0.025198775406897213 0.0001970344038145016\n",
+      "8 0.023445122744411937 0.00014519944498974952\n",
+      "8 0.023445122744411937 0.00014519944498974952\n",
+      "9 0.022026775927756863 0.00013405114330135054\n",
+      "9 0.022026775927756863 0.00013405114330135054\n",
+      "10 0.020840563571749304 0.00012373405753563282\n",
+      "10 0.020840563571749304 0.00012373405753563282\n",
+      "11 0.020719344622895444 0.00012757922565121227\n",
+      "11 0.020719344622895444 0.00012757922565121227\n",
+      "12 0.020338343294610088 0.00015526137577364293\n",
+      "12 0.020338343294610088 0.00015526137577364293\n",
+      "13 0.02017786912255595 7.181810044916066e-05\n",
+      "13 0.02017786912255595 7.181810044916066e-05\n",
+      "14 0.01994103965267256 4.9998342287331404e-05\n",
+      "14 0.01994103965267256 4.9998342287331404e-05\n",
+      "15 0.019704494681211177 4.7409310146026394e-05\n",
+      "15 0.019704494681211177 4.7409310146026394e-05\n",
+      "16 0.019426927967384815 0.00010372477846786122\n",
+      "16 0.019426927967384815 0.00010372477846786122\n",
+      "17 0.01918205337089224 6.683073884844981e-05\n",
+      "17 0.01918205337089224 6.683073884844981e-05\n",
+      "18 0.018953763637386007 4.6173886217614985e-05\n",
+      "18 0.018953763637386007 4.6173886217614985e-05\n",
+      "19 0.018846028917529265 2.685202455660492e-05\n",
+      "19 0.018846028917529265 2.685202455660492e-05\n",
+      "20 0.018631403631241637 6.678035796357086e-05\n",
+      "20 0.018631403631241637 6.678035796357086e-05\n",
+      "21 0.01854190974281003 4.502770115675276e-05\n",
+      "21 0.01854190974281003 4.502770115675276e-05\n",
+      "22 0.018514338740475453 3.425150060261202e-05\n",
+      "22 0.018514338740475453 3.425150060261202e-05\n",
+      "23 0.018485639082084466 4.2093417533664e-05\n",
+      "23 0.018485639082084466 4.2093417533664e-05\n",
+      "24 0.018437053824497146 5.0428966980653616e-05\n",
+      "24 0.018437053824497146 5.0428966980653616e-05\n",
+      "25 0.018425461070956453 3.9222548220596345e-05\n",
+      "25 0.018425461070956453 3.9222548220596345e-05\n",
+      "26 0.01852384178503566 6.238806741127468e-05\n",
+      "26 0.018420270553537392 6.238806741127468e-05\n",
+      "26 0.01842016238791905 6.238806741127468e-05\n",
+      "26 0.018422538337010373 6.238806741127468e-05\n",
+      "26 0.018422538337010373 6.238806741127468e-05\n",
+      "27 0.018392520093583706 2.3287332662026332e-05\n",
+      "27 0.018392520093583706 2.3287332662026332e-05\n",
+      "28 0.01831472329232676 2.0191633170106407e-05\n",
+      "28 0.01831472329232676 2.0191633170106407e-05\n",
+      "29 0.018529469647988846 4.3538612826341447e-05\n",
+      "29 0.018312326627365736 4.3538612826341447e-05\n",
+      "29 0.018312268052452514 4.3538612826341447e-05\n",
+      "29 0.018328527252521622 4.3538612826341447e-05\n",
+      "29 0.018307489272187928 4.3538612826341447e-05\n",
+      "29 0.018307489272187928 4.3538612826341447e-05\n",
+      "30 0.018257012965416777 3.710362908385634e-05\n",
+      "30 0.018257012965416777 3.710362908385634e-05\n",
+      "31 0.018199414633997116 2.418240445691537e-05\n",
+      "31 0.018199414633997116 2.418240445691537e-05\n",
+      "32 0.018327799631967776 2.2510977746555563e-05\n",
+      "32 0.01818954110829634 2.2510977746555563e-05\n",
+      "32 0.01818934437019836 2.2510977746555563e-05\n",
+      "32 0.018161797300166267 2.2510977746555563e-05\n",
+      "32 0.018161797300166267 2.2510977746555563e-05\n",
+      "33 0.01803313305608169 7.344332905384619e-05\n",
+      "33 0.01803313305608169 7.344332905384619e-05\n",
+      "34 0.01793568854717946 4.875831903824109e-05\n",
+      "34 0.01793568854717946 4.875831903824109e-05\n",
+      "35 0.01781604477262699 3.3555504970583496e-05\n",
+      "35 0.01781604477262699 3.3555504970583496e-05\n",
+      "36 0.01756732224682609 4.2590439882522e-05\n",
+      "36 0.01756732224682609 4.2590439882522e-05\n",
+      "37 0.01782173285103622 5.634135538237805e-05\n",
+      "37 0.017528561930617494 5.634135538237805e-05\n",
+      "37 0.017527874539442618 5.634135538237805e-05\n",
+      "37 0.017527874539442618 5.634135538237805e-05\n",
+      "38 0.017169104545275437 5.371233437262628e-05\n",
+      "38 0.017169104545275437 5.371233437262628e-05\n",
+      "39 0.017397158463502704 5.716798217701129e-05\n",
+      "39 0.017158738851705792 5.716798217701129e-05\n",
+      "39 0.017158563298653954 5.716798217701129e-05\n",
+      "39 0.017127194203732793 5.716798217701129e-05\n",
+      "39 0.017127194203732793 5.716798217701129e-05\n",
+      "40 0.016999822367518517 0.00010263964660788626\n",
+      "40 0.016999822367518517 0.00010263964660788626\n",
+      "41 0.016939375873726844 3.062002722380767e-05\n",
+      "41 0.016939375873726844 3.062002722380767e-05\n",
+      "42 0.016900071415636653 2.4804779178967365e-05\n",
+      "42 0.016900071415636653 2.4804779178967365e-05\n",
+      "43 0.016818812714435576 2.173821290765853e-05\n",
+      "43 0.016818812714435576 2.173821290765853e-05\n",
+      "44 0.016719878871306864 6.350741184557774e-05\n",
+      "44 0.016719878871306864 6.350741184557774e-05\n",
+      "45 0.016639319245053432 3.213702163926461e-05\n",
+      "45 0.016639319245053432 3.213702163926461e-05\n",
+      "46 0.01654898672520315 3.675404131968701e-05\n",
+      "46 0.01654898672520315 3.675404131968701e-05\n",
+      "47 0.016538693545448742 2.8717093761991423e-05\n",
+      "47 0.016538693545448742 2.8717093761991423e-05\n",
+      "48 0.016473103960845337 8.379909294888409e-05\n",
+      "48 0.016473103960845337 8.379909294888409e-05\n",
+      "49 0.016416379818304832 3.978562134164317e-05\n",
+      "49 0.016416379818304832 3.978562134164317e-05\n",
+      "50 0.016374861693503176 2.4173639492780945e-05\n",
+      "50 0.016374861693503176 2.4173639492780945e-05\n",
+      "51 0.016320616558310182 2.280657179182863e-05\n",
+      "51 0.016320616558310182 2.280657179182863e-05\n",
+      "52 0.016237656611297765 3.371468880757649e-05\n",
+      "52 0.016237656611297765 3.371468880757649e-05\n",
+      "53 0.01617282865374967 3.5313111171397404e-05\n",
+      "53 0.01617282865374967 3.5313111171397404e-05\n",
+      "54 0.016280556796496978 2.4527158282666573e-05\n",
+      "54 0.016171735511775417 2.4527158282666573e-05\n",
+      "54 0.016171715185304417 2.4527158282666573e-05\n",
+      "54 0.01618628802013192 2.4527158282666573e-05\n",
+      "54 0.016170397272351235 2.4527158282666573e-05\n",
+      "54 0.01617024487627024 2.4527158282666573e-05\n",
+      "54 0.016167524879107553 2.4527158282666573e-05\n",
+      "54 0.016167524879107553 2.4527158282666573e-05\n",
+      "55 0.01616003070096128 2.4023997816247153e-05\n",
+      "55 0.01616003070096128 2.4023997816247153e-05\n",
+      "56 0.016157763482578403 2.1346285312556152e-05\n",
+      "56 0.016157763482578403 2.1346285312556152e-05\n",
+      "57 0.01616700894993573 3.1856411389332574e-05\n",
+      "57 0.016151948056690492 3.1856411389332574e-05\n",
+      "57 0.016151948056690492 3.1856411389332574e-05\n",
+      "58 0.016183298937842004 3.3422468602652076e-05\n",
+      "58 0.01613435173164382 3.3422468602652076e-05\n",
+      "58 0.01613435173164382 3.3422468602652076e-05\n",
+      "59 0.016131150282898285 3.15286642677604e-05\n",
+      "59 0.016131150282898285 3.15286642677604e-05\n",
+      "60 0.01609960849350739 4.693994830345397e-05\n",
+      "60 0.01609960849350739 4.693994830345397e-05\n",
+      "61 0.01605927896547515 2.931621743460376e-05\n",
+      "61 0.01605927896547515 2.931621743460376e-05\n",
+      "62 0.015967800837589606 2.4603773489791228e-05\n",
+      "62 0.015967800837589606 2.4603773489791228e-05\n",
+      "63 0.015972211210877413 2.134784014504225e-05\n",
+      "63 0.01596660638126234 2.134784014504225e-05\n",
+      "63 0.015966224222254338 2.134784014504225e-05\n",
+      "63 0.015965327189121466 2.134784014504225e-05\n",
+      "63 0.015965327189121466 2.134784014504225e-05\n",
+      "64 0.015931832738400743 2.1856098308487245e-05\n",
+      "64 0.015931832738400743 2.1856098308487245e-05\n",
+      "65 0.015920996329924064 3.5901324984501164e-05\n",
+      "65 0.015920996329924064 3.5901324984501164e-05\n",
+      "66 0.015834010264175725 2.0897034514522628e-05\n",
+      "66 0.015834010264175725 2.0897034514522628e-05\n",
+      "67 0.015713514626898375 1.9272611004002098e-05\n",
+      "67 0.015713514626898375 1.9272611004002098e-05\n",
+      "68 0.0156780352050336 1.674366168036431e-05\n",
+      "68 0.015673072228713354 1.674366168036431e-05\n",
+      "68 0.015673072228713354 1.674366168036431e-05\n",
+      "69 0.015633591000682113 3.2525528880471384e-05\n",
+      "69 0.015633591000682113 3.2525528880471384e-05\n",
+      "70 0.01556876453303082 1.846576593637222e-05\n",
+      "70 0.01556876453303082 1.846576593637222e-05\n",
+      "71 0.015518983413157866 1.6423060965051656e-05\n",
+      "71 0.015518983413157866 1.6423060965051656e-05\n",
+      "72 0.015459791359176796 1.6829350046200194e-05\n",
+      "72 0.015459791359176796 1.6829350046200194e-05\n",
+      "73 0.015443693402162657 2.333407007851926e-05\n",
+      "73 0.015443693402162657 2.333407007851926e-05\n",
+      "74 0.015422886539422651 3.597889071472924e-05\n",
+      "74 0.015422886539422651 3.597889071472924e-05\n",
+      "75 0.015420617760226192 2.0679634389968406e-05\n",
+      "75 0.015420617760226192 2.0679634389968406e-05\n",
+      "76 0.015418219022111154 1.243403838262193e-05\n",
+      "76 0.015418219022111154 1.243403838262193e-05\n",
+      "77 0.015397074721454976 1.2413200552990872e-05\n",
+      "77 0.015392861451166612 1.2413200552990872e-05\n",
+      "77 0.015392861451166612 1.2413200552990872e-05\n",
+      "78 0.015363996815726526 2.8912914126315856e-05\n",
+      "78 0.015363996815726526 2.8912914126315856e-05\n",
+      "79 0.01533087613710824 1.7176036554712764e-05\n",
+      "79 0.01533087613710824 1.7176036554712764e-05\n",
+      "80 0.01526455347192918 1.3673258904559342e-05\n",
+      "80 0.01526455347192918 1.3673258904559342e-05\n",
+      "81 0.01517937744360524 2.1444647053295144e-05\n",
+      "81 0.01517937744360524 2.1444647053295144e-05\n",
+      "82 0.015092664815582857 2.9681572102399857e-05\n",
+      "82 0.015119523470234325 2.9681572102399857e-05\n",
+      "82 0.015119523470234325 2.9681572102399857e-05\n",
+      "83 0.015064078764178585 3.706229586133227e-05\n",
+      "83 0.015064078764178585 3.706229586133227e-05\n",
+      "84 0.015033472422681089 1.9516886059533265e-05\n",
+      "84 0.015033472422681089 1.9516886059533265e-05\n",
+      "85 0.014996942533301036 1.158413017775518e-05\n",
+      "85 0.014996942533301036 1.158413017775518e-05\n",
+      "86 0.014966703448472419 2.481945646217349e-05\n",
+      "86 0.014966703448472419 2.481945646217349e-05\n",
+      "87 0.014913005050132676 1.9880885469736253e-05\n",
+      "87 0.014913005050132676 1.9880885469736253e-05\n",
+      "88 0.014861309037298437 6.834991808521764e-05\n",
+      "88 0.014861309037298437 6.834991808521764e-05\n",
+      "89 0.014830916650449786 2.3986646181845994e-05\n",
+      "89 0.014830916650449786 2.3986646181845994e-05\n",
+      "90 0.014806469980290705 8.554666652515568e-06\n",
+      "90 0.014806469980290705 8.554666652515568e-06\n",
+      "91 0.014788434119205215 9.406824983315805e-06\n",
+      "91 0.014788434119205215 9.406824983315805e-06\n",
+      "92 0.014745430166370477 1.3714930471187137e-05\n",
+      "92 0.014745430166370477 1.3714930471187137e-05\n",
+      "93 0.01471204161560252 1.2472075360330234e-05\n",
+      "93 0.01471204161560252 1.2472075360330234e-05\n",
+      "94 0.014681882186110372 2.3823338539220317e-05\n",
+      "94 0.014681882186110372 2.3823338539220317e-05\n",
+      "95 0.014670186382245985 1.7215219511174368e-05\n",
+      "95 0.014670186382245985 1.7215219511174368e-05\n",
+      "96 0.014666043361451832 1.0520707029831575e-05\n",
+      "96 0.014666043361451832 1.0520707029831575e-05\n",
+      "97 0.014661505440730797 1.728671065644675e-05\n",
+      "97 0.014661505440730797 1.728671065644675e-05\n",
+      "98 0.014652771813050438 3.1195396784285585e-05\n",
+      "98 0.014652771813050438 3.1195396784285585e-05\n",
+      "99 0.014637404555737685 1.880305758156002e-05\n",
+      "99 0.014637404555737685 1.880305758156002e-05\n",
+      "100 0.014623334384433346 1.2053567504659005e-05\n",
+      "100 0.014623334384433346 1.2053567504659005e-05\n",
+      "101 0.014599458266245407 1.3992092900481002e-05\n",
+      "101 0.014599458266245407 1.3992092900481002e-05\n",
+      "102 0.014627141414754222 2.8722489343976205e-05\n",
+      "102 0.01459691973427258 2.8722489343976205e-05\n",
+      "102 0.014596893278949658 2.8722489343976205e-05\n",
+      "102 0.01459186930218319 2.8722489343976205e-05\n",
+      "102 0.01459186930218319 2.8722489343976205e-05\n",
+      "103 0.014572269306843393 3.238793039956159e-05\n",
+      "103 0.014572269306843393 3.238793039956159e-05\n",
+      "104 0.014548151722344648 2.0813016072207007e-05\n",
+      "104 0.014548151722344648 2.0813016072207007e-05\n",
+      "105 0.014532410903766675 1.2149510407953024e-05\n",
+      "105 0.014532410903766675 1.2149510407953024e-05\n",
+      "106 0.014500490969368587 1.8397182319511664e-05\n",
+      "106 0.014500490969368587 1.8397182319511664e-05\n",
+      "107 0.014511106180134065 3.053899495542591e-05\n",
+      "107 0.014494858261426878 3.053899495542591e-05\n",
+      "107 0.014494858261426878 3.053899495542591e-05\n",
+      "108 0.014465047584723457 2.523965085400385e-05\n",
+      "108 0.014465047584723457 2.523965085400385e-05\n",
+      "109 0.014438316916050388 2.1997795600567845e-05\n",
+      "109 0.014438316916050388 2.1997795600567845e-05\n",
+      "110 0.014399369608465955 1.4865737474040754e-05\n",
+      "110 0.014399369608465955 1.4865737474040754e-05\n",
+      "111 0.014474144106975846 1.878415002350575e-05\n",
+      "111 0.01439851514606237 1.878415002350575e-05\n",
+      "111 0.014398527810004006 1.878415002350575e-05\n",
+      "111 0.01439851514606237 1.878415002350575e-05\n",
+      "111 0.01439851514606237 1.878415002350575e-05\n",
+      "112 0.014373458155566985 1.789168870309464e-05\n",
+      "112 0.014373458155566985 1.789168870309464e-05\n",
+      "113 0.014356091991294962 2.0388216342805194e-05\n",
+      "113 0.014356091991294962 2.0388216342805194e-05\n",
+      "114 0.01434318019162258 1.8918139065378327e-05\n",
+      "114 0.01434318019162258 1.8918139065378327e-05\n",
+      "115 0.014316740095825937 6.14985391535976e-05\n",
+      "115 0.014316740095825937 6.14985391535976e-05\n",
+      "116 0.014308635865831195 1.3000478788591865e-05\n",
+      "116 0.014308635865831195 1.3000478788591865e-05\n",
+      "117 0.014298659289446961 1.503280963531029e-05\n",
+      "117 0.014298659289446961 1.503280963531029e-05\n",
+      "118 0.014283268598161626 1.7751529752815044e-05\n",
+      "118 0.014283268598161626 1.7751529752815044e-05\n",
+      "119 0.014329470908451413 2.301848307794546e-05\n",
+      "119 0.0142825898108808 2.301848307794546e-05\n",
+      "119 0.014282596175795519 2.301848307794546e-05\n",
+      "119 0.0142825898108808 2.301848307794546e-05\n",
+      "119 0.0142825898108808 2.301848307794546e-05\n",
+      "120 0.014267323756147286 2.2083780696607826e-05\n",
+      "120 0.014267323756147286 2.2083780696607826e-05\n",
+      "121 0.014253008246919848 1.4049007807004813e-05\n",
+      "121 0.014253008246919848 1.4049007807004813e-05\n",
+      "122 0.014228990100999714 1.4905025915792125e-05\n",
+      "122 0.014228990100999714 1.4905025915792125e-05\n",
+      "123 0.01418012137875261 1.7853205433985056e-05\n",
+      "123 0.01418012137875261 1.7853205433985056e-05\n",
+      "124 0.014212409318107837 1.798709949082063e-05\n",
+      "124 0.014177870355709794 1.798709949082063e-05\n",
+      "124 0.014177870355709794 1.798709949082063e-05\n",
+      "125 0.014151574900440486 1.6965494570140058e-05\n",
+      "125 0.014151574900440486 1.6965494570140058e-05\n",
+      "126 0.014143302673057054 8.529928755660089e-06\n",
+      "126 0.014143302673057054 8.529928755660089e-06\n",
+      "127 0.014117866289493578 6.534360679522373e-06\n",
+      "127 0.014117866289493578 6.534360679522373e-06\n",
+      "128 0.014099673969240773 9.404277074588466e-06\n",
+      "128 0.014099673969240773 9.404277074588466e-06\n",
+      "129 0.014075230331225411 1.5457491950434014e-05\n",
+      "129 0.014075230331225411 1.5457491950434014e-05\n",
+      "130 0.014067920741732673 2.0159711607004447e-05\n",
+      "130 0.014067920741732673 2.0159711607004447e-05\n",
+      "131 0.014068528363467621 4.751221167143262e-06\n"
      ]
     },
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "139 0.0018488214728622956 8.851509846565252e-06\n",
-      "139 0.0018488214728622956 8.851509846565252e-06\n",
-      "140 0.0018455469378301228 2.599417286662253e-05\n",
-      "140 0.0018455469378301228 2.599417286662253e-05\n",
-      "141 0.001842810237598681 6.118751047386717e-06\n",
-      "141 0.001842810237598681 6.118751047386717e-06\n",
-      "142 0.0018381434535997365 4.980478460443563e-06\n",
-      "142 0.0018381434535997365 4.980478460443563e-06\n",
-      "143 0.0018345788639350415 6.298596212917168e-06\n",
-      "143 0.0018345788639350415 6.298596212917168e-06\n",
-      "144 0.0018341905117658917 9.925644451932482e-06\n",
-      "144 0.0018341905117658917 9.925644451932482e-06\n",
-      "145 0.0018275382956829034 2.106023039839816e-05\n",
-      "145 0.0018275382956829034 2.106023039839816e-05\n",
-      "146 0.001826388215684216 1.0988414675348195e-05\n",
-      "146 0.001826388215684216 1.0988414675348195e-05\n",
-      "147 0.0018247374240779979 5.3445245755900645e-06\n",
-      "147 0.0018247374240779979 5.3445245755900645e-06\n",
-      "148 0.001818814965177224 6.493776649277651e-06\n",
-      "148 0.001818814965177224 6.493776649277651e-06\n",
-      "149 0.0018145124514857313 1.4350173651247737e-05\n",
-      "149 0.0018145124514857313 1.4350173651247737e-05\n",
-      "150 0.0018066250300585167 1.5691026184229582e-05\n",
-      "Solution = [0.13402887609394482, 0.38638569619547997, 0.23606438303975347, 0.08090428115206634, 0.3371552494822925, 0.6297552297838296, 1.1229306570791724, 0.5915276797073591, -0.6501585707310422, -0.7446125409124095, 1.5822996076684495, 0.33812689655954936, -0.09533707327220255, 0.14323242573263428, 0.39314045140991594, 0.01781402159117454, 0.44014202472024216, -0.34604681545726734, 0.8547492367739802, 0.48990145314663786, 2.6749226196952196, -1.115997974713456, -2.2156304215727864, 1.3388512328189912, -1.0166326637160048, 0.40567013436780897, 0.4902943676933346, -0.4657187939300901, -0.2555566706555399, 1.2858430169256285, 2.1924469624186034, 0.06952772124813388, -0.2117963367624445, -3.483371050637788, 0.2831559210498422, 0.45890124174333025, 3.414791757987822, -1.4964415045565087, 5.487554613707934, 2.0563929913927126, 3.6636118391013515, -0.3807696412152009, -0.6332402583374483, 0.44570394154035636, 0.1349228672715871, -1.9586756989974752, -0.43366531768299427, 0.14029650505679847, -0.054114649467300116, -0.5083922268479795, -0.07099260709634977, 0.03728747070526949, 0.5164211248876853, 1.2525939847253014, 2.6352389013389494, 0.4726049750573159, 0.8098614338927825, 2.2290435919556892, 2.9043193108797665, 0.4358126005278896, 0.04372904454553582, -0.17712576252753612, 0.09010849377520042, 0.04248498492279253, 0.01223590604363185, 0.23279929123081108, 0.09047686953540336, -0.08139176694422395, 0.19202795282424606, -0.634807469094887, -0.10656627630760404, -0.07819133706175223, 0.5265148877559752, -0.13480648932268952, 0.6613949318863346, 0.5723320665406273, 0.09111542897140043, 0.42576208634333257, 0.4342839852027086, 0.09950677971056757, -0.156382630346921, 1.7866157394416238, 0.2660375267913238, -0.5755626655447524, 1.01693940282988, 1.1509732776949892, 0.36381390390395646, 0.4471046323278427, 2.136348163836796, 2.493602467332689, -1.4615517705722725, 0.8990209460725334, -0.09044169348278833, 0.36104234336770813, -1.9926033922770345, -0.6721296056163661, -0.20584241565063283, 3.6633139805476738, 2.09481291943043, -0.3947558284710436, -0.7042816279383664, -1.0402970542204806, -1.8928521049020093, -0.6745743503897967, -2.58959112927434, -1.6728998075845298, 1.2573912942726535, -2.6913162173492307, -1.01002291778196, -0.5452327942699867, -2.426963175865346, -1.5426157950259753, -0.032788534297728975, 0.5666485439579507, 0.7026943381399053, 0.016612868290184636, -0.4964737922688639, -1.5340055878182774, 1.17155365623282, 0.053087199196095426, -0.36073715476533846, 3.8244385295298486, 5.614689616021612, -0.11038651919391634, -0.023662733868969568, 1.4681747949368995, 1.1172969873781085, -0.11472777348956885, 0.1449026071653071, 0.7140396698319708, 0.3431309289891663, -0.11253152597933845, 0.24299313896282662, 2.8354883696615905, -0.20263660945631462, -1.7232716709754285, -0.8830112348451592, -2.2219982131402, -4.191692565214607, -1.8666856707573343, -0.11646817800061632, -0.4571616974849223, -0.634137429528726, -0.1532889027157762, 1.027878699892728, -0.09788073444087389, -2.8338435420330383, -0.8109594305764039, 1.5604842372928454, -0.7238312237774122, 0.2281581976182558, -5.828843030703713, -1.8819478265095853, 0.43418325530092144, 3.02644640015456, -3.95112808408695, 0.39508288323345686, 2.438019488369614, -0.46554639096082967, -0.2725516749875228, 0.4230871002497909, -6.340114544972837, -7.54828683791304, -0.5541084804171731, 4.014375480276859, -3.1151755056752277, 3.538658134726041, 2.1842772830928747, 6.640082980035057, 1.5739462067596686, -4.037125817215529, 4.1939012019657165, 1.3181398735725214, -1.64624490603558, -6.339834341795177, 0.11531274484948192, 0.03130534903303278, -0.5852740144690427, -0.6759141397598057, -0.02469081670769886, 1.4263118053122015, 5.717379812994844, 3.403525966338044, 0.7546373580413233, 1.724077820650585, -2.471524317890313, -6.879051222251853, 0.5233901673952562, 0.12660694695255617, -2.164041703558112, -2.7992202738263874, -0.05941913541633608]\n",
-      "Wrote resulting mesh to Data/901-meansquares-registered.vtk\n"
+      "131 0.014067941013986313 4.751221167143262e-06\n",
+      "131 0.014067964267936404 4.751221167143262e-06\n",
+      "131 0.014067920705364313 4.751221167143262e-06\n",
+      "131 0.014067920706291915 4.751221167143262e-06\n",
+      "131 0.014067920705364313 4.751221167143262e-06\n",
+      "131 0.014067920705364313 4.751221167143262e-06\n",
+      "Solution = [0.014559554532286315, 0.12014350981921557, 0.7987503672311127, 0.12030057710564017, 0.6788038918612957, 1.5143760317904724, 4.745896727046189, 0.8406573458978361, 0.6651776106824592, 1.0193041810049719, 2.7805916020355346, 0.6228623629908627, -0.016504320743012342, -0.2782048145186771, 0.06187687622661249, 0.05234694478796978, 0.6744924117051408, 0.5999101628805228, 2.177563761137019, 0.4782038222375929, 7.189322119112429, -4.102057176569233, 2.757327852881054, 3.0415623211282186, 6.587801209038333, -2.580599375582684, 5.1114076016347925, 3.57606572764389, 0.4978279852600288, -0.9940029033501432, 0.13186057262262493, 0.44372284163806985, 0.16809784969253344, -0.12290561481264638, 2.268174833600322, 0.4155860263734787, 4.555485268867857, -4.229444258289236, 7.957644573235557, 3.088595794465324, 7.358403637408978, -0.5190890198129035, 3.4217676044791263, 3.3728341487664153, 1.0962476432612445, 0.291363267500206, -0.8071058457143645, 0.34116813444675015, -0.113263821741509, -0.17135364766341948, 0.6044692998719549, 0.08178044021928588, -0.10602291476131517, 0.3277038043895957, 4.454428827633091, 0.680568930776753, 0.7177650385920686, 0.818733259825012, 1.676821306546833, 0.49166165137293244, 0.13061488128670057, 0.04687513572205919, -0.16311675491201616, 0.026828586050990342, 0.06735635042292179, -0.0413882668903786, -1.3047775244330235, -0.20170267484792817, 1.240218487260906, 5.185341498721238, -3.7155027316078364, -0.8698215575781665, 2.2203312498200405, 2.981100178479041, -4.359046011537595, -0.029230219880135733, 0.3347986569824664, -0.6450935544885501, -1.424783643489878, 0.03546923495598825, 0.7858154802388289, 4.039456366906765, -3.5490936841483403, -0.9279809712287967, 2.271719770383777, -2.377998038591373, 1.979129536529007, 0.8382744423048009, 15.488613402350417, -1.1857260981437396, -2.8283009854050123, 7.464776163150316, 4.434467557975684, 3.7303899908763447, -4.455305607853352, 1.036576100588723, 0.3683434387080299, 3.289903851361927, -3.312369988857147, -0.9039092495639126, 1.3051272970500514, -1.1040585217171164, 0.3701771294450529, 0.30230988624017036, 14.129237442256258, -3.2483180198669785, 1.1536510657718066, 7.737740273777916, 4.254712408199128, 4.356396613324541, -2.20344009292209, 1.210852212141439, -0.06730643114937142, -0.3292685174543237, -1.0608262010677518, -0.16273661667020134, 0.5852133650569232, 3.2579787390212487, -3.121096412870278, -0.6982378762488956, 1.6306059361923513, 1.281188061194992, -2.1640959691268518, 0.30647094524573165, 0.29618553602634845, -0.3882592000748886, -0.6700220280229727, 0.10195986663798597, -0.17814943194093058, -0.9836515344037943, -1.0048144260618814, -0.1349035724613002, -0.6136880448647852, 3.097936053340804, 0.3716718961913595, -0.9897018208492101, -0.6816705694070737, 3.9334788466069437, 2.5598063877819675, -0.817073602639032, -0.2292094131402109, -0.7050386439301083, -0.2723114129762761, -0.08645345376468942, -0.5366779673437596, -3.71608469445486, -3.027751073546264, -0.3537860495691095, -3.1059145646308024, -0.9048317504302119, 1.5666834646589405, -2.4685118444120673, -3.171111311656828, -0.7138538129079237, 0.14358887986797533, -2.8648548093377144, -0.7530847645000123, -3.8515185546048842, -2.72262564187498, -0.4097915970110762, 0.8632635552271104, 1.358972858440786, 1.4794020217980495, 0.410695409017533, 5.7773588606845605, -0.7994963730672962, 1.3656164039698158, 3.5579064398710196, 5.747093883878372, 1.993656515889032, -2.0815155592814967, 3.0827846671583066, 0.5770732367621493, -0.5383595257095501, -0.7050151392677974, 0.3071040492839861, 0.202805298834437, 0.595659173952605, 0.5421816642763735, 0.10072212412941452, 0.8239655255720084, -3.2758470426646724, -0.8828932110461131, 0.8920181378753079, 0.6698508294463396, -3.505175025508774, -0.9600420493788181, 0.9575317120376746, 0.12597253477361933, 0.07178875319478967, 0.22379974953841417, 0.1153459270680338]\n",
+      "Wrote resulting mesh to Output/901-meansquares-registered.obj\n"
      ]
     }
    ],
    "source": [
-    "meansquares_mesh_result = registrar.register(template_mesh=fixed_mesh,\n",
-    "                                             target_mesh=moving_mesh,\n",
+    "(transform, mesh_result) = registrar.register(template_mesh,\n",
+    "                                             target_mesh,\n",
     "                                             filepath=MEANSQUARES_OUTPUT_FILE,\n",
-    "                                             num_iterations=200,\n",
-    "                                             verbose=True)"
+    "                                             verbose=True,\n",
+    "                                             num_iterations=200)"
    ]
   },
   {
@@ -665,49 +690,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
-   "metadata": {
-    "scrolled": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "c656c68980d14b0597f40a6b0caba96b",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'numberOfComponents': 3, 'd…"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "view(geometries=[meansquares_mesh_result,moving_mesh])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Comparison of the resulting mesh with the output file shows congruency."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "file_mesh_result = itk.meshread(MEANSQUARES_OUTPUT_FILE, itk.F)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 38,
    "metadata": {
     "scrolled": true
    },
@@ -715,12 +698,12 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "556bd9eb307c4fa68194ee52f9fce4d8",
+       "model_id": "47bc08d43e684e6ba03a81e9e0f9da4f",
        "version_major": 2,
        "version_minor": 0
       },
       "text/plain": [
-       "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'numberOfComponents': 3, 'd…"
+       "AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
       ]
      },
      "metadata": {},
@@ -728,7 +711,9 @@
     }
    ],
    "source": [
-    "view(geometries=[file_mesh_result,meansquares_mesh_result])"
+    "#view(geometries=[meansquares_mesh_result,moving_mesh])\n",
+    "result_image = registrar.mesh_to_image(mesh_result, target_image)\n",
+    "compare(result_image, target_image)"
    ]
   },
   {
@@ -744,7 +729,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -753,7 +738,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -762,13 +747,13 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 26,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "4689c76cf18e4e32a5e8c45d3cb53aa2",
+       "model_id": "752109096b8944c2820a03f87ba22000",
        "version_major": 2,
        "version_minor": 0
       },
@@ -795,7 +780,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 27,
    "metadata": {
     "scrolled": true
    },
@@ -805,207 +790,207 @@
      "output_type": "stream",
      "text": [
       "1.7976931348623157e+308\n",
-      "0.039025624562107085\n",
-      "0.03620058111051529\n",
-      "0.03385740047695736\n",
-      "0.0316529992799868\n",
-      "0.02967127488345423\n",
-      "0.02786333676924597\n",
-      "0.026263721371434446\n",
-      "0.024784571211718686\n",
-      "0.023439112890373825\n",
-      "0.022179969985074023\n",
-      "0.021160217575979016\n",
-      "0.02022989923756486\n",
-      "0.019367058349974004\n",
-      "0.018567845127124925\n",
-      "0.017848969406583762\n",
-      "0.017187661496342346\n",
-      "0.01657368277679982\n",
-      "0.01599817637581068\n",
-      "0.015457831585642885\n",
-      "0.014948025199071284\n",
-      "0.014461622847641747\n",
-      "0.014000352105777525\n",
-      "0.013558082766414237\n",
-      "0.01311751745327867\n",
-      "0.012612455200814074\n",
-      "0.012162631078637215\n",
-      "0.011740243666151801\n",
-      "0.011309865240838799\n",
-      "0.010899203476967509\n",
-      "0.010521650813570736\n",
-      "0.010196561107985157\n",
-      "0.009891130130343635\n",
-      "0.009600816910980125\n",
-      "0.009315760503390665\n",
-      "0.009039516487389243\n",
-      "0.008767196010894804\n",
-      "0.008506293948833205\n",
-      "0.008248633969299386\n",
-      "0.00799543225258579\n",
-      "0.0077453645420522965\n",
-      "0.00749730174447974\n",
-      "0.007257772289115741\n",
-      "0.007027261536318484\n",
-      "0.0068053907333040725\n",
-      "0.006592009351901685\n",
-      "0.006385407763355719\n",
-      "0.006188817973227064\n",
-      "0.005999093025599275\n",
-      "0.005811112139699502\n",
-      "0.005627719817663616\n",
-      "0.005450013698900426\n",
-      "0.005276483161505481\n",
-      "0.005107718474447619\n",
-      "0.004944021699863354\n",
-      "0.004784881046850776\n",
-      "0.004627403945911204\n",
-      "0.004472631444322943\n",
-      "0.00432708986678605\n",
-      "0.004181755611710442\n",
-      "0.004046007042062048\n",
-      "0.003910543564363515\n",
-      "0.003776928835572415\n",
-      "0.003651748774315907\n",
-      "0.0035254355563773946\n",
-      "0.0034056166274056584\n",
-      "0.0032874208444440187\n",
-      "0.0031766063482686433\n",
-      "0.0030732377341834986\n",
-      "0.0029663118260594124\n",
-      "0.0028654978328103895\n",
-      "0.0027705034302599975\n",
-      "0.0026746611593414884\n",
-      "0.002581828293476095\n",
-      "0.0024926027552577873\n",
-      "0.0024041100509028675\n",
-      "0.0023211537031277334\n",
-      "0.0022394923684441784\n",
-      "0.0021573903066322564\n",
-      "0.0020814704811892046\n",
-      "0.0020060111617612683\n",
-      "0.0019369915179307477\n",
-      "0.0018649415726044625\n",
-      "0.0018017916860055036\n",
-      "0.0017384859107382948\n",
-      "0.0016788831232328189\n",
-      "0.0016249236832228252\n",
-      "0.0015726446858505016\n",
-      "0.0015220808485447667\n",
-      "0.0014738722656119662\n",
-      "0.0014252690409045166\n",
-      "0.0013813925110105407\n",
-      "0.0013371158259658372\n",
-      "0.0012945639055305799\n",
-      "0.001252099575874205\n",
-      "0.0012112875077578335\n",
-      "0.0011739707910407246\n",
-      "0.0011380005543078454\n",
-      "0.001101071635015579\n",
-      "0.0010653847603036089\n",
-      "0.0010318723358539467\n",
-      "0.0009972384165631203\n",
-      "0.000966312922775045\n",
-      "0.0009342770999523545\n",
-      "0.0009045181337248312\n",
-      "0.0008768690771979427\n",
-      "0.0008500828244220042\n",
-      "0.0008254308975864035\n",
-      "0.0008010413062407819\n",
-      "0.0007760553272720413\n",
-      "0.000753211383801746\n",
-      "0.000729756847116741\n",
-      "0.0007076614714839721\n",
-      "0.0006874866020348999\n",
-      "0.0006662312584093007\n",
-      "0.0006451482244339356\n",
-      "0.000627055849899595\n",
-      "0.0006092029421030994\n",
-      "0.0005874783028960857\n",
-      "0.0005717931942866128\n",
-      "0.0005549292888368047\n",
-      "0.0005380478371784952\n",
-      "0.0005201146650359145\n",
-      "0.0005054419685110467\n",
-      "0.0004924934986366237\n",
-      "0.00047739876792524756\n",
-      "0.00046469263404502135\n",
-      "0.0004536443655474988\n",
-      "0.0004412859633354016\n",
-      "0.00042848630259308915\n",
-      "0.00041766763881578004\n",
-      "0.0004072797829573886\n",
-      "0.0003959767465342979\n",
-      "0.00038491058157508494\n",
-      "0.00037565536484099885\n",
-      "0.00036738715164529696\n",
-      "0.0003576693564867682\n",
-      "0.0003478250341790231\n",
-      "0.0003392932258692299\n",
-      "0.00033114287304467506\n",
-      "0.0003221956622535673\n",
-      "0.00031399916957712304\n",
-      "0.0003071797291965539\n",
-      "0.0003006855530398379\n",
-      "0.00029443366939331994\n",
-      "0.0002868720363774873\n",
-      "0.0002807450793450514\n",
-      "0.0002750292160159778\n",
-      "0.0002696259382267158\n",
-      "0.00026381029567148877\n",
-      "0.00025747523460078786\n",
-      "0.00025246120875020776\n",
-      "0.00024737284238620174\n",
-      "0.00024211694965375674\n",
-      "0.00023645391595279223\n",
-      "0.00023244279139616122\n",
-      "0.00022849429549262563\n",
-      "0.000224154946090284\n",
-      "0.00021992880522408423\n",
-      "0.00021512615793204347\n",
-      "0.00021112664175118356\n",
-      "0.000208052177442707\n",
-      "0.00020474338345446234\n",
-      "0.00020072304144019672\n",
-      "0.00019775908628190988\n",
-      "0.00019465371448508102\n",
-      "0.00019172507890867358\n",
-      "0.00018905619608860144\n",
-      "0.00018583485063236214\n",
-      "0.00018278286577062247\n",
-      "0.0001801076905540537\n",
-      "0.00017738310919106166\n",
-      "0.00017473395371285803\n",
-      "0.0001727125726534076\n",
-      "0.00017047710685367778\n",
-      "0.00016821089468757003\n",
-      "0.0001659042372877211\n",
-      "0.00016407927565906488\n",
-      "0.00016247074847690454\n",
-      "0.0001601752052319858\n",
-      "0.00015844276355980668\n",
-      "0.0001567643486716562\n",
-      "0.0001548519720160484\n",
-      "0.0001539444764862004\n",
-      "0.00015242706419291767\n",
-      "0.00015028598879511014\n",
-      "0.00014889764349392524\n",
-      "0.00014737156388394115\n",
-      "0.00014625559851989025\n",
-      "0.0001448521264190814\n",
-      "0.00014381301362204171\n",
-      "0.0001419614668236029\n",
-      "0.0001408659763373339\n",
-      "0.0001396365178579487\n",
-      "0.0001383314515723009\n",
-      "0.00013735419852379168\n",
-      "0.00013624883128071137\n",
-      "0.0001348271413493323\n",
-      "0.0001340181343812743\n",
-      "0.00013327402210206197\n",
-      "0.00013232118285356898\n",
-      "Wrote resulting mesh to Data/901-diffeo-registered.vtk\n"
+      "0.4987491488238776\n",
+      "0.4957951476333167\n",
+      "0.4941950264434974\n",
+      "0.4930808966130274\n",
+      "0.49244047805993507\n",
+      "0.4914935131356182\n",
+      "0.49018818252226226\n",
+      "0.48846731263850734\n",
+      "0.4865865765164624\n",
+      "0.4845592439304183\n",
+      "0.4825032200711701\n",
+      "0.4805217333057509\n",
+      "0.4784276470217681\n",
+      "0.4763028060774365\n",
+      "0.47410199155061833\n",
+      "0.47183553547207796\n",
+      "0.46945634655126595\n",
+      "0.4670089080804245\n",
+      "0.46447236777377016\n",
+      "0.4618700059751327\n",
+      "0.4594918977465529\n",
+      "0.45712312522024456\n",
+      "0.45522632305652644\n",
+      "0.4533702021556196\n",
+      "0.4515470716093708\n",
+      "0.4497243459441331\n",
+      "0.4479271184542627\n",
+      "0.44616428966981375\n",
+      "0.4443887288887757\n",
+      "0.4426435844212059\n",
+      "0.4409485711023183\n",
+      "0.43921519289735944\n",
+      "0.4375637934800705\n",
+      "0.4357279227468467\n",
+      "0.43395033416663575\n",
+      "0.4320027254100205\n",
+      "0.42996833652422484\n",
+      "0.4278856395645356\n",
+      "0.42554150404513424\n",
+      "0.42268157967961434\n",
+      "0.4194370314646928\n",
+      "0.416190044045965\n",
+      "0.413215106680567\n",
+      "0.41022460807160394\n",
+      "0.40679013365077954\n",
+      "0.40136523982974737\n",
+      "0.39619486958540806\n",
+      "0.3918454867090814\n",
+      "0.3885642069086108\n",
+      "0.3859829635395982\n",
+      "0.38420734998525724\n",
+      "0.3824922398749512\n",
+      "0.3808243533684074\n",
+      "0.3792322783119815\n",
+      "0.37769436685324037\n",
+      "0.37614423320761986\n",
+      "0.37465856721892843\n",
+      "0.37317942043025565\n",
+      "0.37173445611415457\n",
+      "0.3703302595498651\n",
+      "0.3689379282302292\n",
+      "0.36756501528945\n",
+      "0.3662681626913344\n",
+      "0.3649025930155688\n",
+      "0.3636629384134367\n",
+      "0.3624225829818334\n",
+      "0.3612225414632408\n",
+      "0.3600129359953591\n",
+      "0.358821332766345\n",
+      "0.35760697984806156\n",
+      "0.3564723422079777\n",
+      "0.35526083441533785\n",
+      "0.3540956037215497\n",
+      "0.3529542330333589\n",
+      "0.3518011807706184\n",
+      "0.3506469954771379\n",
+      "0.34951550772967926\n",
+      "0.34836685154236613\n",
+      "0.34726208542408576\n",
+      "0.3461150921719098\n",
+      "0.3450115151074318\n",
+      "0.34387867776203423\n",
+      "0.3427829002237941\n",
+      "0.34159588528544904\n",
+      "0.34049534895886163\n",
+      "0.339319883652176\n",
+      "0.3381237074064673\n",
+      "0.33692673081498437\n",
+      "0.3357182399223731\n",
+      "0.33447541281190485\n",
+      "0.3333169807038707\n",
+      "0.3321110742045158\n",
+      "0.3310046027852733\n",
+      "0.3297994310491736\n",
+      "0.32866196734302155\n",
+      "0.32747743130963736\n",
+      "0.3263662750901496\n",
+      "0.32518733319138443\n",
+      "0.32403678354626736\n",
+      "0.3228631243435983\n",
+      "0.3217567838669631\n",
+      "0.32054955798163853\n",
+      "0.3194417693214185\n",
+      "0.31826942842628303\n",
+      "0.31712795164292296\n",
+      "0.3159773350655486\n",
+      "0.31485213860853983\n",
+      "0.3136337808062086\n",
+      "0.31243546848220494\n",
+      "0.3110141143483775\n",
+      "0.3096977265137115\n",
+      "0.3081526366486918\n",
+      "0.30661649967918714\n",
+      "0.30506789230248627\n",
+      "0.3036707669495677\n",
+      "0.30226442453195507\n",
+      "0.30091498063124306\n",
+      "0.2995229470241441\n",
+      "0.298207765718706\n",
+      "0.29684544453427564\n",
+      "0.2954751271373304\n",
+      "0.2940798915073158\n",
+      "0.2927474316876174\n",
+      "0.29128223235146217\n",
+      "0.2899054353538183\n",
+      "0.288356024298714\n",
+      "0.28688806551974316\n",
+      "0.2851986920059592\n",
+      "0.28354859206042576\n",
+      "0.2817644710774674\n",
+      "0.28001398778145564\n",
+      "0.27796618682734303\n",
+      "0.2757928570009418\n",
+      "0.2739154531726392\n",
+      "0.2724833231609268\n",
+      "0.2712953569200721\n",
+      "0.2702372630451096\n",
+      "0.26911273092286436\n",
+      "0.26813015043930255\n",
+      "0.26704210840774534\n",
+      "0.26605488616342693\n",
+      "0.2650404512923426\n",
+      "0.2640959534682906\n",
+      "0.26307226769741576\n",
+      "0.26213402602208263\n",
+      "0.26115971967874263\n",
+      "0.26019209211168826\n",
+      "0.2592749164311503\n",
+      "0.2583765768535429\n",
+      "0.25740643935926094\n",
+      "0.2565027454676833\n",
+      "0.2555803766273984\n",
+      "0.25471810811448814\n",
+      "0.25376413630220923\n",
+      "0.25293531850697737\n",
+      "0.25196550313177146\n",
+      "0.2511243978028238\n",
+      "0.2502196439296294\n",
+      "0.24937757357970394\n",
+      "0.24851073965472603\n",
+      "0.2476794810813617\n",
+      "0.24681730940779165\n",
+      "0.24600519917490254\n",
+      "0.24515172442651317\n",
+      "0.24437949392802974\n",
+      "0.2434944324903384\n",
+      "0.24271443756458097\n",
+      "0.24189178585630577\n",
+      "0.2410787269367082\n",
+      "0.2402556598626836\n",
+      "0.23945152584001922\n",
+      "0.23862283280043353\n",
+      "0.23784353638101008\n",
+      "0.2369823528740593\n",
+      "0.23617915647484122\n",
+      "0.23529930669889468\n",
+      "0.23451095701435382\n",
+      "0.2336363656848183\n",
+      "0.23281122131121731\n",
+      "0.23190724314746022\n",
+      "0.23108708300649286\n",
+      "0.23021512579611403\n",
+      "0.22938362724976488\n",
+      "0.22843175674792268\n",
+      "0.22752324246516567\n",
+      "0.22649365024990883\n",
+      "0.2255680869168843\n",
+      "0.22450119061031334\n",
+      "0.22339800725381626\n",
+      "0.2223607798002034\n",
+      "0.2213762474506999\n",
+      "0.2203950049149954\n",
+      "0.21942923162826636\n",
+      "0.218426726670571\n",
+      "0.21753983413196015\n",
+      "0.2165298650047025\n",
+      "0.2156391627615854\n",
+      "0.21464016159847604\n",
+      "0.2137084751624949\n",
+      "0.21278616687598945\n",
+      "Wrote resulting mesh to Output/901-diffeo-registered.obj\n"
      ]
     }
    ],
@@ -1015,30 +1000,33 @@
     "\n",
     "registrar.filter.AddObserver(itk.IterationEvent(),update_diff_progress)\n",
     "\n",
-    "diffeo_mesh_result = registrar.register(fixed_mesh,moving_mesh,filepath=DIFFEO_OUTPUT_FILE,verbose=True)"
+    "(transform, mesh_result) = registrar.register(template_mesh,\n",
+    "                                        target_mesh,\n",
+    "                                        filepath=DIFFEO_OUTPUT_FILE,\n",
+    "                                        verbose=True)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Compare translated image to target image."
+    "Compare the translated image to the target image."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 37,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "048f1a7e14914b508a81f2ba91ebd808",
+       "model_id": "87d8607d300a4122a7793d728765e443",
        "version_major": 2,
        "version_minor": 0
       },
       "text/plain": [
-       "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'numberOfComponents': 3, 'd…"
+       "AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
       ]
      },
      "metadata": {},
@@ -1046,32 +1034,439 @@
     }
    ],
    "source": [
-    "view(geometries=[diffeo_mesh_result,moving_mesh])"
+    "#view(geometries=[mesh_result, target_mesh])\n",
+    "result_image = registrar.mesh_to_image(mesh_result, target_image)\n",
+    "compare(result_image, target_image)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Comparison of the resulting mesh with the output file shows congruency."
+    "# Entropy-based Registration\n",
+    "\n",
+    "The `PointSetEntropyRegistrar` class registers two 3D meshes by converting them to point clouds and computing the transform which minimizes entropy measures between the two clouds. In this example we substitute a [`EuclideanDistancePointSetToPointSetMetric`](https://itk.org/Doxygen/html/classitk_1_1EuclideanDistancePointSetToPointSetMetricv4.html) to compare the two clouds."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from src.hasi.hasi.pointsetentropyregistrar import PointSetEntropyRegistrar\n",
+    "registrar = PointSetEntropyRegistrar()"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "624dbd34cd76445ea4e22b44c4f1a456",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "HBox(children=(Label(value='Register images'), FloatProgress(value=0.0, max=2000.0)))"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "progress = FloatProgress(\n",
+    "        min=0.0,\n",
+    "        max=2000.0,\n",
+    "        step=1\n",
+    "    )\n",
+    "progressBox = HBox([\n",
+    "    Label('Register images'),\n",
+    "    progress\n",
+    "])\n",
+    "progressBox"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def update_progress():\n",
+    "    progressBox.value = registrar.optimizer.GetCurrentIteration()\n",
+    "\n",
+    "registrar.optimizer.AddObserver(itk.IterationEvent(),update_progress)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
    "metadata": {
-    "scrolled": false
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0 0.0\n",
+      "0 0.2931251218908875\n",
+      "1 0.1205193122124783\n",
+      "2 0.10441760162035982\n",
+      "3 0.09834692909340771\n",
+      "4 0.09362681805832306\n",
+      "5 0.08661904369141127\n",
+      "6 0.08230682202306248\n",
+      "7 0.07942040892548036\n",
+      "8 0.07747047345196857\n",
+      "9 0.0759834773217011\n",
+      "10 0.07431930257841414\n",
+      "11 0.07352427455528829\n",
+      "12 0.07292767471290339\n",
+      "13 0.07255832119738176\n",
+      "14 0.07227852401408703\n",
+      "15 0.07203357375770734\n",
+      "16 0.07162628370337433\n",
+      "17 0.07124927954132765\n",
+      "18 0.0705768147400119\n",
+      "19 0.0704106434338947\n",
+      "20 0.06978295403744568\n",
+      "21 0.06845888597949865\n",
+      "22 0.06800386975512246\n",
+      "23 0.06762741927421313\n",
+      "24 0.06650859049205682\n",
+      "25 0.06529362447371807\n",
+      "26 0.06446744560528696\n",
+      "27 0.06344765417959368\n",
+      "28 0.06251106364577003\n",
+      "29 0.06184677765942656\n",
+      "30 0.06141954778967147\n",
+      "31 0.06111198557453498\n",
+      "32 0.060795775352791286\n",
+      "33 0.05943190314826571\n",
+      "34 0.05757744627271415\n",
+      "35 0.05647908427828097\n",
+      "36 0.05568996446341291\n",
+      "37 0.05512690087778857\n",
+      "38 0.05469473397314897\n",
+      "39 0.054158985845869395\n",
+      "40 0.05380578359136856\n",
+      "41 0.05358108151555352\n",
+      "42 0.05340742678577612\n",
+      "43 0.053274219705111585\n",
+      "44 0.05316793610042692\n",
+      "45 0.05308269496699931\n",
+      "46 0.05301371296526918\n",
+      "47 0.05295769015159573\n",
+      "48 0.0529121345150996\n",
+      "49 0.05287507960334685\n",
+      "50 0.05284494823028165\n",
+      "51 0.05282046027361302\n",
+      "52 0.05280061582988251\n",
+      "53 0.05278457857619163\n",
+      "54 0.05277166385997287\n",
+      "55 0.05276132114617358\n",
+      "56 0.05275307827835525\n",
+      "57 0.05274655488840919\n",
+      "58 0.05274144717475178\n",
+      "59 0.052737497213453534\n",
+      "60 0.05273447201870906\n",
+      "61 0.05273224044711649\n",
+      "62 0.05273061494223988\n",
+      "63 0.05272949371275422\n",
+      "64 0.052728767705602066\n",
+      "65 0.05272837898947649\n",
+      "66 0.05272822080967346\n",
+      "67 0.052728291185365574\n",
+      "68 0.05272849244477658\n",
+      "69 0.05272884149826209\n",
+      "70 0.05272924503522783\n",
+      "71 0.0527297175020867\n",
+      "72 0.05273025912401193\n",
+      "73 0.052730807448687404\n",
+      "74 0.052731375787616594\n",
+      "75 0.052731932903368264\n",
+      "76 0.052732523538547495\n",
+      "77 0.0527330787592742\n",
+      "78 0.0527336356076873\n",
+      "79 0.05273415794536505\n",
+      "80 0.05273466459812528\n",
+      "81 0.05273515909297957\n",
+      "82 0.052735634767808064\n",
+      "83 0.05273607163852323\n",
+      "84 0.052736496588077955\n",
+      "85 0.05273688239070174\n",
+      "86 0.052737266818168704\n",
+      "87 0.0527376298109385\n",
+      "88 0.052737951133744104\n",
+      "89 0.05273826361721223\n",
+      "90 0.05273855161763792\n",
+      "91 0.05273882969467878\n",
+      "92 0.05273908075119218\n",
+      "93 0.052739320395205076\n",
+      "94 0.05273954458718973\n",
+      "95 0.05273975022628204\n",
+      "96 0.052739941443882256\n",
+      "97 0.052740114589799485\n",
+      "98 0.052740283941511486\n",
+      "99 0.05274043358570974\n",
+      "100 0.052740585240879\n",
+      "101 0.05274070567712676\n",
+      "102 0.05274084690726144\n",
+      "103 0.05274094874393182\n",
+      "104 0.05274105141552365\n",
+      "105 0.05274116019775044\n",
+      "106 0.05274125517502859\n",
+      "107 0.0527413192206977\n",
+      "108 0.052741398395078236\n",
+      "109 0.052741484019815106\n",
+      "110 0.05274154090852617\n",
+      "111 0.05274160095831286\n",
+      "112 0.05274165179506828\n",
+      "113 0.05274173058971765\n",
+      "114 0.052741768603165484\n",
+      "115 0.05274180598002177\n",
+      "116 0.05274185425374165\n",
+      "117 0.052741873805947276\n",
+      "118 0.052741926831163195\n",
+      "119 0.05274195808392817\n",
+      "120 0.05274197929420086\n",
+      "121 0.05274200672702676\n",
+      "122 0.05274204567004888\n",
+      "123 0.05274205658019399\n",
+      "124 0.052742092121048675\n",
+      "125 0.052742091939980654\n",
+      "126 0.05274212183922304\n",
+      "127 0.052742139149334274\n",
+      "128 0.05274216362208958\n",
+      "129 0.052742180981508874\n",
+      "130 0.052742176094182795\n",
+      "131 0.05274219411727387\n",
+      "132 0.052742202644710974\n",
+      "133 0.052742207610178164\n",
+      "134 0.05274221801550874\n",
+      "135 0.0527422286462341\n",
+      "136 0.05274224618725576\n",
+      "137 0.05274225297089381\n",
+      "138 0.052742260949388144\n",
+      "139 0.05274227197567831\n",
+      "140 0.05274225355129414\n",
+      "141 0.05274227386957239\n",
+      "142 0.05274227915404861\n",
+      "143 0.05274230303373635\n",
+      "144 0.05274229126281105\n",
+      "145 0.0527422993784419\n",
+      "146 0.052742294384862845\n",
+      "147 0.052742301883444864\n",
+      "148 0.05274230200475095\n",
+      "149 0.05274230588701192\n",
+      "150 0.05274231022266607\n",
+      "151 0.052742309131850275\n",
+      "152 0.05274231121814625\n",
+      "153 0.05274232429489601\n",
+      "154 0.052742312287331235\n",
+      "155 0.05274233571296356\n",
+      "156 0.052742331213004826\n",
+      "157 0.05274233059275258\n",
+      "158 0.05274232778125185\n",
+      "159 0.05274233595388499\n",
+      "160 0.052742335816203995\n",
+      "161 0.0527423441035348\n",
+      "162 0.05274233842687464\n",
+      "163 0.052742343215361066\n",
+      "164 0.0527423431972534\n",
+      "165 0.05274234453768913\n",
+      "166 0.05274234235693176\n",
+      "167 0.05274235273217884\n",
+      "168 0.05274234540753572\n",
+      "169 0.052742357099618456\n",
+      "170 0.052742338375806115\n",
+      "171 0.052742347057393335\n",
+      "172 0.052742343918950135\n",
+      "173 0.0527423477880042\n",
+      "174 0.052742343507648344\n",
+      "175 0.052742347380754714\n",
+      "176 0.05274234160543774\n",
+      "177 0.05274234117154455\n",
+      "178 0.05274234116086449\n",
+      "179 0.05274234331625404\n",
+      "180 0.05274234750583038\n",
+      "181 0.05274234181112226\n",
+      "182 0.05274233993177177\n",
+      "183 0.052742341849855844\n",
+      "184 0.05274234426768576\n",
+      "185 0.05274234922136469\n",
+      "186 0.05274234126055728\n",
+      "187 0.05274234378386527\n",
+      "188 0.05274234455236668\n",
+      "189 0.052742338036802415\n",
+      "190 0.052742343156904174\n",
+      "191 0.05274234293780223\n",
+      "192 0.05274234157828768\n",
+      "193 0.052742345232774816\n",
+      "194 0.052742340837267476\n",
+      "195 0.05274233830651495\n",
+      "196 0.052742340000303915\n",
+      "197 0.052742343701568266\n",
+      "198 0.05274234226838548\n",
+      "199 0.052742337528801995\n",
+      "200 0.05274234637609923\n",
+      "201 0.052742337665423696\n",
+      "202 0.052742341830638285\n",
+      "203 0.052742341442251144\n",
+      "204 0.052742342742916996\n",
+      "205 0.05274234058736223\n",
+      "206 0.052742345537670314\n",
+      "207 0.052742342023070064\n",
+      "208 0.05274234508497935\n",
+      "209 0.05274234043729464\n",
+      "210 0.05274234544417954\n",
+      "211 0.05274233922658734\n",
+      "212 0.05274234327486648\n",
+      "213 0.052742343824586896\n",
+      "214 0.052742343897385746\n",
+      "215 0.05274234450003634\n",
+      "216 0.05274234112212517\n",
+      "217 0.05274234729265143\n",
+      "218 0.052742340764239774\n",
+      "219 0.0527423458736388\n",
+      "220 0.05274234121444444\n",
+      "221 0.05274234689045353\n",
+      "222 0.05274233724865935\n",
+      "223 0.05274234405692857\n",
+      "224 0.05274234323510927\n",
+      "225 0.052742337383331804\n",
+      "226 0.05274234450899358\n",
+      "227 0.052742340038661274\n",
+      "228 0.052742348057924986\n",
+      "229 0.05274235128044098\n",
+      "230 0.05274234810430444\n",
+      "231 0.052742346344961354\n",
+      "232 0.052742341927351805\n",
+      "233 0.052742339543704435\n",
+      "234 0.05274234282676995\n",
+      "235 0.05274234229805968\n",
+      "236 0.05274234604558192\n",
+      "237 0.05274234274056611\n",
+      "238 0.05274234603105472\n",
+      "239 0.05274234806249414\n",
+      "240 0.052742342940694596\n",
+      "241 0.05274234915542901\n",
+      "242 0.052742345803625086\n",
+      "243 0.052742341226866\n",
+      "244 0.05274234063740233\n",
+      "245 0.05274234369008943\n",
+      "246 0.05274233997190216\n",
+      "247 0.05274234390974684\n",
+      "248 0.05274233997190216\n",
+      "249 0.05274234372194166\n",
+      "250 0.05274234584418733\n",
+      "251 0.052742336387582196\n",
+      "252 0.05274235078115932\n",
+      "253 0.0527423451620078\n",
+      "254 0.052742350111788294\n",
+      "255 0.05274234456555411\n",
+      "256 0.05274234593187958\n",
+      "257 0.05274234171692656\n",
+      "258 0.05274234390974684\n",
+      "259 0.05274234018784621\n",
+      "260 0.05274234227907049\n",
+      "261 0.05274234269418666\n",
+      "262 0.052742347649850356\n",
+      "263 0.05274234382186085\n",
+      "264 0.052742339925522685\n",
+      "265 0.05274234188984253\n",
+      "266 0.05274234022013571\n",
+      "267 0.052742343329676505\n",
+      "268 0.05274234419260207\n",
+      "269 0.052742351481819834\n",
+      "270 0.05274234560394798\n",
+      "271 0.05274234972873246\n",
+      "272 0.05274234531055047\n",
+      "273 0.052742349902010495\n",
+      "274 0.052742345570466316\n",
+      "275 0.0527423400338148\n",
+      "276 0.052742347984263444\n",
+      "277 0.05274233940392921\n",
+      "278 0.05274234511596236\n",
+      "279 0.05274233697446629\n",
+      "280 0.052742346877235495\n",
+      "281 0.05274233827292008\n",
+      "282 0.05274234545725356\n",
+      "283 0.05274233852533043\n",
+      "284 0.052742345023203414\n",
+      "285 0.052742336701176014\n",
+      "286 0.052742346784476556\n",
+      "287 0.05274234933171637\n",
+      "288 0.05274233857108266\n",
+      "289 0.05274234319053816\n",
+      "290 0.05274234039978051\n",
+      "291 0.052742343309296884\n",
+      "292 0.05274233958444759\n",
+      "293 0.052742342218163825\n",
+      "294 0.0527423409427445\n",
+      "295 0.052742343767199024\n",
+      "296 0.05274234154077924\n",
+      "297 0.052742345637925014\n",
+      "298 0.05274234848046711\n",
+      "299 0.05274233930343473\n",
+      "300 0.05272822080967346\n",
+      "Number of iterations run: 300\n",
+      "Final metric value: 0.05272822080967346\n",
+      "Final transform position: [1.0118122397637432, -0.010979135992226182, 0.05646173791448229, -0.13940911619381488, 1.0163370989730969, 0.004275247238397029, 0.0022400175276892477, 0.004073478276784635, 1.0055512768178145, 0.042664268054068026, -0.23443978381427807, 0.04475721183486951]\n",
+      "Optimizer scales: [11.939408484311615, 3.394054567442619, 1.4326127243659748, 11.939408484311615, 3.394054567442619, 1.4326127243659748, 11.93940848431163, 3.394054567442619, 1.4326127243659748, 1.0000000000000018, 1.0000000000000018, 1.0000000000000018]\n",
+      "Optimizer learning rate: 1.0\n",
+      "Wrote resulting point set to Output/901-pointset-registered.obj\n"
+     ]
+    }
+   ],
+   "source": [
+    "metric = itk.EuclideanDistancePointSetToPointSetMetricv4[itk.PointSet[itk.F,3]].New()\n",
+    "\n",
+    "(transform, mesh_result) = registrar.register(\n",
+    "                       template_mesh=template_mesh,\n",
+    "                       target_mesh=target_mesh,\n",
+    "                       metric=metric,\n",
+    "                       filepath=POINTSET_OUTPUT_FILE,\n",
+    "                       resample_rate=0.005,\n",
+    "                       verbose=True,\n",
+    "                       learning_rate=1.0,\n",
+    "                       max_iterations=300,\n",
+    "                       resample_from_target=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {
+    "scrolled": true
    },
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "a6b99e27bc9e4b4d90333cb3f9fe5f99",
+       "model_id": "0655152871164adfac83e7b804f23ec8",
        "version_major": 2,
        "version_minor": 0
       },
       "text/plain": [
-       "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'numberOfComponents': 3, 'd…"
+       "AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
       ]
      },
      "metadata": {},
@@ -1079,33 +1474,70 @@
     }
    ],
    "source": [
-    "file_mesh_result = itk.meshread(DIFFEO_OUTPUT_FILE, itk.F)\n",
-    "view(geometries=[file_mesh_result,diffeo_mesh_result])"
+    "compare(registrar.mesh_to_image(mesh_result),registrar.mesh_to_image(target_mesh))"
    ]
   },
   {
-   "cell_type": "markdown",
-   "metadata": {},
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
    "source": [
-    "### Clean up example files"
+    "template_resampled = \\\n",
+    "    registrar.resample_template_from_target(mesh_result, target_mesh)\n",
+    "\n",
+    "itk.meshwrite(template_resampled,'Output/pointset-resampled.obj')"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
-   "metadata": {},
+   "execution_count": 36,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "07d460ff5ece4801ba0b4265c60551b7",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "#view(geometries=[target_mesh,mesh_result,template_resampled])\n",
+    "compare(registrar.mesh_to_image(template_resampled),registrar.mesh_to_image(target_mesh))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": true
+   },
    "outputs": [],
    "source": [
+    "# Clean up file output\n",
     "os.remove(MEANSQUARES_OUTPUT_FILE)\n",
-    "os.remove(DIFFEO_OUTPUT_FILE)"
+    "os.remove(DIFFEO_OUTPUT_FILE)\n",
+    "os.remove(POINTSET_OUTPUT_FILE)"
    ]
   }
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 3",
+   "display_name": "venv-itk4",
    "language": "python",
-   "name": "python3"
+   "name": "venv-itk4"
   },
   "language_info": {
    "codemirror_mode": {
diff --git a/examples/TemplateGenerationIterative.ipynb b/examples/TemplateGenerationIterative.ipynb
new file mode 100644
index 0000000..d0e5634
--- /dev/null
+++ b/examples/TemplateGenerationIterative.ipynb
@@ -0,0 +1,1042 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Iterative Template Generation\n",
+    "\n",
+    "This notebook exemplifies one way in which a template mesh atlas can be generated from a collection of segmented binary images. Each binary image of a mouse femur is downsampled to reduce pixel density prior to applying marching cubes to generate a mesh from the binary image. One arbitrary mesh is selected as the template and then registered to and resampled from each original mesh to get a full set of meshes with correspondence points. The meshes are then groupwise registered via procrustes alignment and the mean mesh is taken as the new template. This process is repeated for a fixed number of iterations to get a template mesh atlas that represents the average case of all meshes."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import os\n",
+    "import glob\n",
+    "\n",
+    "import numpy as np\n",
+    "import itk\n",
+    "import sys\n",
+    "from itkwidgets import view, checkerboard\n",
+    "\n",
+    "module_path = os.path.abspath(os.path.join('..'))\n",
+    "\n",
+    "if module_path not in sys.path:\n",
+    "    sys.path.append(module_path)\n",
+    "\n",
+    "from src.hasi.hasi.pointsetentropyregistrar import PointSetEntropyRegistrar"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Read images\n",
+    "\n",
+    "Input images represent the results of automatic binary segmentations of mouse femur data. Each image contains only the femur object and represents a different possible region in space."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# TODO download femurs if not locally available\n",
+    "IMAGE_FOLDER = 'Input/femurs/'\n",
+    "MESH_OUTPUT_FOLDER = 'Output/femurs/'\n",
+    "MEAN_OUTPUT_FOLDER = 'Output/mean/'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "for folder in [IMAGE_FOLDER, MESH_OUTPUT_FOLDER, MEAN_OUTPUT_FOLDER]:\n",
+    "    os.makedirs(folder, exist_ok=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "input_paths = glob.glob(IMAGE_FOLDER + '*')\n",
+    "assert(len(input_paths) == 28)\n",
+    "\n",
+    "# FIXME remove 901-R for now because it is misaligned\n",
+    "del input_paths[1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "MESH_FILENAMES = [os.path.basename(file).replace('.nrrd','.obj') for file in input_paths]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "images = list()\n",
+    "\n",
+    "for path in input_paths:\n",
+    "    images.append(itk.imread(path, itk.UC))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Paste images into same space\n",
+    "For viewing convenience."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Verify image spacing is equivalent\n",
+    "TOLERANCE = 0.0000001\n",
+    "assert(all([itk.spacing(images[i])[j] - itk.spacing(images[i+1])[j] < TOLERANCE\n",
+    "            for j in range(0,images[0].GetImageDimension())\n",
+    "            for i in range(0,len(images) - 1)]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "itkSize3 ([1392, 983, 1247])\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Get largest range containing images\n",
+    "max_size = itk.size(images[0])\n",
+    "for image in images:\n",
+    "    for i in range(0,len(max_size)):\n",
+    "        max_size[i] = max(max_size[i], itk.size(image)[i])\n",
+    "print(max_size)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Make image of common size\n",
+    "def paste_common_size(orig_image, size, spacing):\n",
+    "    dimension = orig_image.GetImageDimension()\n",
+    "    region = itk.ImageRegion[dimension]()\n",
+    "    region.SetSize(size)\n",
+    "    region.SetIndex([0] * dimension)\n",
+    "\n",
+    "    new_image = type(orig_image).New()\n",
+    "    new_image.SetRegions(region)\n",
+    "    new_image.SetSpacing(spacing)\n",
+    "    new_image.Allocate()\n",
+    "    \n",
+    "    filter = itk.PasteImageFilter[type(orig_image)].New()\n",
+    "    filter.SetSourceImage(orig_image)\n",
+    "    filter.SetSourceRegion(orig_image.GetLargestPossibleRegion())\n",
+    "    filter.SetDestinationImage(new_image)\n",
+    "    filter.SetDestinationIndex([0,0,0])\n",
+    "    filter.Update()\n",
+    "    \n",
+    "    return filter.GetOutput()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Make images common size\n",
+    "for i in range(0, len(images)):\n",
+    "    images[i] = paste_common_size(images[i], max_size, images[0].GetSpacing())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "ee821e422e2746df91da3d8c03bcb11f",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Viewer(geometries=[], gradient_opacity=0.22, point_sets=[], rendered_image=<itk.itkImagePython.itkImageUC3; pr…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "view(images[1])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Downsample images\n",
+    "The marching cubes algorithm returns a mesh with vertex density related to the pixel density of the original image. In this case marching cubes on the default images would produce meshes of approximately 800,000 points each, but the template mesh atlas is desired to contain only approximately 5,000 points. Each image is downsampled in order to yield a less dense mesh output."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "DOWNSAMPLE_RATIO = 14"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "downsampled_images = list()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "for image in images:\n",
+    "    output_spacing = [spacing * DOWNSAMPLE_RATIO for spacing in itk.spacing(image)]\n",
+    "    output_size = [int(size / DOWNSAMPLE_RATIO) for size in itk.size(image)]\n",
+    "\n",
+    "    downsample = itk.resample_image_filter(Input=image,\n",
+    "                                           Size=output_size,\n",
+    "                                           OutputOrigin=itk.origin(image),\n",
+    "                                           OutputSpacing=output_spacing,)\n",
+    "    downsampled_images.append(downsample)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "271e62f8d21146f2acc8818f912bb61e",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Viewer(geometries=[], gradient_opacity=0.22, point_sets=[], rendered_image=<itk.itkImagePython.itkImageUC3; pr…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "view(downsample)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Generate Meshes\n",
+    "The `itk.BinaryMask3DMeshSource` class makes use of the Marching Cubes algorithm to generate a mesh from a given object. Each binary image here uses the value '1' to indicate the femur is present at a pixel and '0' to indicate the femur is not present. Marching Cubes rapidly fills the femur space and generates surfaces at pixel region boundaries."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "FEMUR_OBJECT_PIXEL_VALUE = 1\n",
+    "\n",
+    "Dimension = itk.template(downsampled_images[0])[1][1]\n",
+    "MeshType = itk.Mesh[itk.F,Dimension]\n",
+    "MeshSourceType = itk.BinaryMask3DMeshSource[type(downsampled_images[0]), MeshType]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Average mesh points: 4822.518518518518\n"
+     ]
+    }
+   ],
+   "source": [
+    "meshes = list()\n",
+    "\n",
+    "for image in downsampled_images:\n",
+    "    mesh_source = MeshSourceType.New()\n",
+    "    mesh_source.SetObjectValue(FEMUR_OBJECT_PIXEL_VALUE)\n",
+    "    mesh_source.SetInput(image)\n",
+    "    mesh_source.Update()\n",
+    "    \n",
+    "    mesh_output = mesh_source.GetOutput()\n",
+    "    meshes.append(mesh_output)\n",
+    "    \n",
+    "print('Average mesh points: ' +\n",
+    "      str(sum([mesh.GetNumberOfPoints() for mesh in meshes]) / len(meshes)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Write out each mesh to disk\n",
+    "for i in range(0,len(meshes)):\n",
+    "    itk.meshwrite(meshes[i], f'{MESH_OUTPUT_FOLDER}{MESH_FILENAMES[i]}')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# TODO visualize with itkwidgets\n",
+    "# view(geometries=meshes)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Select Template Mesh\n",
+    "It is now necessary to select a mesh that will act as the 'standard' for correspondence point updates from this point forward. The first mesh in the list is arbitrarily selected as this standard template."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "TEMPLATE_MESH_INDEX = 0\n",
+    "template_mesh = meshes[TEMPLATE_MESH_INDEX]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# FIXME visualize template\n",
+    "# view(geometries=[template_mesh])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Define Iterative Registration\n",
+    "It is desired to find correspondence points between the template and each sample mesh. In order to get correspondence, two steps are employed:\n",
+    "- First, a copy of the template mesh is registered to the target sample;\n",
+    "- Second, each mesh point is updated to its nearest neighbor on the target sample.\n",
+    "\n",
+    "The result of this process is a full collection of meshes having the same number of points and correspondence between each point such that it represents the same approximate feature on each femur."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "#FIXME set mesh1 to better inital transform for registration\n",
+    "#transform = itk.Euler3DTransform[itk.D].New()\n",
+    "#params = transform.GetParameters()\n",
+    "#params.SetElement(0,3.14)\n",
+    "#params.SetElement(1,3.14)\n",
+    "#params.SetElement(2,3.14 / 2)\n",
+    "#transform.SetParameters(params)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "def register_template_to_sample(template_mesh, \n",
+    "                                sample_mesh,\n",
+    "                                learning_rate=1.0,\n",
+    "                                max_iterations=2000):\n",
+    "    \n",
+    "    registrar = PointSetEntropyRegistrar()\n",
+    "    metric = itk.EuclideanDistancePointSetToPointSetMetricv4[itk.PointSet[itk.F,3]].New()\n",
+    "    transform = itk.Euler3DTransform[itk.D].New()\n",
+    "    \n",
+    "    # Make a deep copy of the template point set to resample from the target\n",
+    "    template_copy = itk.Mesh[itk.F,3].New()\n",
+    "    for i in range(0, template_mesh.GetNumberOfPoints()):\n",
+    "        template_copy.SetPoint(i, template_mesh.GetPoint(i))\n",
+    "    template_copy.SetCells(template_mesh.GetCells())\n",
+    "    \n",
+    "    # Run registration and resample from target\n",
+    "    (transform, deformed_mesh) = registrar.register(template_mesh=template_copy,\n",
+    "                                                    target_mesh=sample_mesh,\n",
+    "                                                    metric=metric,\n",
+    "                                                    transform=transform,\n",
+    "                                                    learning_rate=learning_rate,\n",
+    "                                                    max_iterations=max_iterations,\n",
+    "                                                    resample_from_target=True,\n",
+    "                                                    verbose=False)\n",
+    "    return deformed_mesh"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Define Procrustes Alignment Parameters\n",
+    "Now that template meshes have been aligned to represent each input mesh with correspondence, run Procrustes alignment and get out a mean mesh as the new template."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def align_procrustes(deformed_meshes, \n",
+    "                     template_index, \n",
+    "                     verbose=False,\n",
+    "                     convergence=0.08):\n",
+    "    \n",
+    "    procrustes_filter = itk.MeshProcrustesAlignFilter[type(deformed_meshes[0]), type(deformed_meshes[0])].New()\n",
+    "    \n",
+    "    procrustes_filter.SetUseInitialAverageOff()\n",
+    "    procrustes_filter.SetUseNormalizationOff()\n",
+    "    procrustes_filter.SetUseScalingOff()\n",
+    "    procrustes_filter.SetConvergence(convergence)  # Minimum threshold to exit alignment\n",
+    "    \n",
+    "    # Set mesh correspondence inputs\n",
+    "    procrustes_filter.SetNumberOfInputs(len(deformed_meshes))\n",
+    "    for i in range(0, len(deformed_meshes)):\n",
+    "        procrustes_filter.SetInput(i, deformed_meshes[i])\n",
+    "    \n",
+    "    # Run filter\n",
+    "    procrustes_filter.Update()\n",
+    "    \n",
+    "    if(verbose):\n",
+    "        print(f'Alignment converged at {procrustes_filter.GetMeanPointsDifference()}')\n",
+    "    \n",
+    "    mean_result = procrustes_filter.GetMean()\n",
+    "    mean_result.SetCells(deformed_meshes[template_index].GetCells())\n",
+    "    return mean_result"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Run Iterative Refinement\n",
+    "\n",
+    "Run registration and alignment on every mesh, choosing whether to iteratively update meshes to take advantage of mean alignment in each iteration or to ignore previous changes so that each alignment procedure is independent of the order of meshes in the list."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "NUM_ITERATIONS = 1\n",
+    "UPDATE_CONTINUOUSLY = True\n",
+    "aligned_templates = list()\n",
+    "\n",
+    "# Write out mean meshes by iteration\n",
+    "# ex. 'Output/mean/0/901-L-femur-label.obj'\n",
+    "for i in range(0,NUM_ITERATIONS):\n",
+    "    os.makedirs(MEAN_OUTPUT_FOLDER + str(i) + '\\\\', exist_ok=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Now at iteration 0\n",
+      "Now at template mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0013539076418325581\n",
+      "Writing mean to Output/mean//0/901-L-femur-label.obj\n",
+      "Now at template mesh 1\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0021126325521304205\n",
+      "Writing mean to Output/mean//0/902-L-femur-label.obj\n",
+      "Now at template mesh 2\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0013403246222149828\n",
+      "Writing mean to Output/mean//0/902-R-femur-label.obj\n",
+      "Now at template mesh 3\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0010776738666368856\n",
+      "Writing mean to Output/mean//0/906-L-femur-label.obj\n",
+      "Now at template mesh 4\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0009368941564440909\n",
+      "Writing mean to Output/mean//0/906-R-femur-label.obj\n",
+      "Now at template mesh 5\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.01771205656103327\n",
+      "Writing mean to Output/mean//0/907-L-femur-label.obj\n",
+      "Now at template mesh 6\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0015883326966217473\n",
+      "Writing mean to Output/mean//0/907-R-femur-label.obj\n",
+      "Now at template mesh 7\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0019276822157436202\n",
+      "Writing mean to Output/mean//0/908-L-femur-label.obj\n",
+      "Now at template mesh 8\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0008468561680195561\n",
+      "Writing mean to Output/mean//0/908-R-femur-label.obj\n",
+      "Now at template mesh 9\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0014259736570786917\n",
+      "Writing mean to Output/mean//0/915-L-femur-label.obj\n",
+      "Now at template mesh 10\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Running alignment\n",
+      "Alignment converged at 0.0007549640420944888\n",
+      "Writing mean to Output/mean//0/915-R-femur-label.obj\n",
+      "Now at template mesh 11\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0008808021989129835\n",
+      "Writing mean to Output/mean//0/916-L-femur-label.obj\n",
+      "Now at template mesh 12\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 13\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.0004644934773637309\n",
+      "Writing mean to Output/mean//0/916-R-femur-label.obj\n",
+      "Now at template mesh 13\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n",
+      "Resampling from mesh 11\n",
+      "Resampling from mesh 12\n",
+      "Resampling from mesh 14\n",
+      "Resampling from mesh 15\n",
+      "Resampling from mesh 16\n",
+      "Resampling from mesh 17\n",
+      "Resampling from mesh 18\n",
+      "Resampling from mesh 19\n",
+      "Resampling from mesh 20\n",
+      "Resampling from mesh 21\n",
+      "Resampling from mesh 22\n",
+      "Resampling from mesh 23\n",
+      "Resampling from mesh 24\n",
+      "Resampling from mesh 25\n",
+      "Resampling from mesh 26\n",
+      "Running alignment\n",
+      "Alignment converged at 0.003948452450873146\n",
+      "Writing mean to Output/mean//0/917-L-femur-label.obj\n",
+      "Now at template mesh 14\n",
+      "Resampling from mesh 0\n",
+      "Resampling from mesh 1\n",
+      "Resampling from mesh 2\n",
+      "Resampling from mesh 3\n",
+      "Resampling from mesh 4\n",
+      "Resampling from mesh 5\n",
+      "Resampling from mesh 6\n",
+      "Resampling from mesh 7\n",
+      "Resampling from mesh 8\n",
+      "Resampling from mesh 9\n",
+      "Resampling from mesh 10\n"
+     ]
+    },
+    {
+     "ename": "KeyboardInterrupt",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[1;32m<ipython-input-29-28689507c5ee>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     12\u001b[0m             \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m                 \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf'Resampling from mesh {sample_index}'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m                 \u001b[0mdeformed_template\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mregister_template_to_sample\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtemplate_mesh\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmeshes\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0msample_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     15\u001b[0m                 \u001b[0mdeformed_templates\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdeformed_template\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m<ipython-input-23-2a81ba112558>\u001b[0m in \u001b[0;36mregister_template_to_sample\u001b[1;34m(template_mesh, sample_mesh, learning_rate, max_iterations)\u001b[0m\n\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m     \u001b[1;31m# Run registration and resample from target\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 17\u001b[1;33m     (transform, deformed_mesh) = registrar.register(template_mesh=template_copy,\n\u001b[0m\u001b[0;32m     18\u001b[0m                                                     \u001b[0mtarget_mesh\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msample_mesh\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     19\u001b[0m                                                     \u001b[0mmetric\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mmetric\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m~\\source\\repos\\HASI\\src\\hasi\\hasi\\pointsetentropyregistrar.py\u001b[0m in \u001b[0;36mregister\u001b[1;34m(self, template_mesh, template_point_set, target_mesh, target_point_set, filepath, verbose, metric, transform, resample_rate, max_iterations, learning_rate, resample_from_target)\u001b[0m\n\u001b[0;32m    143\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    144\u001b[0m         \u001b[1;32mif\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mresample_from_target\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 145\u001b[1;33m             \u001b[0mregistered_template_mesh\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mresample_template_from_target\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mregistered_template_mesh\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget_mesh\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    146\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    147\u001b[0m         \u001b[1;31m# Write out\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m~\\source\\repos\\HASI\\src\\hasi\\hasi\\meshtomeshregistrar.py\u001b[0m in \u001b[0;36mresample_template_from_target\u001b[1;34m(template_mesh, target_mesh)\u001b[0m\n\u001b[0;32m    119\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    120\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtemplate_mesh\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mGetNumberOfPoints\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 121\u001b[1;33m             \u001b[0mpt\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtemplate_mesh\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mGetPoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    122\u001b[0m             \u001b[0mind\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mloc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mFindClosestPoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpt\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    123\u001b[0m             \u001b[0mwarped_pts\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mSetPoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget_pts\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mGetPoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mind\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
+     ]
+    }
+   ],
+   "source": [
+    "for iteration in range(0,NUM_ITERATIONS):\n",
+    "    print(f'Now at iteration {iteration}')\n",
+    "    \n",
+    "    for template_mesh_index in range(0,len(meshes)):\n",
+    "        print(f'Now at template mesh {template_mesh_index}')\n",
+    "        template_mesh = meshes[template_mesh_index]\n",
+    "\n",
+    "        deformed_templates = list()\n",
+    "        for sample_index in range(0,len(meshes)):\n",
+    "            if sample_index == template_mesh_index:\n",
+    "                deformed_templates.append(template_mesh)\n",
+    "            else:\n",
+    "                print(f'Resampling from mesh {sample_index}')\n",
+    "                deformed_template = register_template_to_sample(template_mesh, meshes[sample_index])\n",
+    "                deformed_templates.append(deformed_template)\n",
+    "\n",
+    "        print('Running alignment')\n",
+    "        mesh_result = align_procrustes(deformed_templates, template_mesh_index, verbose=True)\n",
+    "\n",
+    "        # Save intermediate results to disk\n",
+    "        # These meshes are very small so this is not a significant expense (~400 KB/mesh)\n",
+    "        output_path = f'{MEAN_OUTPUT_FOLDER}/{iteration}/{MESH_FILENAMES[template_mesh_index]}'\n",
+    "        print(f'Writing mean to {output_path}')\n",
+    "        itk.meshwrite(mesh_result, output_path)\n",
+    "        \n",
+    "        # Optionally update current mesh in place for use in subsequent alignments\n",
+    "        if UPDATE_IN_PLACE:\n",
+    "            meshes[template_mesh_index] = mesh_result\n",
+    "        else:\n",
+    "            aligned_templates.append(mesh_result)\n",
+    "    \n",
+    "    # Optionally update templates only between iterations\n",
+    "    if not UPDATE_CONTINUOUSLY:\n",
+    "        meshes = aligned_templates"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# FIXME visualize template\n",
+    "# view(geometries=[meshes])"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python (dev)",
+   "language": "python",
+   "name": "venv-itkdev"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.8"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/requirements.txt b/examples/requirements.txt
index 4a0f9e0..a4e1a01 100644
--- a/examples/requirements.txt
+++ b/examples/requirements.txt
@@ -1,5 +1,4 @@
 itk-hasi
 itkwidgets
 itk-boneenhancement
-itk-elastix
 itk-bonemorphometry
diff --git a/src/hasi/hasi/meansquaresregistrar.py b/src/hasi/hasi/meansquaresregistrar.py
index bb4c23d..1bccc1c 100644
--- a/src/hasi/hasi/meansquaresregistrar.py
+++ b/src/hasi/hasi/meansquaresregistrar.py
@@ -42,9 +42,6 @@ class MeanSquaresRegistrar(MeshToMeshRegistrar):
     SMOOTHING_SIGMAS_PER_LEVEL = [0] * NUMBER_OF_LEVELS
     SHRINK_FACTORS_PER_LEVEL = [1] * Dimension
 
-    # TODO investigate if this is useful
-    LinearInterpolatorType = \
-        itk.LinearInterpolateImageFunction[ImageType, itk.D]
     TransformType = itk.BSplineTransform[itk.D, Dimension, V_SPLINE_ORDER]
     
 
@@ -57,6 +54,7 @@ def initialize(self):
             GradientConvergenceTolerance=self.GRADIENT_CONVERGENCE_TOLERANCE,
             MaximumNumberOfFunctionEvaluations=self.MAX_FUNCTION_EVALUATIONS,
             MaximumNumberOfCorrections=self.MAX_CORRECTIONS)
+        # TODO initialize verbose output with observer
 
 
     # Register two 3D images with an LBFGSB optimizer
@@ -100,6 +98,7 @@ def print_iteration():
             infnorm = self.optimizer.GetInfinityNormOfProjectedGradient()
             print(f'{iteration} {metric} {infnorm}')
 
+        # FIXME adds a duplicate observer if multiple calls without re-initialization
         if(verbose):
             self.optimizer.AddObserver(itk.IterationEvent(),
                                             print_iteration)
@@ -107,6 +106,8 @@ def print_iteration():
         self.optimizer.SetNumberOfIterations(num_iterations)
 
         # Define object to handle image registration
+
+        # TODO use functional interface image_registration_method()
         RegistrationType = \
             itk.ImageRegistrationMethodv4[ImageType,ImageType]
         registration = RegistrationType.New(InitialTransform=transform,
@@ -126,19 +127,15 @@ def print_iteration():
         #     no observed impact on performance from this warning
         registration.Update()
 
-        # TODO functional interface
-        # image_registration_method()
-
         # Report results
         if(verbose):
             print('Solution = ' + str(list(transform.GetParameters())))
-
-        # Update fixed image
-        # TODO try inverting moving transform and compare results
-
+        
+        # Update template
         transformed_mesh = itk.transform_mesh_filter(template_mesh, transform=transform)
 
         # Write out
+        # TODO move away from monolithic design, leave write responsibility to user
         if filepath is not None:
             itk.meshwrite(transformed_mesh, filepath)
             if(verbose):
diff --git a/src/hasi/hasi/meshtomeshregistrar.py b/src/hasi/hasi/meshtomeshregistrar.py
index ba8ac39..c56355b 100644
--- a/src/hasi/hasi/meshtomeshregistrar.py
+++ b/src/hasi/hasi/meshtomeshregistrar.py
@@ -2,14 +2,14 @@
 
 # Filename: MeshToMeshRegistration
 # Contributors: Tom Birdsong
-# Purpose: Python implementation of Slicer SALT mesh-to-mesh registration Cxx
-# CLI.
-#    Ported from https://github.com/slicersalt/RegistrationBasedCorrespondence/
+# Purpose: Base Python class for implementations of mesh-to-mesh registration algorithms.
+#   Initially ported from https://github.com/slicersalt/RegistrationBasedCorrespondence/
 import logging
 import os
+import random
 
 import itk
-
+import numpy as np
 
 class MeshToMeshRegistrar:
     # Common definitions
@@ -26,6 +26,7 @@ class MeshToMeshRegistrar:
     FixedPointSetType = itk.PointSet[itk.F, Dimension]
 
     MeshType = itk.Mesh[itk.F, Dimension]
+    PointSetType = itk.PointSet[itk.F, Dimension]
 
     def __init__(self):
         self.initialize()
@@ -91,3 +92,56 @@ def mesh_to_image(self, meshes:list, reference_image:ImageType=None) -> ImageTyp
             images.append(distance.GetOutput())
 
         return images[0] if len(images) == 1 else images
+
+    # Randomly sample mesh to get a reduced point set
+    # This may not be suitable for low-density meshes
+    def randomly_sample_mesh_points(self, mesh:MeshType, sampling_rate:float=1.0) -> PointSetType:
+        if(sampling_rate > 1.0):
+            raise ValueError('Cannot resample with a rate greater than 1.0!')
+        
+        selected_points = set()
+        num_source_points = mesh.GetNumberOfPoints()
+        resampled_set = self.PointSetType.New()
+
+        while resampled_set.GetNumberOfPoints() < sampling_rate * num_source_points:
+            point_index = random.randrange(0, num_source_points)
+            while(point_index in selected_points):
+                point_index = random.randrange(0, num_source_points)
+            selected_points.add(point_index)
+
+            resampled_set.SetPoint(
+                resampled_set.GetNumberOfPoints(),
+                mesh.GetPoint(point_index))
+
+        return resampled_set
+    
+    @staticmethod
+    def resample_template_from_target(template_mesh:MeshType, target_mesh:MeshType) -> MeshType:
+        # Set samples from target mesh points
+        measurement = itk.Vector[itk.F,3]()
+        sample = itk.ListSample[type(measurement)].New()
+
+        # Use available wrapping for itk.VectorContainer
+        if (itk.ULL, itk.ULL) in itk.VectorContainer.keys():
+            neighbors = itk.VectorContainer[itk.ULL, itk.ULL].New()
+        else:
+            neighbors = itk.VectorContainer[itk.UL, itk.UL].New()
+
+        sample.Resize(target_mesh.GetNumberOfPoints())
+        for i in range(0, target_mesh.GetNumberOfPoints()):
+            measurement.SetVnlVector(target_mesh.GetPoint(i).GetVnlVector())
+            sample.SetMeasurementVector(i, measurement)
+
+        # Build kd-tree
+        tree_generator = itk.KdTreeGenerator[type(sample)].New(Sample=sample, BucketSize=16)
+        tree_generator.Update()
+
+        # Iteratively update template points to nearest neighbor in target point set
+        tree = tree_generator.GetOutput()
+
+        for i in range(0, template_mesh.GetNumberOfPoints()):
+            measurement.SetVnlVector(template_mesh.GetPoint(i).GetVnlVector())
+            tree.Search(measurement, 1, neighbors)
+            template_mesh.SetPoint(i, target_mesh.GetPoint(neighbors.GetElement(0)))
+
+        return template_mesh
diff --git a/src/hasi/hasi/pointsetentropyregistrar.py b/src/hasi/hasi/pointsetentropyregistrar.py
new file mode 100644
index 0000000..2d33f3c
--- /dev/null
+++ b/src/hasi/hasi/pointsetentropyregistrar.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+
+# Filename:     pointsetentropyregistrar.py
+# Contributors: Tom Birdsong
+# Purpose:  Python implementation of mesh-to-mesh registration
+#     using point set entropy-based registration
+# Referenced https://github.com/InsightSoftwareConsortium/ITKTrimmedPointSetRegistration/blob/master/examples/TrimmedPointSetRegistrationExample.cxx
+#     for development purposes
+
+import logging
+import os
+import pytest
+
+import itk
+from .meshtomeshregistrar import MeshToMeshRegistrar
+
+class PointSetEntropyRegistrar(MeshToMeshRegistrar):
+    # Common definitions
+    MAX_ITERATIONS = 200
+
+    Dimension = 3
+    PixelType = itk.F
+    ImageType = itk.Image[PixelType, Dimension]
+    TemplateImageType = ImageType
+    TargetImageType = ImageType
+
+    MeshType = itk.Mesh[itk.F, Dimension]
+
+    # Class definitions
+    PointSetType = itk.PointSet[itk.F,Dimension]
+    TransformType = itk.AffineTransform[itk.D, Dimension]
+
+    def __init__(self):
+        super(self.__class__,self).__init__()
+
+    def initialize(self):
+        # Optimizer is exposed so that calling scripts can reference with custom observers
+        self.optimizer = itk.GradientDescentOptimizerv4.New(
+            MaximumStepSizeInPhysicalUnits=3,
+            MinimumConvergenceValue=-1,
+            ConvergenceWindowSize=1,
+            DoEstimateLearningRateOnce=False,
+            DoEstimateLearningRateAtEachIteration=False,
+            ReturnBestParametersAndValue=True)
+
+    def register(self,
+                 template_mesh:MeshType=None,
+                 template_point_set:PointSetType=None,
+                 target_mesh:MeshType=None,
+                 target_point_set:PointSetType=None,
+                 filepath:str=None,
+                 verbose=False,
+                 metric=None,
+                 transform=None,
+                 resample_rate=1.0,
+                 max_iterations=MAX_ITERATIONS,
+                 learning_rate=1.0,
+                 resample_from_target=False) -> (TransformType, PointSetType):
+
+        # Verify a template and target were passed in
+        if(not (template_mesh or template_point_set) or not (target_mesh or target_point_set)):
+            raise Exception('Registration requires both a template and a target!')
+
+        # Need both a mesh and a point set representing the template and the transform
+        if(not template_mesh):
+            template_mesh = self.MeshType.New(Points=template_point_set.GetPoints())
+        else:
+            template_point_set = self.PointSetType.New(Points=template_mesh.GetPoints())
+
+        if(not target_mesh):
+            target_mesh = self.MeshType.New(Points=target_point_set.GetPoints())
+        else:
+            target_point_set = self.PointSetType.New(Points=target_mesh.GetPoints())
+
+        # Optionally resample to improve performance
+        if(resample_rate != 1.0):
+            template_point_set = self.randomly_sample_mesh_points(mesh=template_point_set, sampling_rate=resample_rate)
+            target_point_set = self.randomly_sample_mesh_points(mesh=target_point_set, sampling_rate=resample_rate)
+
+        # Define registration components
+        if not transform:
+            transform = self.TransformType.New()
+            transform.SetIdentity()
+        
+        #template_image = self.mesh_to_image(template_mesh)
+        # Set physical dimensions for transform
+        #fixed_physical_dimensions = list()
+        #fixed_origin = list(template_image.GetOrigin())
+
+        #for i in range(0, self.Dimension):
+        #    fixed_physical_dimensions.append(template_image.GetSpacing()[i] * \
+        #        (template_image.GetLargestPossibleRegion().GetSize()[i] - 1))
+
+        if not metric:
+            metric = itk.JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4[self.PointSetType].New(
+                FixedPointSet=template_point_set,
+                MovingPointSet=target_point_set,
+                MovingTransform=transform,
+                PointSetSigma=20.0,
+                KernelSigma=3.0,
+                UseAnisotropicCovariances=False,
+                CovarianceKNeighborhood=5,
+                EvaluationKNeighborhood=10,
+                Alpha=1.1)
+            #metric.SetVirtualDomainFromImage( template_image );
+
+        metric.SetFixedPointSet(template_point_set)
+        metric.SetMovingPointSet(target_point_set)
+        metric.SetMovingTransform(transform)
+
+        metric.Initialize()
+
+        # Define scales to guide gradient descent steps
+        ShiftScalesType = \
+            itk.RegistrationParameterScalesFromPhysicalShift[type(metric)]
+        shift_scale_estimator = ShiftScalesType.New(
+            Metric=metric,
+            VirtualDomainPointSet=metric.GetVirtualTransformedPointSet())
+
+        self.optimizer.SetMetric(metric)
+        self.optimizer.SetNumberOfIterations(max_iterations)
+        self.optimizer.SetScalesEstimator(shift_scale_estimator)
+        self.optimizer.SetLearningRate(learning_rate)
+
+        def print_iteration():
+            print(f'{self.optimizer.GetCurrentIteration()} {self.optimizer.GetCurrentMetricValue()}')
+
+        if verbose:
+            self.optimizer.AddObserver(itk.AnyEvent(), print_iteration)
+
+        self.optimizer.StartOptimization()
+
+        if(verbose):
+            print(f'Number of iterations run: {self.optimizer.GetCurrentIteration()}')
+            print(f'Final metric value: {self.optimizer.GetCurrentMetricValue()}')
+            print(f'Final transform position: {list(self.optimizer.GetCurrentPosition())}')
+            print(f'Optimizer scales: {list(self.optimizer.GetScales())}')
+            print(f'Optimizer learning rate: {self.optimizer.GetLearningRate()}')
+
+        moving_transform = metric.GetMovingTransform()
+
+        registered_template_mesh = itk.transform_mesh_filter(template_mesh, transform=moving_transform)
+
+        if(resample_from_target):
+            registered_template_mesh = self.resample_template_from_target(registered_template_mesh, target_mesh)
+
+        # Write out
+        if filepath is not None:
+            itk.meshwrite(registered_template_mesh,filepath)
+            if(verbose):
+                print(f'Wrote resulting point set to {filepath}')
+
+        return (transform, registered_template_mesh)
diff --git a/src/hasi/pyproject.toml b/src/hasi/pyproject.toml
index 996a1db..373a217 100644
--- a/src/hasi/pyproject.toml
+++ b/src/hasi/pyproject.toml
@@ -8,7 +8,7 @@ author = "Kitware Medical"
 author-email = "matt.mccormick@kitware.com"
 home-page = "https://github.com/KitwareMedical/HASI"
 requires = [
-    "itk-hasi",
+    "itk-hasi"
 ]
 requires-python=">=3.7"
 classifiers = [


Test patch:
diff --git a/src/hasi/test_meshtomeshregistration.py b/src/hasi/test_meshtomeshregistration.py
index ebdd422..74146e2 100644
--- a/src/hasi/test_meshtomeshregistration.py
+++ b/src/hasi/test_meshtomeshregistration.py
@@ -19,29 +19,28 @@
 
 import itk
 
-MEANSQUARES_METRIC_MAXIMUM_THRESHOLD = 0.002
-DIFFEO_METRIC_MAXIMUM_THRESHOLD = 0.0002
+MEANSQUARES_METRIC_MAXIMUM_THRESHOLD = 0.015
+DIFFEO_METRIC_MAXIMUM_THRESHOLD = 0.25
+POINT_SET_METRIC_MAXIMUM_THRESHOLD = 0.0001
 MAX_ITERATIONS = 200
 
-FIXED_MESH_FILE = 'test/Input/901-L-mesh.vtk'
-MOVING_MESH_FILE = 'test/Input/901-R-mesh.vtk'
+TEMPLATE_MESH_FILE = 'test/Input/template-901-L.obj'
+TARGET_MESH_FILE = 'test/Input/901-R-mesh.vtk'
 
 os.makedirs('test', exist_ok=True)
 os.makedirs('test/Input', exist_ok=True)
 os.makedirs('test/Output', exist_ok=True)
 
-if not os.path.exists(FIXED_MESH_FILE):
-    url = 'https://data.kitware.com/api/v1/file/5f9daaae50a41e3d1924dae1/download'
-    urlretrieve(url, FIXED_MESH_FILE)
+if not os.path.exists(TEMPLATE_MESH_FILE):
+    url = 'https://data.kitware.com/api/v1/file/60762a4b2fa25629b9bbefef/download'
+    urlretrieve(url, TEMPLATE_MESH_FILE)
     
-if not os.path.exists(MOVING_MESH_FILE):
-    url = 'https://data.kitware.com/api/v1/file/5f9daaae50a41e3d1924dae1/download'
-    urlretrieve(url, MOVING_MESH_FILE)
+if not os.path.exists(TARGET_MESH_FILE):
+    url = 'https://data.kitware.com/api/v1/file/5f9daaba50a41e3d1924dae9/download'
+    urlretrieve(url, TARGET_MESH_FILE)
 
-os.makedirs('test/Output', exist_ok=True)
-
-mesh1 = itk.meshread(FIXED_MESH_FILE)
-mesh2 = itk.meshread(MOVING_MESH_FILE)
+template_mesh = itk.meshread(TEMPLATE_MESH_FILE, itk.F)
+target_mesh = itk.meshread(TARGET_MESH_FILE, itk.F)
 
 # Test base class import and functions
 def test_mesh_to_image():
@@ -55,15 +54,13 @@ def test_mesh_to_image():
     registrar.initialize()
 
     # Mesh-to-image executes without error
-    img1 = registrar.mesh_to_image(mesh1)
+    img1 = registrar.mesh_to_image(template_mesh)
 
     # Image was generated
     assert(type(img1) == itk.Image[itk.F, 3])
 
     # Mesh-to-image can run with reference image
-    img2 = registrar.mesh_to_image(mesh2, img1)
-
-    # Image was generated
+    img2 = registrar.mesh_to_image(target_mesh, img1)
     assert(type(img2) == itk.Image[itk.F, 3])
 
     # Images occupy the same physical space
@@ -72,7 +69,7 @@ def test_mesh_to_image():
 
 # Test registration with mean squares image metric
 def test_meansquares_registration():
-    MESH_OUTPUT = 'test/Output/testMeanSquaresRegisterOutput.vtk'
+    MESH_OUTPUT_FILE = 'test/Output/testMeanSquaresRegisterOutput.vtk'
 
     # Class is imported
     from hasi.meansquaresregistrar import MeanSquaresRegistrar
@@ -81,10 +78,16 @@ def test_meansquares_registration():
     registrar = MeanSquaresRegistrar()
 
     # Registration executes
-    (transform, mesh3) = registrar.register(mesh1,mesh2,filepath=MESH_OUTPUT)
+    (transform, template_output_mesh) = registrar.register(template_mesh=template_mesh,
+                                            target_mesh=target_mesh,
+                                            filepath=MESH_OUTPUT_FILE)
 
     # Mesh was generated
-    assert(type(mesh3) == type(mesh1))
+    assert(type(template_output_mesh) == type(template_mesh))
+
+    # Mesh is a resampling of the original template
+    assert(template_output_mesh.GetNumberOfPoints() == \
+        template_mesh.GetNumberOfPoints())
 
     # Optimization converged
     assert(registrar.optimizer.GetCurrentMetricValue() <
@@ -97,20 +100,24 @@ def test_meansquares_registration():
     assert(type(transform) == registrar.TransformType)
 
     # Mesh was output
-    assert(os.path.isfile(MESH_OUTPUT))
+    assert(os.path.isfile(MESH_OUTPUT_FILE))
 
     # File output matches mesh
-    fileMesh3 = itk.meshread(MESH_OUTPUT)
-    assert(fileMesh3.GetNumberOfPoints() == mesh3.GetNumberOfPoints())
-    assert(all(mesh3.GetPoint(i) == fileMesh3.GetPoint(i)
-                for i in range(0,mesh3.GetNumberOfPoints())))
+    output_mesh = itk.meshread(MESH_OUTPUT_FILE)
+    assert(output_mesh.GetNumberOfPoints() == \
+        template_output_mesh.GetNumberOfPoints())
+    assert(all(output_mesh.GetPoint(i) == template_output_mesh.GetPoint(i)
+                for i in range(0,output_mesh.GetNumberOfPoints())))
+
+    # Resample template
+    template_resampled = registrar.resample_template_from_target(template_output_mesh, target_mesh)
 
     # Clean up
-    os.remove(MESH_OUTPUT)
+    os.remove(MESH_OUTPUT_FILE)
 
 # Test registration with diffeomorphic demons image registration
 def test_diffeo_registration():
-    MESH_OUTPUT = 'test/Output/testDiffeoRegisterOutput.vtk'
+    MESH_OUTPUT_FILE = 'test/Output/testDiffeoRegisterOutput.vtk'
 
     # Class is imported
     from hasi.diffeoregistrar import DiffeoRegistrar
@@ -119,16 +126,22 @@ def test_diffeo_registration():
     registrar = DiffeoRegistrar()
 
     # Registration executes without error
-    (transform, mesh4) = registrar.register(mesh1,mesh2,filepath=MESH_OUTPUT)
+    (transform, template_output_mesh) = registrar.register(template_mesh=template_mesh,
+                                                           target_mesh=target_mesh,
+                                                           filepath=MESH_OUTPUT_FILE)
     
     # Transform was output
     assert(type(transform) == registrar.TransformType)
 
     # Mesh was generated
-    assert(type(mesh4) == type(mesh1))
+    assert(type(template_output_mesh) == type(template_mesh))
+    
+    # Mesh is a resampling of the original template
+    assert(template_output_mesh.GetNumberOfPoints() == \
+        template_mesh.GetNumberOfPoints())
 
     # Mesh was output
-    assert(os.path.isfile(MESH_OUTPUT))
+    assert(os.path.isfile(MESH_OUTPUT_FILE))
 
     # Optimization converged
     assert(registrar.filter.GetMetric() <
@@ -138,4 +151,51 @@ def test_diffeo_registration():
     assert(registrar.filter.GetElapsedIterations() <= MAX_ITERATIONS)
 
     # Clean up
-    os.remove(MESH_OUTPUT)
+    os.remove(MESH_OUTPUT_FILE)
+
+def test_pointset_registration():
+    MESH_OUTPUT_FILE = 'test/Output/testPointSetRegistrarOutput.vtk'
+    RESAMPLED_OUTPUT_FILE = 'test/Output/testPointSetResampledOutput.vtk'
+
+    # Class is imported
+    from hasi.pointsetentropyregistrar import PointSetEntropyRegistrar
+
+    # Class is instantiable
+    registrar = PointSetEntropyRegistrar()
+
+    # Registration executes without error
+    (transform, template_output_mesh) = registrar.register(template_mesh=template_mesh,
+                               target_mesh=target_mesh,
+                               filepath=MESH_OUTPUT_FILE,
+                               resample_from_target=False)
+    
+    # Transform was output
+    assert(type(transform) == registrar.TransformType)
+
+    # Mesh was generated
+    assert(type(template_output_mesh) == type(template_mesh))
+    
+    # Mesh is a transformation of the original template
+    assert(template_output_mesh.GetNumberOfPoints() == \
+        template_mesh.GetNumberOfPoints())
+
+    # Mesh was output
+    assert(os.path.isfile(MESH_OUTPUT_FILE))
+
+    # Optimization converged
+    assert(registrar.optimizer.GetCurrentMetricValue() <
+           POINT_SET_METRIC_MAXIMUM_THRESHOLD)
+
+    # Optimization did not exceed allowable iterations
+    assert(registrar.optimizer.GetCurrentIteration() <= registrar.MAX_ITERATIONS)
+
+    # Resample template
+    template_resampled = \
+        registrar.resample_template_from_target(template_output_mesh, target_mesh)
+    
+    # Mesh is a transformation of the original template
+    assert(template_resampled.GetNumberOfPoints() == \
+        template_mesh.GetNumberOfPoints())
+
+    # Clean up
+    os.remove(MESH_OUTPUT_FILE)