Spaces:
No application file
No application file
| # -*- coding: utf-8 -*- | |
| """ | |
| Created on Fri Apr 15 13:01:08 2022 | |
| @author: 12593 | |
| """ | |
| import numpy as np | |
| import scipy.ndimage | |
| # neighbour_code_to_normals is a lookup table. | |
| # For every binary neighbour code | |
| # (2x2x2 neighbourhood = 8 neighbours = 8 bits = 256 codes) | |
| # it contains the surface normals of the triangles (called "surfel" for | |
| # "surface element" in the following). The length of the normal | |
| # vector encodes the surfel area. | |
| # | |
| # created by compute_surface_area_lookup_table.ipynb using the | |
| # marching_cube algorithm, see e.g. https://en.wikipedia.org/wiki/Marching_cubes | |
| # credit to: http://medicaldecathlon.com/files/Surface_distance_based_measures.ipynb | |
| neighbour_code_to_normals = [ | |
| [[0, 0, 0]], | |
| [[0.125, 0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [0.25, 0.25, -0.0]], | |
| [[0.125, -0.125, 0.125]], | |
| [[-0.25, -0.0, -0.25], [0.25, 0.0, 0.25]], | |
| [[0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[0.5, 0.0, -0.0], [0.25, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[-0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25]], | |
| [[0.5, 0.0, 0.0], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [[0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [[0.5, 0.0, 0.0], [0.25, -0.25, 0.25], [-0.125, 0.125, -0.125]], | |
| [[-0.5, 0.0, 0.0], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[0.5, 0.0, 0.0], [0.5, 0.0, 0.0]], | |
| [[0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25]], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.5, 0.0], [0.25, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, 0.0, -0.5], [0.25, 0.25, 0.25], [-0.125, -0.125, -0.125]], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, -0.25, -0.25], | |
| [0.25, 0.25, 0.25], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25], [0.125, -0.125, -0.125]], | |
| [ | |
| [0.125, 0.125, 0.125], | |
| [0.375, 0.375, 0.375], | |
| [0.0, -0.25, 0.25], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [[0.125, -0.125, -0.125], [0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [ | |
| [0.375, 0.375, 0.375], | |
| [0.0, 0.25, -0.25], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, 0.25, 0.0], | |
| ], | |
| [ | |
| [-0.5, 0.0, 0.0], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, -0.25, -0.25], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[-0.5, 0.0, 0.0], [-0.125, -0.125, -0.125], [-0.25, -0.25, -0.25]], | |
| [[0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.0, -0.25, 0.25], [0.0, 0.25, -0.25]], | |
| [[0.0, -0.5, 0.0], [0.125, 0.125, -0.125], [0.25, 0.25, -0.25]], | |
| [[0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.125, -0.125, 0.125], [-0.25, -0.0, -0.25], [0.25, 0.0, 0.25]], | |
| [[0.0, -0.25, 0.25], [0.0, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [-0.375, -0.375, 0.375], | |
| [-0.0, 0.25, 0.25], | |
| [0.125, 0.125, -0.125], | |
| [-0.25, -0.0, -0.25], | |
| ], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.0, 0.0, 0.5], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [ | |
| [0.25, 0.25, -0.25], | |
| [0.25, 0.25, -0.25], | |
| [0.125, 0.125, -0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, -0.125, 0.125], [0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [ | |
| [0.5, 0.0, 0.0], | |
| [0.25, -0.25, 0.25], | |
| [-0.125, 0.125, -0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [ | |
| [0.0, 0.25, -0.25], | |
| [0.375, -0.375, -0.375], | |
| [-0.125, 0.125, 0.125], | |
| [0.25, 0.25, 0.0], | |
| ], | |
| [[-0.5, 0.0, 0.0], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [[0.25, -0.25, 0.0], [-0.25, 0.25, 0.0]], | |
| [[0.0, 0.5, 0.0], [-0.25, 0.25, 0.25], [0.125, -0.125, -0.125]], | |
| [[0.0, 0.5, 0.0], [0.125, -0.125, 0.125], [-0.25, 0.25, -0.25]], | |
| [[0.0, 0.5, 0.0], [0.0, -0.5, 0.0]], | |
| [[0.25, -0.25, 0.0], [-0.25, 0.25, 0.0], [0.125, -0.125, 0.125]], | |
| [ | |
| [-0.375, -0.375, -0.375], | |
| [-0.25, 0.0, 0.25], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, 0.25, 0.0], | |
| ], | |
| [ | |
| [0.125, 0.125, 0.125], | |
| [0.0, -0.5, 0.0], | |
| [-0.25, -0.25, -0.25], | |
| [-0.125, -0.125, -0.125], | |
| ], | |
| [[0.0, -0.5, 0.0], [-0.25, -0.25, -0.25], [-0.125, -0.125, -0.125]], | |
| [[-0.125, 0.125, 0.125], [0.25, -0.25, 0.0], [-0.25, 0.25, 0.0]], | |
| [ | |
| [0.0, 0.5, 0.0], | |
| [0.25, 0.25, -0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [ | |
| [-0.375, 0.375, -0.375], | |
| [-0.25, -0.25, 0.0], | |
| [-0.125, 0.125, -0.125], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [[0.0, 0.5, 0.0], [0.25, 0.25, -0.25], [-0.125, -0.125, 0.125]], | |
| [[0.25, -0.25, 0.0], [-0.25, 0.25, 0.0], [0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [[-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0], [-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]], | |
| [[-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]], | |
| [[-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [-0.25, -0.25, 0.0], [0.25, 0.25, -0.0]], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25]], | |
| [[0.0, 0.0, 0.5], [0.25, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [ | |
| [0.375, -0.375, 0.375], | |
| [0.0, -0.25, -0.25], | |
| [-0.125, 0.125, -0.125], | |
| [0.25, 0.25, 0.0], | |
| ], | |
| [[-0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25]], | |
| [ | |
| [0.5, 0.0, 0.0], | |
| [-0.25, -0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.0, 0.5, 0.0], [-0.25, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [-0.25, 0.25, -0.25], | |
| [-0.25, 0.25, -0.25], | |
| [-0.125, 0.125, -0.125], | |
| [-0.125, 0.125, -0.125], | |
| ], | |
| [ | |
| [-0.25, 0.0, -0.25], | |
| [0.375, -0.375, -0.375], | |
| [0.0, 0.25, -0.25], | |
| [-0.125, 0.125, 0.125], | |
| ], | |
| [[0.5, 0.0, 0.0], [-0.25, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [[-0.25, 0.0, 0.25], [0.25, 0.0, -0.25]], | |
| [[-0.0, 0.0, 0.5], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [-0.25, 0.0, 0.25], [0.25, 0.0, -0.25]], | |
| [ | |
| [-0.25, -0.0, -0.25], | |
| [-0.375, 0.375, 0.375], | |
| [-0.25, -0.25, 0.0], | |
| [-0.125, 0.125, 0.125], | |
| ], | |
| [[0.0, 0.0, -0.5], [0.25, 0.25, -0.25], [-0.125, -0.125, 0.125]], | |
| [[-0.0, 0.0, 0.5], [0.0, 0.0, 0.5]], | |
| [[0.125, 0.125, 0.125], [0.125, 0.125, 0.125], [0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [[0.125, 0.125, 0.125], [0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [[-0.25, 0.0, 0.25], [0.25, 0.0, -0.25], [-0.125, 0.125, 0.125]], | |
| [ | |
| [-0.0, 0.0, 0.5], | |
| [0.25, -0.25, 0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25], [0.25, 0.0, -0.25]], | |
| [[0.125, -0.125, 0.125], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [ | |
| [0.25, 0.0, 0.25], | |
| [-0.375, -0.375, 0.375], | |
| [-0.25, 0.25, 0.0], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.0, 0.0, 0.5], [0.25, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [[0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [0.0, -0.25, 0.25], [0.0, 0.25, -0.25]], | |
| [ | |
| [0.0, -0.5, 0.0], | |
| [0.125, 0.125, -0.125], | |
| [0.25, 0.25, -0.25], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [0.0, 0.0, 0.5], | |
| [0.25, -0.25, 0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [0.0, 0.25, -0.25]], | |
| [[0.0, 0.25, 0.25], [0.0, 0.25, 0.25], [0.125, -0.125, -0.125]], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [ | |
| [-0.125, 0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [ | |
| [-0.0, 0.0, 0.5], | |
| [-0.25, -0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.0, 0.5, 0.0], | |
| [-0.25, 0.25, -0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.5, 0.0, -0.0], [0.25, -0.25, -0.25], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.25, 0.25, 0.25], | |
| [-0.125, 0.125, 0.125], | |
| [-0.25, 0.25, 0.25], | |
| [0.125, -0.125, -0.125], | |
| ], | |
| [ | |
| [0.375, -0.375, 0.375], | |
| [0.0, 0.25, 0.25], | |
| [-0.125, 0.125, -0.125], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [[0.0, -0.5, 0.0], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [ | |
| [-0.375, -0.375, 0.375], | |
| [0.25, -0.25, 0.0], | |
| [0.0, 0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.125, 0.125, 0.125], [-0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [[0.125, 0.125, 0.125], [0.0, 0.25, 0.25], [0.0, 0.25, 0.25]], | |
| [[0.0, 0.25, 0.25], [0.0, 0.25, 0.25]], | |
| [ | |
| [0.5, 0.0, -0.0], | |
| [0.25, 0.25, 0.25], | |
| [0.125, 0.125, 0.125], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[0.125, -0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, 0.125, 0.125]], | |
| [[-0.25, -0.0, -0.25], [0.25, 0.0, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [0.25, 0.25, -0.0], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [0.25, 0.25, -0.0], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[-0.25, -0.0, -0.25], [0.25, 0.0, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, -0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, 0.125, 0.125]], | |
| [ | |
| [0.5, 0.0, -0.0], | |
| [0.25, 0.25, 0.25], | |
| [0.125, 0.125, 0.125], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[0.0, 0.25, 0.25], [0.0, 0.25, 0.25]], | |
| [[0.125, 0.125, 0.125], [0.0, 0.25, 0.25], [0.0, 0.25, 0.25]], | |
| [[-0.125, 0.125, 0.125], [-0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [ | |
| [-0.375, -0.375, 0.375], | |
| [0.25, -0.25, 0.0], | |
| [0.0, 0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[0.0, -0.5, 0.0], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [ | |
| [0.375, -0.375, 0.375], | |
| [0.0, 0.25, 0.25], | |
| [-0.125, 0.125, -0.125], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [ | |
| [-0.25, 0.25, 0.25], | |
| [-0.125, 0.125, 0.125], | |
| [-0.25, 0.25, 0.25], | |
| [0.125, -0.125, -0.125], | |
| ], | |
| [[0.5, 0.0, -0.0], [0.25, -0.25, -0.25], [0.125, -0.125, -0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.0, 0.5, 0.0], | |
| [-0.25, 0.25, -0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.0, 0.0, 0.5], | |
| [-0.25, -0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [ | |
| [-0.125, 0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[0.0, 0.25, 0.25], [0.0, 0.25, 0.25], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25], [0.0, 0.25, 0.25], [0.0, 0.25, 0.25]], | |
| [ | |
| [0.0, 0.0, 0.5], | |
| [0.25, -0.25, 0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [0.0, -0.5, 0.0], | |
| [0.125, 0.125, -0.125], | |
| [0.25, 0.25, -0.25], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.125, -0.125, 0.125], [0.0, -0.25, 0.25], [0.0, 0.25, -0.25]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [[0.125, 0.125, 0.125], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [[-0.0, 0.0, 0.5], [0.25, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [0.25, 0.0, 0.25], | |
| [-0.375, -0.375, 0.375], | |
| [-0.25, 0.25, 0.0], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, -0.125, 0.125], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [[-0.25, -0.0, -0.25], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25], [0.25, 0.0, 0.25]], | |
| [ | |
| [-0.0, 0.0, 0.5], | |
| [0.25, -0.25, 0.25], | |
| [0.125, -0.125, 0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[-0.25, 0.0, 0.25], [0.25, 0.0, -0.25], [-0.125, 0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [[0.125, 0.125, 0.125], [0.125, 0.125, 0.125], [0.25, 0.25, 0.25], [0.0, 0.0, 0.5]], | |
| [[-0.0, 0.0, 0.5], [0.0, 0.0, 0.5]], | |
| [[0.0, 0.0, -0.5], [0.25, 0.25, -0.25], [-0.125, -0.125, 0.125]], | |
| [ | |
| [-0.25, -0.0, -0.25], | |
| [-0.375, 0.375, 0.375], | |
| [-0.25, -0.25, 0.0], | |
| [-0.125, 0.125, 0.125], | |
| ], | |
| [[-0.125, -0.125, 0.125], [-0.25, 0.0, 0.25], [0.25, 0.0, -0.25]], | |
| [[-0.0, 0.0, 0.5], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[-0.25, 0.0, 0.25], [0.25, 0.0, -0.25]], | |
| [[0.5, 0.0, 0.0], [-0.25, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [-0.25, 0.0, -0.25], | |
| [0.375, -0.375, -0.375], | |
| [0.0, 0.25, -0.25], | |
| [-0.125, 0.125, 0.125], | |
| ], | |
| [ | |
| [-0.25, 0.25, -0.25], | |
| [-0.25, 0.25, -0.25], | |
| [-0.125, 0.125, -0.125], | |
| [-0.125, 0.125, -0.125], | |
| ], | |
| [[-0.0, 0.5, 0.0], [-0.25, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [ | |
| [0.5, 0.0, 0.0], | |
| [-0.25, -0.25, 0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.125, -0.125, 0.125], [-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [ | |
| [0.375, -0.375, 0.375], | |
| [0.0, -0.25, -0.25], | |
| [-0.125, 0.125, -0.125], | |
| [0.25, 0.25, 0.0], | |
| ], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [[0.0, 0.0, 0.5], [0.25, -0.25, 0.25], [0.125, -0.125, 0.125]], | |
| [[0.0, -0.25, 0.25], [0.0, -0.25, 0.25]], | |
| [[-0.125, -0.125, 0.125], [-0.25, -0.25, 0.0], [0.25, 0.25, -0.0]], | |
| [[-0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]], | |
| [[0.125, 0.125, 0.125], [-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]], | |
| [[-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0], [-0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0], [-0.25, -0.25, 0.0], [0.25, 0.25, -0.0]], | |
| [[0.0, 0.5, 0.0], [0.25, 0.25, -0.25], [-0.125, -0.125, 0.125]], | |
| [ | |
| [-0.375, 0.375, -0.375], | |
| [-0.25, -0.25, 0.0], | |
| [-0.125, 0.125, -0.125], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [ | |
| [0.0, 0.5, 0.0], | |
| [0.25, 0.25, -0.25], | |
| [-0.125, -0.125, 0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.125, 0.125, 0.125], [0.25, -0.25, 0.0], [-0.25, 0.25, 0.0]], | |
| [[0.0, -0.5, 0.0], [-0.25, -0.25, -0.25], [-0.125, -0.125, -0.125]], | |
| [ | |
| [0.125, 0.125, 0.125], | |
| [0.0, -0.5, 0.0], | |
| [-0.25, -0.25, -0.25], | |
| [-0.125, -0.125, -0.125], | |
| ], | |
| [ | |
| [-0.375, -0.375, -0.375], | |
| [-0.25, 0.0, 0.25], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, 0.25, 0.0], | |
| ], | |
| [[0.25, -0.25, 0.0], [-0.25, 0.25, 0.0], [0.125, -0.125, 0.125]], | |
| [[0.0, 0.5, 0.0], [0.0, -0.5, 0.0]], | |
| [[0.0, 0.5, 0.0], [0.125, -0.125, 0.125], [-0.25, 0.25, -0.25]], | |
| [[0.0, 0.5, 0.0], [-0.25, 0.25, 0.25], [0.125, -0.125, -0.125]], | |
| [[0.25, -0.25, 0.0], [-0.25, 0.25, 0.0]], | |
| [[-0.5, 0.0, 0.0], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [ | |
| [0.0, 0.25, -0.25], | |
| [0.375, -0.375, -0.375], | |
| [-0.125, 0.125, 0.125], | |
| [0.25, 0.25, 0.0], | |
| ], | |
| [ | |
| [0.5, 0.0, 0.0], | |
| [0.25, -0.25, 0.25], | |
| [-0.125, 0.125, -0.125], | |
| [0.125, -0.125, 0.125], | |
| ], | |
| [[0.125, -0.125, 0.125], [0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [ | |
| [0.25, 0.25, -0.25], | |
| [0.25, 0.25, -0.25], | |
| [0.125, 0.125, -0.125], | |
| [-0.125, -0.125, 0.125], | |
| ], | |
| [[-0.0, 0.0, 0.5], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [ | |
| [-0.375, -0.375, 0.375], | |
| [-0.0, 0.25, 0.25], | |
| [0.125, 0.125, -0.125], | |
| [-0.25, -0.0, -0.25], | |
| ], | |
| [[0.0, -0.25, 0.25], [0.0, 0.25, -0.25], [0.125, -0.125, 0.125]], | |
| [[0.125, -0.125, 0.125], [-0.25, -0.0, -0.25], [0.25, 0.0, 0.25]], | |
| [[0.125, -0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.0, -0.5, 0.0], [0.125, 0.125, -0.125], [0.25, 0.25, -0.25]], | |
| [[0.0, -0.25, 0.25], [0.0, 0.25, -0.25]], | |
| [[0.125, 0.125, 0.125], [0.125, -0.125, 0.125]], | |
| [[0.125, -0.125, 0.125]], | |
| [[-0.5, 0.0, 0.0], [-0.125, -0.125, -0.125], [-0.25, -0.25, -0.25]], | |
| [ | |
| [-0.5, 0.0, 0.0], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, -0.25, -0.25], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [ | |
| [0.375, 0.375, 0.375], | |
| [0.0, 0.25, -0.25], | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, 0.25, 0.0], | |
| ], | |
| [[0.125, -0.125, -0.125], [0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [ | |
| [0.125, 0.125, 0.125], | |
| [0.375, 0.375, 0.375], | |
| [0.0, -0.25, 0.25], | |
| [-0.25, 0.0, 0.25], | |
| ], | |
| [[-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[-0.125, 0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [ | |
| [-0.125, -0.125, -0.125], | |
| [-0.25, -0.25, -0.25], | |
| [0.25, 0.25, 0.25], | |
| [0.125, 0.125, 0.125], | |
| ], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, 0.0, -0.5], [0.25, 0.25, 0.25], [-0.125, -0.125, -0.125]], | |
| [[0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.5, 0.0], [0.25, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[-0.125, -0.125, 0.125], [0.125, -0.125, -0.125]], | |
| [[0.0, -0.25, -0.25], [0.0, 0.25, 0.25]], | |
| [[0.125, -0.125, -0.125]], | |
| [[0.5, 0.0, 0.0], [0.5, 0.0, 0.0]], | |
| [[-0.5, 0.0, 0.0], [-0.25, 0.25, 0.25], [-0.125, 0.125, 0.125]], | |
| [[0.5, 0.0, 0.0], [0.25, -0.25, 0.25], [-0.125, 0.125, -0.125]], | |
| [[0.25, -0.25, 0.0], [0.25, -0.25, 0.0]], | |
| [[0.5, 0.0, 0.0], [-0.25, -0.25, 0.25], [-0.125, -0.125, 0.125]], | |
| [[-0.25, 0.0, 0.25], [-0.25, 0.0, 0.25]], | |
| [[0.125, 0.125, 0.125], [-0.125, 0.125, 0.125]], | |
| [[-0.125, 0.125, 0.125]], | |
| [[0.5, 0.0, -0.0], [0.25, 0.25, 0.25], [0.125, 0.125, 0.125]], | |
| [[0.125, -0.125, 0.125], [-0.125, -0.125, 0.125]], | |
| [[-0.25, -0.0, -0.25], [0.25, 0.0, 0.25]], | |
| [[0.125, -0.125, 0.125]], | |
| [[-0.25, -0.25, 0.0], [0.25, 0.25, -0.0]], | |
| [[-0.125, -0.125, 0.125]], | |
| [[0.125, 0.125, 0.125]], | |
| [[0, 0, 0]], | |
| ] | |
| def compute_surface_distances(mask_gt, mask_pred, spacing_mm): | |
| """Compute closest distances from all surface points to the other surface. | |
| Finds all surface elements "surfels" in the ground truth mask `mask_gt` and | |
| the predicted mask `mask_pred`, computes their area in mm^2 and the distance | |
| to the closest point on the other surface. It returns two sorted lists of | |
| distances together with the corresponding surfel areas. If one of the masks | |
| is empty, the corresponding lists are empty and all distances in the other | |
| list are `inf` | |
| Args: | |
| mask_gt: 3-dim Numpy array of type bool. The ground truth mask. | |
| mask_pred: 3-dim Numpy array of type bool. The predicted mask. | |
| spacing_mm: 3-element list-like structure. Voxel spacing in x0, x1 and x2 | |
| direction | |
| Returns: | |
| A dict with | |
| "distances_gt_to_pred": 1-dim numpy array of type float. The distances in mm | |
| from all ground truth surface elements to the predicted surface, | |
| sorted from smallest to largest | |
| "distances_pred_to_gt": 1-dim numpy array of type float. The distances in mm | |
| from all predicted surface elements to the ground truth surface, | |
| sorted from smallest to largest | |
| "surfel_areas_gt": 1-dim numpy array of type float. The area in mm^2 of | |
| the ground truth surface elements in the same order as | |
| distances_gt_to_pred | |
| "surfel_areas_pred": 1-dim numpy array of type float. The area in mm^2 of | |
| the predicted surface elements in the same order as | |
| distances_pred_to_gt | |
| """ | |
| # compute the area for all 256 possible surface elements | |
| # (given a 2x2x2 neighbourhood) according to the spacing_mm | |
| neighbour_code_to_surface_area = np.zeros([256]) | |
| for code in range(256): | |
| normals = np.array(neighbour_code_to_normals[code]) | |
| sum_area = 0 | |
| for normal_idx in range(normals.shape[0]): | |
| # normal vector | |
| n = np.zeros([3]) | |
| n[0] = normals[normal_idx, 0] * spacing_mm[1] * spacing_mm[2] | |
| n[1] = normals[normal_idx, 1] * spacing_mm[0] * spacing_mm[2] | |
| n[2] = normals[normal_idx, 2] * spacing_mm[0] * spacing_mm[1] | |
| area = np.linalg.norm(n) | |
| sum_area += area | |
| neighbour_code_to_surface_area[code] = sum_area | |
| # compute the bounding box of the masks to trim | |
| # the volume to the smallest possible processing subvolume | |
| mask_all = mask_gt | mask_pred | |
| bbox_min = np.zeros(3, np.int64) | |
| bbox_max = np.zeros(3, np.int64) | |
| # max projection to the x0-axis | |
| proj_0 = np.max(np.max(mask_all, axis=2), axis=1) | |
| idx_nonzero_0 = np.nonzero(proj_0)[0] | |
| if len(idx_nonzero_0) == 0: | |
| return { | |
| "distances_gt_to_pred": np.array([]), | |
| "distances_pred_to_gt": np.array([]), | |
| "surfel_areas_gt": np.array([]), | |
| "surfel_areas_pred": np.array([]), | |
| } | |
| bbox_min[0] = np.min(idx_nonzero_0) | |
| bbox_max[0] = np.max(idx_nonzero_0) | |
| # max projection to the x1-axis | |
| proj_1 = np.max(np.max(mask_all, axis=2), axis=0) | |
| idx_nonzero_1 = np.nonzero(proj_1)[0] | |
| bbox_min[1] = np.min(idx_nonzero_1) | |
| bbox_max[1] = np.max(idx_nonzero_1) | |
| # max projection to the x2-axis | |
| proj_2 = np.max(np.max(mask_all, axis=1), axis=0) | |
| idx_nonzero_2 = np.nonzero(proj_2)[0] | |
| bbox_min[2] = np.min(idx_nonzero_2) | |
| bbox_max[2] = np.max(idx_nonzero_2) | |
| # print("bounding box min = {}".format(bbox_min)) | |
| # print("bounding box max = {}".format(bbox_max)) | |
| # crop the processing subvolume. | |
| # we need to zeropad the cropped region with 1 voxel at the lower, | |
| # the right and the back side. This is required to obtain the "full" | |
| # convolution result with the 2x2x2 kernel | |
| cropmask_gt = np.zeros((bbox_max - bbox_min) + 2, np.uint8) | |
| cropmask_pred = np.zeros((bbox_max - bbox_min) + 2, np.uint8) | |
| cropmask_gt[0:-1, 0:-1, 0:-1] = mask_gt[ | |
| bbox_min[0] : bbox_max[0] + 1, | |
| bbox_min[1] : bbox_max[1] + 1, | |
| bbox_min[2] : bbox_max[2] + 1, | |
| ] | |
| cropmask_pred[0:-1, 0:-1, 0:-1] = mask_pred[ | |
| bbox_min[0] : bbox_max[0] + 1, | |
| bbox_min[1] : bbox_max[1] + 1, | |
| bbox_min[2] : bbox_max[2] + 1, | |
| ] | |
| # compute the neighbour code (local binary pattern) for each voxel | |
| # the resultsing arrays are spacially shifted by minus half a voxel in each axis. | |
| # i.e. the points are located at the corners of the original voxels | |
| kernel = np.array([[[128, 64], [32, 16]], [[8, 4], [2, 1]]]) | |
| neighbour_code_map_gt = scipy.ndimage.filters.correlate( | |
| cropmask_gt.astype(np.uint8), kernel, mode="constant", cval=0 | |
| ) | |
| neighbour_code_map_pred = scipy.ndimage.filters.correlate( | |
| cropmask_pred.astype(np.uint8), kernel, mode="constant", cval=0 | |
| ) | |
| # create masks with the surface voxels | |
| borders_gt = (neighbour_code_map_gt != 0) & (neighbour_code_map_gt != 255) | |
| borders_pred = (neighbour_code_map_pred != 0) & (neighbour_code_map_pred != 255) | |
| # compute the distance transform (closest distance of each voxel to the surface voxels) | |
| if borders_gt.any(): | |
| distmap_gt = scipy.ndimage.morphology.distance_transform_edt( | |
| ~borders_gt, sampling=spacing_mm | |
| ) | |
| else: | |
| distmap_gt = np.Inf * np.ones(borders_gt.shape) | |
| if borders_pred.any(): | |
| distmap_pred = scipy.ndimage.morphology.distance_transform_edt( | |
| ~borders_pred, sampling=spacing_mm | |
| ) | |
| else: | |
| distmap_pred = np.Inf * np.ones(borders_pred.shape) | |
| # compute the area of each surface element | |
| surface_area_map_gt = neighbour_code_to_surface_area[neighbour_code_map_gt] | |
| surface_area_map_pred = neighbour_code_to_surface_area[neighbour_code_map_pred] | |
| # create a list of all surface elements with distance and area | |
| distances_gt_to_pred = distmap_pred[borders_gt] | |
| distances_pred_to_gt = distmap_gt[borders_pred] | |
| surfel_areas_gt = surface_area_map_gt[borders_gt] | |
| surfel_areas_pred = surface_area_map_pred[borders_pred] | |
| # sort them by distance | |
| if distances_gt_to_pred.shape != (0,): | |
| sorted_surfels_gt = np.array(sorted(zip(distances_gt_to_pred, surfel_areas_gt))) | |
| distances_gt_to_pred = sorted_surfels_gt[:, 0] | |
| surfel_areas_gt = sorted_surfels_gt[:, 1] | |
| if distances_pred_to_gt.shape != (0,): | |
| sorted_surfels_pred = np.array( | |
| sorted(zip(distances_pred_to_gt, surfel_areas_pred)) | |
| ) | |
| distances_pred_to_gt = sorted_surfels_pred[:, 0] | |
| surfel_areas_pred = sorted_surfels_pred[:, 1] | |
| return { | |
| "distances_gt_to_pred": distances_gt_to_pred, | |
| "distances_pred_to_gt": distances_pred_to_gt, | |
| "surfel_areas_gt": surfel_areas_gt, | |
| "surfel_areas_pred": surfel_areas_pred, | |
| } | |
| def compute_average_surface_distance(surface_distances): | |
| distances_gt_to_pred = surface_distances["distances_gt_to_pred"] | |
| distances_pred_to_gt = surface_distances["distances_pred_to_gt"] | |
| surfel_areas_gt = surface_distances["surfel_areas_gt"] | |
| surfel_areas_pred = surface_distances["surfel_areas_pred"] | |
| average_distance_gt_to_pred = np.sum( | |
| distances_gt_to_pred * surfel_areas_gt | |
| ) / np.sum(surfel_areas_gt) | |
| average_distance_pred_to_gt = np.sum( | |
| distances_pred_to_gt * surfel_areas_pred | |
| ) / np.sum(surfel_areas_pred) | |
| return (average_distance_gt_to_pred, average_distance_pred_to_gt) | |
| def compute_robust_hausdorff(surface_distances, percent): | |
| distances_gt_to_pred = surface_distances["distances_gt_to_pred"] | |
| distances_pred_to_gt = surface_distances["distances_pred_to_gt"] | |
| surfel_areas_gt = surface_distances["surfel_areas_gt"] | |
| surfel_areas_pred = surface_distances["surfel_areas_pred"] | |
| if len(distances_gt_to_pred) > 0: | |
| surfel_areas_cum_gt = np.cumsum(surfel_areas_gt) / np.sum(surfel_areas_gt) | |
| idx = np.searchsorted(surfel_areas_cum_gt, percent / 100.0) | |
| perc_distance_gt_to_pred = distances_gt_to_pred[ | |
| min(idx, len(distances_gt_to_pred) - 1) | |
| ] | |
| else: | |
| perc_distance_gt_to_pred = np.Inf | |
| if len(distances_pred_to_gt) > 0: | |
| surfel_areas_cum_pred = np.cumsum(surfel_areas_pred) / np.sum(surfel_areas_pred) | |
| idx = np.searchsorted(surfel_areas_cum_pred, percent / 100.0) | |
| perc_distance_pred_to_gt = distances_pred_to_gt[ | |
| min(idx, len(distances_pred_to_gt) - 1) | |
| ] | |
| else: | |
| perc_distance_pred_to_gt = np.Inf | |
| return max(perc_distance_gt_to_pred, perc_distance_pred_to_gt) | |
| def compute_surface_overlap_at_tolerance(surface_distances, tolerance_mm): | |
| distances_gt_to_pred = surface_distances["distances_gt_to_pred"] | |
| distances_pred_to_gt = surface_distances["distances_pred_to_gt"] | |
| surfel_areas_gt = surface_distances["surfel_areas_gt"] | |
| surfel_areas_pred = surface_distances["surfel_areas_pred"] | |
| rel_overlap_gt = np.sum( | |
| surfel_areas_gt[distances_gt_to_pred <= tolerance_mm] | |
| ) / np.sum(surfel_areas_gt) | |
| rel_overlap_pred = np.sum( | |
| surfel_areas_pred[distances_pred_to_gt <= tolerance_mm] | |
| ) / np.sum(surfel_areas_pred) | |
| return (rel_overlap_gt, rel_overlap_pred) | |
| def compute_surface_dice_at_tolerance(surface_distances, tolerance_mm): | |
| distances_gt_to_pred = surface_distances["distances_gt_to_pred"] | |
| distances_pred_to_gt = surface_distances["distances_pred_to_gt"] | |
| surfel_areas_gt = surface_distances["surfel_areas_gt"] | |
| surfel_areas_pred = surface_distances["surfel_areas_pred"] | |
| overlap_gt = np.sum(surfel_areas_gt[distances_gt_to_pred <= tolerance_mm]) | |
| overlap_pred = np.sum(surfel_areas_pred[distances_pred_to_gt <= tolerance_mm]) | |
| surface_dice = (overlap_gt + overlap_pred) / ( | |
| np.sum(surfel_areas_gt) + np.sum(surfel_areas_pred) | |
| ) | |
| return surface_dice | |
| def compute_dice_coefficient(mask_gt, mask_pred): | |
| """Compute soerensen-dice coefficient. | |
| compute the soerensen-dice coefficient between the ground truth mask `mask_gt` | |
| and the predicted mask `mask_pred`. | |
| Args: | |
| mask_gt: 3-dim Numpy array of type bool. The ground truth mask. | |
| mask_pred: 3-dim Numpy array of type bool. The predicted mask. | |
| Returns: | |
| the dice coeffcient as float. If both masks are empty, the result is NaN | |
| """ | |
| volume_sum = mask_gt.sum() + mask_pred.sum() | |
| if volume_sum == 0: | |
| return np.NaN | |
| volume_intersect = (mask_gt & mask_pred).sum() | |
| return 2 * volume_intersect / volume_sum | |