diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..67d045a
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+@HarryHeres
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3716905..c2bc530 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,9 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Changelog
- Alert when installing Open3D (#3)
- Formatting settings for flake8
+- Codeowners
+- Pipeline steps visualization (#12)
### Changed
- Naming of the generated model based on the selected target node
+- Updated documentation (#11)
### Removed
- Testing STL models
diff --git a/README.md b/README.md
index 89e4682..202de98 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,11 @@
# SlicerBoneMorphing
-
Extension for 3D Slicer for bone mesh morphing.
At the moment, this module specializes for the *humerus* bone, but the use case is not limited to it.
## Special thanks
-Special thanks goes to my wonderful colleagues Eva C. Herbst (@evaherbst) and Arthur Porto (@agporto) for creating the initial idea and their huge help during the development of this module!
-Also, I would like to thank O. Hirose (@ohirose) for the research on BCPD/GBCPD and it's implementation (can be found [here](https://github.com/ohirose/bcpd))
+Special thanks goes to my wonderful colleagues [Eva C. Herbst](https://github.com/evaherbst) and [Arthur Porto](https://github.com/agporto) for creating the initial idea and their huge help during the development of this module!
+Also, I would like to thank [O. Hirose](https://github.com/ohirose) for the research on BCPD/GBCPD and it's implementation (can be found [here](https://github.com/ohirose/bcpd))
## Installation
**Supported platforms:**
@@ -15,97 +14,17 @@ Also, I would like to thank O. Hirose (@ohirose) for the research on BCPD/GBCPD
- MacOS (both x86_64 and ARM; Slicer runs through Rosetta on ARM-based Macs)
Steps:
-- Download the latest ZIP package from Releases
+- Download the latest ZIP package from [Releases](https://github.com/HarryHeres/SlicerBoneMorphing/releases)
- Extract the ZIP contents to your desired folder
- Open up 3D Slicer, go to Edit -> Application Settings
- In the modules section, add the extracted contents' path to "Additional Module Paths"
- Restart 3D Slicer
-> **DISCLAIMER! After restarting, the installation process will begin. If there are any Python modules not available in Slicer, they will be installed, so the startup will take SIGNIFICANTLY MORE amount of time. Do not be scared, this is intended behaviour.**
-
## Usage
-After a successful install, the module will be available in the **Morphing** section.
-When switching to the module, you should be greeted with the following UI:
-
-
-
-
-
-The UI consists of **4** main sections
-- Input
-- Preprocessing
-- Generation
-- Postprocessing
-
-## Architecture
-
-
-
-
-## Module sections
-
-### Input section
-This section is self-explanatory. Here, you choose two input models:
-- Source = The mean model, i.e. a full humerus
-- Target = Partial model to be reconstructed
-
-### Preprocessing section
-
-Before the generation process, we want to preprocess the model.
-First of all is the option of downsampling. For this, you can configure the threshold for downsampling by the following parameter:
-- **Downsampling distance threshold**
- - If set to 0.0, no downsampling is performed
-
-After the downsampling, we compute the normals of the point cloud.
-The computation needs a radius for which the normals are calculated and maximum number of neighbours.
-These can be adjusted with the following parameters:
-- **Normals estimation radius** - maximum radius in which points are considered neighbouring
-- **Normals estimation max neighbours** - maximum number of neighbours taken into account
-
-Also, we need to calculate a *(Fast) point feature histogram* in order to encode the local geometric properties of the models.
-This method uses the following parameters:
-- **FPFH search radius** - maximum radius in which points are considered neighbouring
-- **FPFH max neighbours** - maximum number of neighbours taken into account
-
-#### Registration
-At this moment we have our models preprocessed and ready for the next step, which is the registration.
-Here we calculate the rigid alignment of the models in order to pre-align them.
-The concrete method we use is called **RANSAC** (random sample consensus).
-The behaviour of this algorithm can be adjusted by the following parameters:
-- **Max iterations**
-- **Distance threshold** - maximum distance in which points are considered neighbouring
-- **Fitness threshold** - the lowest fitness between the models to be accepted.
-
-The computed fit by the RANSAC algorithm is a bit "raw". To improve it further, we perform the **ICP** (Iterative closest points) algorithm.
-This can be tuned by the following parameter:
-- **ICP Distance threshold** - maximum distance in which points are considered neighbouring
-
-### Reconstruction section
-Since we now have a preprocessed meshes and with defined transformations from the *source* to the *target*, we can proceed to the **reconstruction section**.
-For the reconstruction we use the **BCPD** (Bayesian coherent point drift) algorithm.
-Now, the BCPD allows for very fine adjustments of its behaviour using lots of different parameters.
-For the exact description of their effects, please refer to the official documentation [here](https://github.com/ohirose/bcpd/blob/master/README.md).
-
-> **Note: You do NOT have to perform any kind of installation process, the BCPD and its geodesic variant are already pre-built and preconfigured for immediate use in this module.**
-
-**Not implemented options:**
-- Terminal output
-- File output
-
-### Postprocessing section
-After the model is reconstructed, we include a postprocessing section to slightly modify the result, if necessary.
-For these, we let you modify the following parameters:
-- **Clustering scaling**
- - Scaled size of voxel for within vertices that are clustered together (additionally refer to [here](http://www.open3d.org/docs/0.7.0/python_api/open3d.geometry.simplify_vertex_clustering.html))
- - If set to 1.0, no scaling is performed
-- **Smoothing iterations** - Number of iterations of mesh smoothing
- - If set to 0, no smoothing is applied
-
-After the whole process is done, both the generated mesh (source transformed into target, standalone) and the merged mesh (generated meshes merged with the target; "combined model") are import back into the current Slicer scene.
+After a successful installation, the module will be available in the **Morphing** section in the Modules dropdown menu.
-
-
-
+## How to use
+For guidance on how to use the module, please refer to this [Guide](./docs/how-to-use.md).
## Contributors
A huge thank you to all of the contributors!
diff --git a/SlicerBoneMorphing/Resources/UI/SlicerBoneMorphing.ui b/SlicerBoneMorphing/Resources/UI/SlicerBoneMorphing.ui
index 5f9b7fd..f5ef3fa 100644
--- a/SlicerBoneMorphing/Resources/UI/SlicerBoneMorphing.ui
+++ b/SlicerBoneMorphing/Resources/UI/SlicerBoneMorphing.ui
@@ -1,1341 +1,1416 @@
- UI
-
-
-
- 0
- 0
- 564
- 1257
-
-
-
- -
-
-
- Input
-
-
- true
-
-
- false
-
-
-
-
-
-
- <html><head/><body><p>Select a node that represents the reference (mean) model</p></body></html>
-
-
- Source:
-
-
-
- -
-
-
- false
-
-
- Select a node that represents the reference model
-
-
-
- vtkMRMLModelNode
-
-
-
- true
-
-
-
-
-
-
-
-
-
- -
-
-
- <html><head/><body><p>Select a node that represents the target (impartial) model</p></body></html>
-
-
- Target:
-
-
-
- -
-
-
- Select a node that represents the target model (the one to be deformed)
-
-
-
- vtkMRMLModelNode
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Preprocessing parameters
-
-
- true
-
-
- false
-
-
-
-
-
-
- Point cloud preprocessing
-
-
-
-
-
-
- Maximum distance in which points are considered neighbouring
-
-
- Downsampling distance threshold:
-
-
-
- -
-
-
- The higher the number, the lower the distance threshold for the RANSAC registration
-
-
- 100.000000000000000
-
-
- 55.000000000000000
-
-
-
- -
-
-
- Normals estimation radius:
-
-
-
- -
-
-
- 100.000000000000000
-
-
- 4.000000000000000
-
-
-
- -
-
-
- Normals estimation max neighbours:
-
-
-
- -
-
-
- 1
-
-
- 1000
-
-
- 100
-
-
-
- -
-
-
- FPFH search radius:
-
-
-
- -
-
-
- 100.000000000000000
-
-
- 10.000000000000000
-
-
-
- -
-
-
- FPFH max neighbours:
-
-
-
- -
-
-
- 1
-
-
- 1000
-
-
- 30
-
-
-
-
-
-
- -
-
-
- Registration
-
-
-
-
-
-
- Distance threshold:
-
-
-
- -
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
- The higher the number, the longer the registration process will take, but higher the chance to converge to a fit solution
-
-
- Max iterations:
-
-
-
- -
-
-
- The higher the number, the longer the registration process will take, but higher the chance to converge to a fit solution
-
-
- 1
-
-
- 30
-
-
-
- -
-
-
- Fitness threshold:
-
-
-
- -
-
-
- 8
-
-
- 1.000000000000000
-
-
- 0.000100000000000
-
-
- 0.999000000000000
-
-
-
- -
-
-
- ICP Distance threshold:
-
-
-
- -
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
-
-
-
-
-
-
- -
-
-
- BCPD parameters
-
-
- false
-
-
- true
-
-
-
-
-
-
- Tuning parameters
-
-
- true
-
-
- false
-
-
-
-
-
-
- Omega. Outlier probability in (0,1).
-
-
- Outlier probability (omega):
-
-
-
- -
-
-
- Omega. Outlier probability in (0,1).
-
-
-
-
-
- 3
-
-
- 0.001000000000000
-
-
- 0.999000000000000
-
-
- 0.001000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Lambda. Positive. It controls the expected length of deformation vectors. Smaller is longer.
-
-
- Deformation vector length (lambda):
-
-
-
- -
-
-
- 3
-
-
- 100000.000000000000000
-
-
- 10.000000000000000
-
-
-
- -
-
-
- Beta. Positive. It controls the range where deformation vectors are smoothed.
-
-
- Deformation smoothing range (beta):
-
-
-
- -
-
-
- 3
-
-
- 100.000000000000000
-
-
- 10.000000000000000
-
-
-
- -
-
-
- Gamma. Positive. It defines the randomness of the point matching at the beginning of the optimization.
-
-
- Point matching randomness (gamma):
-
-
-
- -
-
-
- Gamma. Positive. It defines the randomness of the point matching at the beginning of the optimization.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 0.100000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Kappa. Positive. It controls the randomness of mixing coefficients.
-
-
- Mixing coefficient randomness (kappa):
-
-
-
- -
-
-
- Kappa. Positive. It controls the randomness of mixing coefficients. Value 1000 is considered "infinity"
-
-
- 3
-
-
- 1000.000000000000000
-
-
- 1000.000000000000000
-
-
-
-
-
-
- -
-
-
- false
-
-
- Show more granular controls over the BCPD algorithm. DISCLAIMER: USE WITH CAUTION!
-
-
- Show advanced controls
-
-
-
- -
-
-
- Advanced controls
-
-
-
-
-
-
- Kernel parameters
-
-
- true
-
-
- false
-
-
- true
-
-
-
-
-
-
- Geodesic Kernel
-
-
-
-
-
-
- Tau. The rate controlling the balance between geodesic and Gaussian kernels.
-
-
- Kernel balance rate (tau):
-
-
-
- -
-
-
- I have an input mesh
-
-
-
- -
-
-
- The file that defines a triangle mesh.
-
-
- Input mesh path:
-
-
-
- -
-
-
- The number of neighbors for each node, required for k-NN graph construction.
-
-
- kNN neighbours
-
-
-
- -
-
-
- The number of neighbors for each node, required for k-NN graph construction.
-
-
- 10
-
-
-
- -
-
-
- The file that defines a triangle mesh.
-
-
- Absolute path to the input mesh file
-
-
-
- -
-
-
- The radius that defines neighbors for each node, required for k-NN graph construction.
-
-
- kNN neighbor radius
-
-
-
- -
-
-
- The radius that defines neighbors for each node, required for k-NN graph construction.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 10.000000000000000
-
-
-
- -
-
-
- Beta. Positive. Gaussian function's width.
-
-
- Gaussian function width (beta):
-
-
-
- -
-
-
- Beta. Positive. Gaussian function's width.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
- K tilde. Positive. Rank constraint on G.
-
-
- Rank constraint (K tilde):
-
-
-
- -
-
-
- K tilde. Positive. Rank constraint on G.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
- Epsilon. Positive. Acceptable condition number of G.
-
-
- Acceptable condition number (epsilon):
-
-
-
- -
-
-
- Epsilon. Positive. Acceptable condition number of G.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
-
-
-
-
- -
-
-
- Standard kernel
-
-
-
-
-
-
- Kernel type:
-
-
-
- -
-
-
-
-
-
- -
-
-
- Kernel type:
-
-
-
- -
-
-
-
-
-
- -
-
-
- Acceleration
-
-
- true
-
-
- false
-
-
-
-
-
-
- Mode:
-
-
-
- -
-
-
- Manual acceleration methods. For optimal convergence, use both Nystorm and KD Tree search
-
-
- Manual acceleration
-
-
- false
-
-
-
-
-
-
- Nystorm method
-
-
- true
-
-
- true
-
-
-
-
-
-
- Samples for computing G
-
-
-
- -
-
-
- 1000000
-
-
- 70
-
-
-
- -
-
-
- Samples for computing J
-
-
-
- -
-
-
- 1000000
-
-
- 300
-
-
-
- -
-
-
- Random number seed for the Nystrom method. Reproducibility is guaranteed if the same number is specified.
-
-
- Randomness seed
-
-
-
- -
-
-
- Random number seed for the Nystrom method. Reproducibility is guaranteed if the same number is specified.
-
-
- 1
-
-
- 1000000
-
-
-
-
-
-
- -
-
-
- KD Tree Search
-
-
- true
-
-
- true
-
-
-
-
-
-
- Scale factor of sigma that defines areas to search for neighbors.
-
-
- Scale factor:
-
-
-
- -
-
-
- Scale factor of sigma that defines areas to search for neighbors.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 1.000000000000000
-
-
- 7.000000000000000
-
-
-
- -
-
-
- Maximum radius to search for neighbors.
-
-
- Maximum radius
-
-
-
- -
-
-
- Maximum radius to search for neighbors.
-
-
- 0.150000000000000
-
-
-
- -
-
-
- The value of sigma at which the KD tree search is turned on.
-
-
- Sigma threshold:
-
-
-
- -
-
-
- The value of sigma at which the KD tree search is turned on.
-
-
- 3
-
-
- 100.000000000000000
-
-
- 0.200000000000000
-
-
-
-
-
-
-
-
-
- -
-
-
- Automatic acceleration
-
-
-
-
-
-
- Variational Bazes Inference acceleration
-
-
- VBI acceleration
-
-
- true
-
-
-
- -
-
-
- Downsampling and deformation vector interpolation
-
-
- BCPD++ acceleration
-
-
- true
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
- Note: Downsampling automaticallz activates the deformation vecttor interpolation
-
-
- Downsampling
-
-
- true
-
-
- false
-
-
- true
-
-
-
-
-
-
- Downsampling options. For syntax, please check the documentation
-
-
- Options:
-
-
-
- -
-
-
- Downsampling options. For syntax, please check the documentation
-
-
- B,5000,0.08
-
-
-
-
-
-
- -
-
-
- Convergence
-
-
- true
-
-
- false
-
-
-
-
-
-
- Tolerance:
-
-
-
- -
-
-
- 8
-
-
- 1.000000000000000
-
-
- 0.000100000000000
-
-
- 0.000100000000000
-
-
-
- -
-
-
- Max number of iterations:
-
-
-
- -
-
-
- 1
-
-
- 1000000
-
-
- 1000
-
-
-
- -
-
-
- 1
-
-
- 1000
-
-
- 30
-
-
-
- -
-
-
- Min number of iterations:
-
-
-
-
-
-
- -
-
-
- Normalization
-
-
- false
-
-
-
-
-
-
- Please, refer to the documentation for the explanation of choices
-
-
- Options:
-
-
-
- -
-
-
- Please, refer to the documentation for the explanation of choices
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Postprocessing parameters
-
-
- false
-
-
-
-
-
-
- Clustering scaling:
-
-
-
- -
-
-
- 0.000000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
- Smoothing iterations:
-
-
-
- -
-
-
- 0
-
-
- 1000
-
-
-
-
-
-
- -
-
-
- Reset parameters to default
-
-
-
- -
-
-
- true
-
-
- Generate
-
-
-
-
-
-
-
- ctkCollapsibleButton
- QWidget
-
- 1
-
-
- ctkCollapsibleGroupBox
- QGroupBox
-
- 1
-
-
- qMRMLNodeComboBox
- QWidget
-
-
-
- qMRMLWidget
- QWidget
-
- 1
-
-
-
-
-
- UI
- mrmlSceneChanged(vtkMRMLScene*)
- sourceNodeSelectionBox
- setMRMLScene(vtkMRMLScene*)
-
-
- 272
- 237
-
-
- 335
- 57
-
-
-
-
- bcpdAdvancedParametersCheckBox
- toggled(bool)
- bcpdAdvancedControlsGroupBox
- setVisible(bool)
-
-
- 114
- 577
-
-
- 274
- 1065
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelInputMeshLabel
- setVisible(bool)
-
-
- 156
- 818
-
-
- 132
- 847
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelInputMeshLineEdit
- setVisible(bool)
-
-
- 156
- 818
-
-
- 611
- 847
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelNeighboursLabel
- setHidden(bool)
-
-
- 156
- 818
-
-
- 130
- 878
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelNeighboursSpinBox
- setHidden(bool)
-
-
- 156
- 818
-
-
- 611
- 878
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelRadiusLabel
- setHidden(bool)
-
-
- 156
- 818
-
-
- 145
- 910
-
-
-
-
- bcpdGeodesicKernelInputMeshCheckBox
- toggled(bool)
- bcpdGeodesicKernelRadiusDoubleSpinBox
- setHidden(bool)
-
-
- 156
- 818
-
-
- 611
- 910
-
-
-
-
- bcpdAccelerationAutomaticPlusPlusCheckBox
- toggled(bool)
- bcpdDownsamplingCollapsibleGroupBox
- setHidden(bool)
-
-
- 134
- 1207
-
-
- 102
- 1145
-
-
-
-
+ UI
+
+
+
+ 0
+ 0
+ 638
+ 1158
+
+
+
+ -
+
+
+ Visualization
+
+
+ true
+
+
+
-
+
+
+ If checked, the pipeline steps will be visualized using Open3D
+
+
+ Visualize pipeline steps
+
+
+
+ -
+
+
+ Coloring
+
+
+
-
+
+
+ -
+
+
+ Source model color
+
+
+
+ -
+
+
+ Target model color
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+ Input
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ <html><head/><body><p>Select a node that represents the reference (mean) model</p></body></html>
+
+
+ Source:
+
+
+
+ -
+
+
+ false
+
+
+ Select a node that represents the reference model
+
+
+
+ vtkMRMLModelNode
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ -
+
+
+ <html><head/><body><p>Select a node that represents the target (impartial) model</p></body></html>
+
+
+ Target:
+
+
+
+ -
+
+
+ Select a node that represents the target model (the one to be deformed)
+
+
+
+ vtkMRMLModelNode
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Preprocessing
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ Point cloud preprocessing
+
+
+
-
+
+
+ Maximum distance in which points are considered neighbouring
+
+
+ Downsampling voxel size
+
+
+
+ -
+
+
+ The higher the number, the lower the distance threshold for the RANSAC registration
+
+
+ 100.000000000000000
+
+
+ 0.000000000000000
+
+
+
+ -
+
+
+ Normals estimation radius:
+
+
+
+ -
+
+
+ 100.000000000000000
+
+
+ 4.000000000000000
+
+
+
+ -
+
+
+ Normals estimation max neighbours:
+
+
+
+ -
+
+
+ 1
+
+
+ 1000
+
+
+ 100
+
+
+
+ -
+
+
+ FPFH search radius:
+
+
+
+ -
+
+
+ 100.000000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+ FPFH max neighbours:
+
+
+
+ -
+
+
+ 1
+
+
+ 1000
+
+
+ 30
+
+
+
+
+
+
+ -
+
+
+ Registration
+
+
+
-
+
+
+ Distance threshold:
+
+
+
+ -
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ The higher the number, the longer the registration process will take, but higher the chance to converge to a fit solution
+
+
+ Max iterations:
+
+
+
+ -
+
+
+ The higher the number, the longer the registration process will take, but higher the chance to converge to a fit solution
+
+
+ 1
+
+
+ 1000000
+
+
+ 100000
+
+
+
+ -
+
+
+ Fitness threshold:
+
+
+
+ -
+
+
+ 8
+
+
+ 1.000000000000000
+
+
+ 0.000100000000000
+
+
+ 0.999000000000000
+
+
+
+ -
+
+
+ ICP Distance threshold:
+
+
+
+ -
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+
+
+
+
+
+
+ -
+
+
+ BCPD
+
+
+ false
+
+
+ true
+
+
+
-
+
+
+ Tuning parameters
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ Omega. Outlier probability in (0,1).
+
+
+ Outlier probability (omega):
+
+
+
+ -
+
+
+ Omega. Outlier probability in (0,1).
+
+
+
+
+
+ 3
+
+
+ 0.001000000000000
+
+
+ 0.999000000000000
+
+
+ 0.001000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+ Lambda. Positive. It controls the expected length of deformation vectors. Smaller is longer.
+
+
+ Deformation vector length (lambda):
+
+
+
+ -
+
+
+ 3
+
+
+ 100000.000000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+ Beta. Positive. It controls the range where deformation vectors are smoothed.
+
+
+ Deformation smoothing range (beta):
+
+
+
+ -
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+ Gamma. Positive. It defines the randomness of the point matching at the beginning of the optimization.
+
+
+ Point matching randomness (gamma):
+
+
+
+ -
+
+
+ Gamma. Positive. It defines the randomness of the point matching at the beginning of the optimization.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 0.100000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+ Kappa. Positive. It controls the randomness of mixing coefficients.
+
+
+ Mixing coefficient randomness (kappa):
+
+
+
+ -
+
+
+ Kappa. Positive. It controls the randomness of mixing coefficients. Value 1000 is considered "infinity"
+
+
+ 3
+
+
+ 1000.000000000000000
+
+
+ 1000.000000000000000
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Show more granular controls over the BCPD algorithm. DISCLAIMER: USE WITH CAUTION!
+
+
+ Show advanced controls
+
+
+
+ -
+
+
+ Advanced controls
+
+
+
-
+
+
+ Kernel parameters
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
-
+
+
+ Geodesic Kernel
+
+
+
-
+
+
+ Tau. The rate controlling the balance between geodesic and Gaussian kernels.
+
+
+ Kernel balance rate (tau):
+
+
+
+ -
+
+
+ I have an input mesh
+
+
+
+ -
+
+
+ The file that defines a triangle mesh.
+
+
+ Input mesh path:
+
+
+
+ -
+
+
+ The number of neighbors for each node, required for k-NN graph construction.
+
+
+ kNN neighbours
+
+
+
+ -
+
+
+ The number of neighbors for each node, required for k-NN graph construction.
+
+
+ 10
+
+
+
+ -
+
+
+ The file that defines a triangle mesh.
+
+
+ Absolute path to the input mesh file
+
+
+
+ -
+
+
+ The radius that defines neighbors for each node, required for k-NN graph construction.
+
+
+ kNN neighbor radius
+
+
+
+ -
+
+
+ The radius that defines neighbors for each node, required for k-NN graph construction.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+ Beta. Positive. Gaussian function's width.
+
+
+ Gaussian function width (beta):
+
+
+
+ -
+
+
+ Beta. Positive. Gaussian function's width.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ K tilde. Positive. Rank constraint on G.
+
+
+ Rank constraint (K tilde):
+
+
+
+ -
+
+
+ K tilde. Positive. Rank constraint on G.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Epsilon. Positive. Acceptable condition number of G.
+
+
+ Acceptable condition number (epsilon):
+
+
+
+ -
+
+
+ Epsilon. Positive. Acceptable condition number of G.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+
+
+
+
+ -
+
+
+ Standard kernel
+
+
+
-
+
+
+ Kernel type:
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ Kernel type:
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ Acceleration
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ Mode:
+
+
+
+ -
+
+
+ Manual acceleration methods. For optimal convergence, use both Nystorm and KD Tree search
+
+
+ Manual acceleration
+
+
+ false
+
+
+
-
+
+
+ Nystorm method
+
+
+ true
+
+
+ true
+
+
+
-
+
+
+ Samples for computing G
+
+
+
+ -
+
+
+ 1000000
+
+
+ 70
+
+
+
+ -
+
+
+ Samples for computing J
+
+
+
+ -
+
+
+ 1000000
+
+
+ 300
+
+
+
+ -
+
+
+ Random number seed for the Nystrom method. Reproducibility is guaranteed if the same number is specified.
+
+
+ Randomness seed
+
+
+
+ -
+
+
+ Random number seed for the Nystrom method. Reproducibility is guaranteed if the same number is specified.
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+
+ -
+
+
+ KD Tree Search
+
+
+ true
+
+
+ true
+
+
+
-
+
+
+ Scale factor of sigma that defines areas to search for neighbors.
+
+
+ Scale factor:
+
+
+
+ -
+
+
+ Scale factor of sigma that defines areas to search for neighbors.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 1.000000000000000
+
+
+ 7.000000000000000
+
+
+
+ -
+
+
+ Maximum radius to search for neighbors.
+
+
+ Maximum radius
+
+
+
+ -
+
+
+ Maximum radius to search for neighbors.
+
+
+ 0.150000000000000
+
+
+
+ -
+
+
+ The value of sigma at which the KD tree search is turned on.
+
+
+ Sigma threshold:
+
+
+
+ -
+
+
+ The value of sigma at which the KD tree search is turned on.
+
+
+ 3
+
+
+ 100.000000000000000
+
+
+ 0.200000000000000
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Automatic acceleration
+
+
+
-
+
+
+ Variational Bazes Inference acceleration
+
+
+ VBI acceleration
+
+
+ true
+
+
+
+ -
+
+
+ Downsampling and deformation vector interpolation
+
+
+ BCPD++ acceleration
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ Note: Downsampling automaticallz activates the deformation vecttor interpolation
+
+
+ Downsampling
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
-
+
+
+ Downsampling options. For syntax, please check the documentation
+
+
+ Options:
+
+
+
+ -
+
+
+ Downsampling options. For syntax, please check the documentation
+
+
+ B,5000,0.08
+
+
+
+
+
+
+ -
+
+
+ Convergence
+
+
+ true
+
+
+ false
+
+
+
-
+
+
+ Tolerance:
+
+
+
+ -
+
+
+ 8
+
+
+ 1.000000000000000
+
+
+ 0.000100000000000
+
+
+ 0.000100000000000
+
+
+
+ -
+
+
+ Max number of iterations:
+
+
+
+ -
+
+
+ 1
+
+
+ 1000000
+
+
+ 1000
+
+
+
+ -
+
+
+ 1
+
+
+ 1000
+
+
+ 30
+
+
+
+ -
+
+
+ Min number of iterations:
+
+
+
+
+
+
+ -
+
+
+ Normalization
+
+
+ false
+
+
+
-
+
+
+ Please, refer to the documentation for the explanation of choices
+
+
+ Options:
+
+
+
+ -
+
+
+ Please, refer to the documentation for the explanation of choices
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Postprocessing
+
+
+ false
+
+
+
-
+
+
+ Clustering scaling:
+
+
+
+ -
+
+
+ 0.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Smoothing iterations:
+
+
+
+ -
+
+
+ 0
+
+
+ 1000
+
+
+
+
+
+
+ -
+
+
+ Reset parameters to default
+
+
+
+ -
+
+
+ true
+
+
+ Generate
+
+
+
+
+
+
+
+ ctkCollapsibleButton
+ QWidget
+
+ 1
+
+
+ ctkCollapsibleGroupBox
+ QGroupBox
+
+ 1
+
+
+ ctkColorPickerButton
+ QPushButton
+
+
+
+ qMRMLNodeComboBox
+ QWidget
+
+
+
+ qMRMLWidget
+ QWidget
+
+ 1
+
+
+
+
+
+ UI
+ mrmlSceneChanged(vtkMRMLScene*)
+ sourceNodeSelectionBox
+ setMRMLScene(vtkMRMLScene*)
+
+
+ 272
+ 237
+
+
+ 335
+ 57
+
+
+
+
+ bcpdAdvancedParametersCheckBox
+ toggled(bool)
+ bcpdAdvancedControlsGroupBox
+ setVisible(bool)
+
+
+ 114
+ 577
+
+
+ 274
+ 1065
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelInputMeshLabel
+ setVisible(bool)
+
+
+ 156
+ 818
+
+
+ 132
+ 847
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelInputMeshLineEdit
+ setVisible(bool)
+
+
+ 156
+ 818
+
+
+ 611
+ 847
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelNeighboursLabel
+ setHidden(bool)
+
+
+ 156
+ 818
+
+
+ 130
+ 878
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelNeighboursSpinBox
+ setHidden(bool)
+
+
+ 156
+ 818
+
+
+ 611
+ 878
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelRadiusLabel
+ setHidden(bool)
+
+
+ 156
+ 818
+
+
+ 145
+ 910
+
+
+
+
+ bcpdGeodesicKernelInputMeshCheckBox
+ toggled(bool)
+ bcpdGeodesicKernelRadiusDoubleSpinBox
+ setHidden(bool)
+
+
+ 156
+ 818
+
+
+ 611
+ 910
+
+
+
+
+ bcpdAccelerationAutomaticPlusPlusCheckBox
+ toggled(bool)
+ bcpdDownsamplingCollapsibleGroupBox
+ setHidden(bool)
+
+
+ 134
+ 1207
+
+
+ 102
+ 1145
+
+
+
+
+ visualizationVisualizeCheckBox
+ toggled(bool)
+ visualizationModelColorGroupBox
+ setVisible(bool)
+
+
+ 163
+ 44
+
+
+ 318
+ 192
+
+
+
+
diff --git a/SlicerBoneMorphing/SlicerBoneMorphing.py b/SlicerBoneMorphing/SlicerBoneMorphing.py
index f92b054..f8a8860 100644
--- a/SlicerBoneMorphing/SlicerBoneMorphing.py
+++ b/SlicerBoneMorphing/SlicerBoneMorphing.py
@@ -16,7 +16,9 @@ def __init__(self, parent):
self.parent.helpText = """
This module gives a user ability to recreate bone mesh models based on their partial scan.
- Please, start with importing your model and checking out the options on the left side afterwards."""
+ Please, start with importing your model and checking out the options on the left side afterwards.
+ Version: 0.2.0-rc.1
+ """
self.parent.acknowledgementText = """
Credits: Jan Heres
diff --git a/SlicerBoneMorphing/src/logic/Constants.py b/SlicerBoneMorphing/src/logic/Constants.py
index b59a5a0..4b8c5ac 100644
--- a/SlicerBoneMorphing/src/logic/Constants.py
+++ b/SlicerBoneMorphing/src/logic/Constants.py
@@ -1,17 +1,47 @@
### RETURN VALUES ###
from src.logic.Enums import BcpdAccelerationMode, BcpdKernelType, BcpdNormalizationOptions, BcpdStandardKernel
+import qt
EXIT_OK = 0
EXIT_FAILURE = 1
BCPD_MULTIPLE_VALUES_SEPARATOR = ","
-"""
- Used when one parameter have multiple values, e.g. -G [string,real,file]
-"""
-VALUE_NODE_NOT_SELECTED = 0 # Via Slicer documentation
+VISUALIZATION_KEY = "visualization"
+VISUALIZATION_KEY_SHOULD_VISUALIZE = "sv"
+VISUALIZATION_KEY_SOURCE_MODEL_COLOR = "smc"
+VISUALIZATION_KEY_TARGET_MODEL_COLOR = "tmc"
-### BCPD PARAMETERS###
+VISUALIZATION_DEFAULT_VALUE_SOURCE_MODEL_COLOR = qt.QColor(255, 0, 0, 0)
+VISUALIZATION_DEFAULT_VALUE_TARGET_MODEL_COLOR = qt.QColor(0, 255, 0, 0)
+
+### PREPROCESSING PARAMETERS ###
+PREPROCESSING_KEY = "preprocessing"
+PREPROCESSING_KEY_DOWNSAMPLING_VOXEL_SIZE = "dvs"
+PREPROCESSING_KEY_NORMALS_ESTIMATION_RADIUS = "ner"
+PREPROCESSING_KEY_FPFH_ESTIMATION_RADIUS = "fer"
+PREPROCESSING_KEY_MAX_NN_NORMALS = "mnnn"
+PREPROCESSING_KEY_MAX_NN_FPFH = "mnf"
+
+PREPROCESSING_DEFAULT_VALUE_DOWNSAMPLING_VOXEL_SIZE = 0.0
+PREPROCESSING_DEFAULT_VALUE_RADIUS_NORMAL_SCALE = 0.5
+PREPROCESSING_DEFAULT_VALUE_RADIUS_FEATURE_SCALE = 10
+PREPROCESSING_DEFAULT_VALUE_MAX_NN_NORMALS = 10
+PREPROCESSING_DEFAULT_VALUE_MAX_NN_FPFH = 100
+
+### REGISTRATION PARAMETERS ###
+REGISTRATION_KEY_DISTANCE_THRESHOLD = "rdt"
+REGISTRATION_KEY_FITNESS_THRESHOLD = "rft"
+REGISTRATION_KEY_MAX_ITERATIONS = "rmi"
+REGISTRATION_KEY_ICP_DISTANCE_THRESHOLD = "idt"
+
+REGISTRATION_DEFAULT_VALUE_DISTANCE_THRESHOLD = 1
+REGISTRATION_DEFAULT_VALUE_FITNESS_THRESHOLD = 0.999
+REGISTRATION_DEFAULT_VALUE_MAX_ITERATIONS = 100000
+REGISTRATION_DEFAULT_VALUE_ICP_DISTANCE_THRESHOLD = 1
+REGISTRATION_DEFAULT_VALUE_RANSAC_CONVERGENCE_CONFIDENCE = 1.0 # Leave at 1.0 to NOT terminate early
+
+### BCPD PARAMETERS ###
BCPD_KEY = "bcpd"
## Tuning ##
@@ -83,31 +113,6 @@
## Normalization ##
BCPD_DEFAULT_VALUE_NORMALIZATION_OPTIONS = BcpdNormalizationOptions.X.value
-### PREPROCESSING PARAMETERS ###
-PREPROCESSING_KEY = "preprocessing"
-PREPROCESSING_KEY_DOWNSAMPLING_DISTANCE_THRESHOLD = "ddt"
-PREPROCESSING_KEY_NORMALS_ESTIMATION_RADIUS = "ner"
-PREPROCESSING_KEY_FPFH_ESTIMATION_RADIUS = "fer"
-PREPROCESSING_KEY_MAX_NN_NORMALS = "mnnn"
-PREPROCESSING_KEY_MAX_NN_FPFH = "mnf"
-
-PREPROCESSING_DEFAULT_VALUE_DOWNSAMPLING_DISTANCE_THRESHOLD = 0.05
-PREPROCESSING_DEFAULT_VALUE_RADIUS_NORMAL_SCALE = 0.5
-PREPROCESSING_DEFAULT_VALUE_RADIUS_FEATURE_SCALE = 10
-PREPROCESSING_DEFAULT_VALUE_MAX_NN_NORMALS = 10
-PREPROCESSING_DEFAULT_VALUE_MAX_NN_FPFH = 100
-
-### REGISTRATION PARAMETERS ###
-REGISTRATION_KEY_DISTANCE_THRESHOLD = "rdt"
-REGISTRATION_KEY_FITNESS_THRESHOLD = "rft"
-REGISTRATION_KEY_MAX_ITERATIONS = "rmi"
-REGISTRATION_KEY_ICP_DISTANCE_THRESHOLD = "idt"
-
-REGISTRATION_DEFAULT_VALUE_DISTANCE_THRESHOLD = 1
-REGISTRATION_DEFAULT_VALUE_FITNESS_THRESHOLD = 0.999
-REGISTRATION_DEFAULT_VALUE_MAX_ITERATIONS = 30
-REGISTRATION_DEFAULT_VALUE_ICP_DISTANCE_THRESHOLD = 1
-
### POSTPROCESSING PARAMETERS ###
POSTPROCESSING_KEY = "postprocessing"
POSTPROCESSING_KEY_CLUSTERING_SCALING = "cs"
diff --git a/SlicerBoneMorphing/src/logic/Enums.py b/SlicerBoneMorphing/src/logic/Enums.py
index 751d850..957b942 100644
--- a/SlicerBoneMorphing/src/logic/Enums.py
+++ b/SlicerBoneMorphing/src/logic/Enums.py
@@ -1,8 +1,10 @@
from enum import Enum
+
class BcpdKernelType(Enum):
- STANDARD = 0
- GEODESIC = 1
+ STANDARD = 0
+ GEODESIC = 1
+
class BcpdStandardKernel(Enum):
G0 = 0
@@ -10,12 +12,14 @@ class BcpdStandardKernel(Enum):
G2 = 2
G3 = 3
+
class BcpdNormalizationOptions(Enum):
E = 0
- X = 1
+ X = 1
Y = 2
N = 3
+
class BcpdAccelerationMode(Enum):
AUTOMATIC = 0
- MANUAL = 1
+ MANUAL = 1
diff --git a/SlicerBoneMorphing/src/logic/SlicerBoneMorphingLogic.py b/SlicerBoneMorphing/src/logic/SlicerBoneMorphingLogic.py
index 8a432bf..152e6f8 100644
--- a/SlicerBoneMorphing/src/logic/SlicerBoneMorphingLogic.py
+++ b/SlicerBoneMorphing/src/logic/SlicerBoneMorphingLogic.py
@@ -33,26 +33,23 @@
elif platform == "win32":
BCPD_EXEC += "bcpd_win32.exe"
-SOURCE_VISUALIZATION_COLOR = [0, 1, 0]
-TARGET_VISUALIZATION_COLOR = [1, 0, 0]
-
class SlicerBoneMorphingLogic(ScriptedLoadableModuleLogic):
def __init__(self, parent=None):
ScriptedLoadableModuleLogic.__init__(self, parent)
- def __visualize(self, source, target):
+ def __visualize(self, source, target, window_name: str = "", source_color=const.VISUALIZATION_DEFAULT_VALUE_TARGET_MODEL_COLOR, target_color=const.VISUALIZATION_KEY_TARGET_MODEL_COLOR):
models = []
if (source is not None):
- source.paint_uniform_color(SOURCE_VISUALIZATION_COLOR)
+ source.paint_uniform_color(np.array([source_color.red() / 255, source_color.green() / 255, source_color.blue() / 255]))
models.append(source)
if (target is not None):
- target.paint_uniform_color(TARGET_VISUALIZATION_COLOR)
+ target.paint_uniform_color(np.array([target_color.red() / 255, target_color.green() / 255, target_color.blue() / 255]))
models.append(target)
- o3d.visualization.draw_geometries(models)
+ o3d.visualization.draw_geometries(models, window_name=window_name, mesh_show_wireframe=True, point_show_normal=True)
def generate_model(
self,
@@ -75,11 +72,6 @@ def generate_model(
- status: EXIT_OK or EXIT_FAILURE
- generatedPolydata: Generated model by the BCPD
"""
-
- if (source_model == const.VALUE_NODE_NOT_SELECTED or target_model == const.VALUE_NODE_NOT_SELECTED):
- print("Input or foundation model(s) were not selected")
- return const.EXIT_FAILURE, None
-
source_mesh = self.__convert_model_to_mesh(source_model)
target_mesh = self.__convert_model_to_mesh(target_model)
@@ -90,17 +82,24 @@ def generate_model(
source_mesh.transform(result_icp.transformation)
- # self.__visualize(source_mesh, target_mesh)
+ visualization_params = parameters[const.VISUALIZATION_KEY]
+
+ if (visualization_params[const.VISUALIZATION_KEY_SHOULD_VISUALIZE] is True):
+ self.__visualize(source_mesh, target_mesh, "Preprocessed models", visualization_params[const.VISUALIZATION_KEY_SOURCE_MODEL_COLOR], visualization_params[const.VISUALIZATION_KEY_TARGET_MODEL_COLOR])
# BCPD stage
deformed = self.__deformable_registration(source_mesh, target_mesh, parameters[const.BCPD_KEY])
if (deformed is None):
return const.EXIT_FAILURE, None
- # self.__visualize(deformed, None)
+ if (visualization_params[const.VISUALIZATION_KEY_SHOULD_VISUALIZE] is True):
+ self.__visualize(deformed, None, "Reconstructed model", visualization_params[const.VISUALIZATION_KEY_SOURCE_MODEL_COLOR], visualization_params[const.VISUALIZATION_KEY_TARGET_MODEL_COLOR])
generated_polydata = self.__postprocess_meshes(deformed, parameters[const.POSTPROCESSING_KEY])
+ if (visualization_params[const.VISUALIZATION_KEY_SHOULD_VISUALIZE] is True):
+ self.__visualize(deformed, None, "Postprocessed model", visualization_params[const.VISUALIZATION_KEY_SOURCE_MODEL_COLOR], visualization_params[const.VISUALIZATION_KEY_TARGET_MODEL_COLOR])
+
return const.EXIT_OK, generated_polydata
def __convert_mesh_to_vtk_polydata(self, mesh: o3d.geometry.TriangleMesh) -> vtk.vtkPolyData:
@@ -215,7 +214,7 @@ def __preprocess_model(
source_pcd_downsampled, source_pcd_fpfh = self.__preprocess_point_cloud(
source_pcd,
- parameters[const.PREPROCESSING_KEY_DOWNSAMPLING_DISTANCE_THRESHOLD],
+ parameters[const.PREPROCESSING_KEY_DOWNSAMPLING_VOXEL_SIZE],
parameters[const.PREPROCESSING_KEY_NORMALS_ESTIMATION_RADIUS],
parameters[const.PREPROCESSING_KEY_FPFH_ESTIMATION_RADIUS],
parameters[const.PREPROCESSING_KEY_MAX_NN_NORMALS],
@@ -224,7 +223,7 @@ def __preprocess_model(
target_pcd_downsampled, target_pcd_fpfh = self.__preprocess_point_cloud(
target_pcd,
- parameters[const.PREPROCESSING_KEY_DOWNSAMPLING_DISTANCE_THRESHOLD],
+ parameters[const.PREPROCESSING_KEY_DOWNSAMPLING_VOXEL_SIZE],
parameters[const.PREPROCESSING_KEY_NORMALS_ESTIMATION_RADIUS],
parameters[const.PREPROCESSING_KEY_FPFH_ESTIMATION_RADIUS],
parameters[const.PREPROCESSING_KEY_MAX_NN_NORMALS],
@@ -257,7 +256,7 @@ def __preprocess_model(
def __preprocess_point_cloud(
self,
pcd: o3d.geometry.PointCloud,
- downsampling_distance_threshold: float,
+ downsampling_voxel_size: float,
normals_estimation_radius: float,
fpfh_estimation_radius: float,
max_nn_normals: int,
@@ -282,8 +281,8 @@ def __preprocess_point_cloud(
- [1] = FPFH
'''
- if downsampling_distance_threshold > 0.0:
- pcd = pcd.voxel_down_sample(downsampling_distance_threshold)
+ if downsampling_voxel_size > 0.0:
+ pcd = pcd.voxel_down_sample(downsampling_voxel_size)
pcd.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=normals_estimation_radius, max_nn=max_nn_normals))
@@ -318,39 +317,26 @@ def __ransac_pcd_registration(
RANSAC registration result
'''
- fitness = 0
- count = 0
- best_result = None
- fitness_max = 1
-
- while (fitness < fitness_threshold and fitness < fitness_max and count < max_iterations):
- result = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(
- source_pcd_down,
- target_pcd_down,
- source_fpfh,
- target_fpfh,
- True,
- distance_threshold,
+ result = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(
+ source_pcd_down,
+ target_pcd_down,
+ source_fpfh,
+ target_fpfh,
+ True,
+ distance_threshold,
+ o3d.pipelines.registration.
+ TransformationEstimationPointToPoint(True),
+ 3,
+ [
o3d.pipelines.registration.
- TransformationEstimationPointToPoint(True),
- 3,
- [
- o3d.pipelines.registration.
- CorrespondenceCheckerBasedOnEdgeLength(0.9),
- o3d.pipelines.registration.
- CorrespondenceCheckerBasedOnDistance(distance_threshold)
- ],
- # NOTE: Just for earlier termination, but still needs the outer loop for proper convergence
- o3d.pipelines.registration.RANSACConvergenceCriteria(100000, fitness_threshold)
- )
-
- if result.fitness > fitness and result.fitness < 1:
- fitness = result.fitness
- best_result = result
-
- count += 1
+ CorrespondenceCheckerBasedOnEdgeLength(0.9),
+ o3d.pipelines.registration.
+ CorrespondenceCheckerBasedOnDistance(distance_threshold)
+ ],
+ o3d.pipelines.registration.RANSACConvergenceCriteria(max_iteration=max_iterations, confidence=const.REGISTRATION_DEFAULT_VALUE_RANSAC_CONVERGENCE_CONFIDENCE)
+ )
- return best_result
+ return result
def __deformable_registration(
self,
diff --git a/SlicerBoneMorphing/src/widget/SlicerBoneMorphingWidget.py b/SlicerBoneMorphing/src/widget/SlicerBoneMorphingWidget.py
index 230ee43..460a0b8 100644
--- a/SlicerBoneMorphing/src/widget/SlicerBoneMorphingWidget.py
+++ b/SlicerBoneMorphing/src/widget/SlicerBoneMorphingWidget.py
@@ -23,9 +23,10 @@ def setup(self) -> None:
self.__ui = su.childWidgetVariables(self.__uiWidget)
self.__logic = None
self.__setup_ui()
- self.__reset_parameters_to_default()
def __setup_ui(self) -> None:
+ self.__ui.visualizationModelColorGroupBox.setVisible(False)
+
self.__ui.sourceNodeSelectionBox.setMRMLScene(slicer.mrmlScene)
self.__ui.targetNodeSelectionBox.setMRMLScene(slicer.mrmlScene)
@@ -49,9 +50,15 @@ def __setup_ui(self) -> None:
self.__ui.bcpdResetParametersPushButton.clicked.connect(self.__reset_parameters_to_default)
self.__ui.generateModelButton.clicked.connect(self.__generate_model)
+ self.__reset_parameters_to_default()
+
def __reset_parameters_to_default(self) -> None:
+ self.__ui.visualizationVisualizeCheckBox.setChecked(False)
+ self.__ui.visualizationSourceModelColorPickerButton.setColor(const.VISUALIZATION_DEFAULT_VALUE_SOURCE_MODEL_COLOR)
+ self.__ui.visualizationTargetModelColorPickerButton.setColor(const.VISUALIZATION_DEFAULT_VALUE_TARGET_MODEL_COLOR)
+
## Preprocessing parameters ##
- self.__ui.preprocessingDownsamplingDistanceThresholdDoubleSpinBox.value = const.PREPROCESSING_DEFAULT_VALUE_DOWNSAMPLING_DISTANCE_THRESHOLD
+ self.__ui.preprocessingDownsamplingVoxelSizeDoubleSpinBox.value = const.PREPROCESSING_DEFAULT_VALUE_DOWNSAMPLING_VOXEL_SIZE
self.__ui.preprocessingNormalsEstimationRadiusDoubleSpinBox.value = const.PREPROCESSING_DEFAULT_VALUE_RADIUS_NORMAL_SCALE
self.__ui.preprocessingNormalsEstimationMaxNeighboursSpinBox.value = const.PREPROCESSING_DEFAULT_VALUE_MAX_NN_NORMALS
self.__ui.preprocessingFpfhRadiusDoubleSpinBox.value = const.PREPROCESSING_DEFAULT_VALUE_RADIUS_FEATURE_SCALE
@@ -150,17 +157,26 @@ def __parse_parameters(self) -> dict:
Parsing parameters from the UI user option elements
"""
params = {}
+ params[const.VISUALIZATION_KEY] = self.__parse_parameters_visualization()
params[const.PREPROCESSING_KEY] = self.__parse_parameters_preprocessing()
params[const.BCPD_KEY] = self.__parse_parameters_bcpd()
params[const.POSTPROCESSING_KEY] = self.__parse_parameters_postprocessing()
return params
+ def __parse_parameters_visualization(self) -> dict:
+ params = {}
+ params[const.VISUALIZATION_KEY_SHOULD_VISUALIZE] = self.__ui.visualizationVisualizeCheckBox.checked
+ params[const.VISUALIZATION_KEY_SOURCE_MODEL_COLOR] = self.__ui.visualizationSourceModelColorPickerButton.color
+ params[const.VISUALIZATION_KEY_TARGET_MODEL_COLOR] = self.__ui.visualizationTargetModelColorPickerButton.color
+
+ return params
+
def __parse_parameters_preprocessing(self) -> dict:
params = {}
# Preprocessing
- params[const.PREPROCESSING_KEY_DOWNSAMPLING_DISTANCE_THRESHOLD] = self.__ui.preprocessingDownsamplingDistanceThresholdDoubleSpinBox.value
+ params[const.PREPROCESSING_KEY_DOWNSAMPLING_VOXEL_SIZE] = self.__ui.preprocessingDownsamplingVoxelSizeDoubleSpinBox.value
params[const.PREPROCESSING_KEY_NORMALS_ESTIMATION_RADIUS] = self.__ui.preprocessingNormalsEstimationRadiusDoubleSpinBox.value
params[const.PREPROCESSING_KEY_MAX_NN_NORMALS] = self.__ui.preprocessingNormalsEstimationMaxNeighboursSpinBox.value
params[const.PREPROCESSING_KEY_FPFH_ESTIMATION_RADIUS] = self.__ui.preprocessingFpfhRadiusDoubleSpinBox.value
diff --git a/docs/dev_docs.md b/docs/dev_docs.md
new file mode 100644
index 0000000..f88191e
--- /dev/null
+++ b/docs/dev_docs.md
@@ -0,0 +1,4 @@
+## Architecture
+
+
+
diff --git a/docs/how-to-use.md b/docs/how-to-use.md
new file mode 100644
index 0000000..3e7dc39
--- /dev/null
+++ b/docs/how-to-use.md
@@ -0,0 +1,62 @@
+# Guide on how to use the module
+### Visualization
+Here, you can check whether you want to visualize results of each pipeline steps using Open3D.
+
+### Input section
+- Source = The mean model, i.e. a full humerus
+- Target = Partial model to be reconstructed
+
+### Preprocessing section
+Before the generation process, it is possible to preprocess the models.
+First is the option to downsample the models in order to relieve some of the computation.
+You can configure the amount of downsampling by the following parameter:
+- **Downsampling voxel size**
+ - If set to 0.0, no downsampling is performed
+
+After the downsampling, we compute the normals of the point cloud.
+The computation needs a radius for which the normals are calculated and maximum number of neighbours.
+These can be adjusted with the following parameters:
+- **Normals estimation radius** - maximum radius in which points are considered neighbouring
+- **Normals estimation max neighbours** - maximum number of neighbours taken into account
+
+Also, we need to calculate a *(Fast) point feature histogram* in order to encode the local geometric properties of the models.
+This method uses the following parameters:
+- **FPFH search radius** - maximum radius in which points are considered neighbouring
+- **FPFH max neighbours** - maximum number of neighbours taken into account
+
+#### Registration
+At this moment we have our models preprocessed and ready for the next step, which is the registration.
+Here we calculate the rigid alignment of the models.
+We use the **RANSAC** (Random Sample Consensus) for the computation.
+The behaviour of this algorithm can be adjusted by the following parameters:
+- **Max iterations** - maximum number of iterations of the algorithm
+- **Distance threshold** - maximum distance in which points are considered neighbouring
+- **Fitness threshold** - the lowest fitness between the models to be accepted.
+
+The computed fit by the RANSAC algorithm is a bit "raw".
+To improve it further, we perform the **ICP** (Iterative closest points) algorithm.
+This algorithm can be tuned by the following parameter:
+- **ICP Distance threshold** - maximum corresponding points-pair distance
+
+### Reconstruction section
+Since we now have a preprocessed meshes and with defined transformations from the *source* to the *target*, we can proceed to the **reconstruction section**.
+For the reconstruction we use the **BCPD** (Bayesian coherent point drift) algorithm.
+Now, the BCPD allows for very fine adjustments of its behaviour using lots of different parameters.
+For the exact description of their effects, please refer to the official documentation [here](https://github.com/ohirose/bcpd/blob/master/README.md).
+
+> **Note: You do NOT have to perform any kind of installation process, the BCPD and its geodesic variant are already pre-built and preconfigured for immediate use in this module.**
+
+**Not implemented options:**
+- Terminal output
+- File output
+
+### Postprocessing section
+After the model is reconstructed, we a postprocessing section is included for you to be able to slightly modify the result, if necessary.
+For these, we let you modify the following parameters:
+- **Clustering scaling**
+ - Scaled size of voxel for within vertices that are clustered together (additionally refer to [here](http://www.open3d.org/docs/0.7.0/python_api/open3d.geometry.simplify_vertex_clustering.html))
+ - If set to 1.0, no scaling is performed
+- **Smoothing iterations** - Number of iterations of mesh smoothing
+ - If set to 0, no smoothing is applied
+
+After the whole process is done, the generated mesh is imported back into the current Slicer scene.