Switch to unified view

a/README.md b/README.md
1
# pyMSKT (Musculoskeletal Toolkit)
1
# pyMSKT (Musculoskeletal Toolkit)
2
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)<br>
2
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)<br>
3
![Build Status](https://github.com/gattia/pymskt/actions/workflows/build-test.yml/badge.svg?branch=main)<br>
3
![Build Status](https://github.com/gattia/pymskt/actions/workflows/build-test.yml/badge.svg?branch=main)<br>
4
|[Documentation](https://anthonygattiphd.com/pymskt/)|
4
|[Documentation](https://anthonygattiphd.com/pymskt/)|
5
5
6
pyMSKT is an open-source library for performing quantitative analyses of the musculoskeletal system. It enables creation of surface meshes of musculoskeletal anatomy and then processes these meshes to get quantitative outcomes and visualizatons, like for cartilage thickness.  
6
pyMSKT is an open-source library for performing quantitative analyses of the musculoskeletal system. It enables creation of surface meshes of musculoskeletal anatomy and then processes these meshes to get quantitative outcomes and visualizatons, like for cartilage thickness.  
7
7
8
<p align="center">
8
9
<img src="./images/whole_knee_1.png" width="300">
10
</p>
11
12
# Installation
9
# Installation
13
10
14
# Pip install from pypi
11
# Pip install from pypi
15
```bash
12
```bash
16
    # create environment
13
    # create environment
17
    conda env create -n mskt
14
    conda env create -n mskt
18
    conda activate mskt
15
    conda activate mskt
19
16
20
    pip install mskt
17
    pip install mskt
21
```
18
```
22
19
23
### Conda / pip install from source
20
### Conda / pip install from source
24
```bash
21
```bash
25
    # clone repository
22
    # clone repository
26
    git clone https://github.com/gattia/pymskt.git
23
    git clone https://github.com/gattia/pymskt.git
27
    
24
    
28
    # move into directory
25
    # move into directory
29
    cd pymskt
26
    cd pymskt
30
    
27
    
31
    # CREATE ENVIRONMENT:
28
    # CREATE ENVIRONMENT:
32
    conda env create -n mskt
29
    conda env create -n mskt
33
    conda activate mskt
30
    conda activate mskt
34
31
35
    # INSTALLING DEPENDENCIES
32
    # INSTALLING DEPENDENCIES
36
    # Recommend pip becuase cycpd and pyfocusr are available on pypi (but not conda)
33
    # Recommend pip becuase cycpd and pyfocusr are available on pypi (but not conda)
37
    pip install -r requirements.txt
34
    pip install -r requirements.txt
38
35
39
    # IF USING PIP
36
    # IF USING PIP
40
    pip install .
37
    pip install .
41
```
38
```
42
39
43
### Conda only install (not-recommended)
40
### Conda only install (not-recommended)
44
41
45
1. Clone this repository & install dependencies: <br>
42
1. Clone this repository & install dependencies: <br>
46
    ```bash
43
    ```bash
47
    # clone repository
44
    # clone repository
48
    git clone https://github.com/gattia/pymskt.git
45
    git clone https://github.com/gattia/pymskt.git
49
    
46
    
50
    # move into directory
47
    # move into directory
51
    cd pymskt
48
    cd pymskt
52
    
49
    
53
    # CREATE ENVIRONMENT:
50
    # CREATE ENVIRONMENT:
54
    conda env create -n mskt
51
    conda env create -n mskt
55
    conda activate mskt
52
    conda activate mskt
56
53
57
    # Install all available requirements
54
    # Install all available requirements
58
    conda install --file requirements-conda.txt # pip (below) can alternatively be used to install dependencies in conda env
55
    conda install --file requirements-conda.txt # pip (below) can alternatively be used to install dependencies in conda env
59
    
56
    
60
    # Return to root dir
57
    # Return to root dir
61
    cd ..
58
    cd ..
62
    
59
    
63
    ```
60
    ```
64
61
65
2. Clone cycpd & install: (ONLY NEEDED FOR CONDA INSTALL)<br>
62
2. Clone cycpd & install: (ONLY NEEDED FOR CONDA INSTALL)<br>
66
    ```bash
63
    ```bash
67
    git clone https://github.com/gattia/cycpd.git
64
    git clone https://github.com/gattia/cycpd.git
68
    cd cycpd
65
    cd cycpd
69
    pip install .
66
    pip install .
70
    cd ..
67
    cd ..
71
    ```
68
    ```
72
3. Clone pyfocusr & install: (ONLY NEEDED FOR CONDA INSTALL)<br>
69
3. Clone pyfocusr & install: (ONLY NEEDED FOR CONDA INSTALL)<br>
73
    ```bash
70
    ```bash
74
    git clone https://github.com/gattia/pyfocusr.git
71
    git clone https://github.com/gattia/pyfocusr.git
75
    cd pyfocusr
72
    cd pyfocusr
76
    pip install .
73
    pip install .
77
    cd ..
74
    cd ..
78
    ```
75
    ```
79
4. Install pymskt: (ONLY NEEDED FOR CONDA INSTALL)<br>
76
4. Install pymskt: (ONLY NEEDED FOR CONDA INSTALL)<br>
80
    ```bash
77
    ```bash
81
    cd pymskt
78
    cd pymskt
82
    pip install .
79
    pip install .
83
    ```
80
    ```
84
81
85
82
86
### To install itkwidgets (for visualization): 
83
### To install itkwidgets (for visualization): 
87
If you are using jupyterlab instead of jupyter notebook, you also need to install an extension: 
84
If you are using jupyterlab instead of jupyter notebook, you also need to install an extension: 
88
```
85
```
89
jupyter labextension install @jupyter-widgets/jupyterlab-manager jupyter-matplotlib jupyterlab-datawidgets itkwidgets
86
jupyter labextension install @jupyter-widgets/jupyterlab-manager jupyter-matplotlib jupyterlab-datawidgets itkwidgets
90
```
87
```
91
88
92
# Examples
89
# Examples
93
There are jupyter notebook examples in the directory `/examples`
90
There are jupyter notebook examples in the directory `/examples`
94
91
95
pyMSKT allows you to easily create bone meshes and attribute cartilage to the bone for calculating quantitative outcomes. 
92
pyMSKT allows you to easily create bone meshes and attribute cartilage to the bone for calculating quantitative outcomes. 
96
93
97
```python
94
```python
98
femur = BoneMesh(path_seg_image=location_seg,  # path to the segmentation image being used.
95
femur = BoneMesh(path_seg_image=location_seg,  # path to the segmentation image being used.
99
                 label_idx=5,                  # what is the label of this bone.
96
                 label_idx=5,                  # what is the label of this bone.
100
                 list_cartilage_labels=[1]) # labels for cartilage associted with bone.   
97
                 list_cartilage_labels=[1]) # labels for cartilage associted with bone.   
101
# Create the bone mesh
98
# Create the bone mesh
102
femur.create_mesh()
99
femur.create_mesh()
103
# Calcualte cartialge thickness for the cartialge meshes associated with the bone
100
# Calcualte cartialge thickness for the cartialge meshes associated with the bone
104
femur.calc_cartilage_thickness()
101
femur.calc_cartilage_thickness()
105
femur.save_mesh(os.path.expanduser'~/Downloads/femur.vtk')
102
femur.save_mesh(os.path.expanduser'~/Downloads/femur.vtk')
106
```
103
```
107
The saved file can be viewed in many mesh viewers such as [3D Slicer](https://www.slicer.org/) or [Paraview](https://www.paraview.org/). Or, better yet they can be viewed in your jupyter notebook using [itkwidgets](https://pypi.org/project/itkwidgets/): 
104
The saved file can be viewed in many mesh viewers such as [3D Slicer](https://www.slicer.org/) or [Paraview](https://www.paraview.org/). Or, better yet they can be viewed in your jupyter notebook using [itkwidgets](https://pypi.org/project/itkwidgets/): 
108
```python
105
```python
109
from itkwidgets import view
106
from itkwidgets import view
110
107
111
view(geometries=[femur.mesh])
108
view(geometries=[femur.mesh])
112
```
109
```
113
110
114
![](/images/femur_itkwidgets.png)
111
![](/images/femur_itkwidgets.png)
115
112
116
After creating the above mesh, creating cartilage subregions & an anatomical coordinate
113
After creating the above mesh, creating cartilage subregions & an anatomical coordinate
117
system is as simple as: 
114
system is as simple as: 
118
115
119
```python
116
```python
120
# Load in full seg image
117
# Load in full seg image
121
seg_image = sitk.ReadImage(location_seg)
118
seg_image = sitk.ReadImage(location_seg)
122
# break into sub regions. (weightbearing / trochlea / posterior condyles)
119
# break into sub regions. (weightbearing / trochlea / posterior condyles)
123
seg_image = mskt.image.cartilage_processing.get_knee_segmentation_with_femur_subregions(seg_image)
120
seg_image = mskt.image.cartilage_processing.get_knee_segmentation_with_femur_subregions(seg_image)
124
121
125
# assign femoral condyle cartilage sub regions to femur 
122
# assign femoral condyle cartilage sub regions to femur 
126
femur.seg_image = seg_image
123
femur.seg_image = seg_image
127
femur.list_cartilage_labels=[11, 12, 13, 14, 15]
124
femur.list_cartilage_labels=[11, 12, 13, 14, 15]
128
femur.assign_cartilage_regions()
125
femur.assign_cartilage_regions()
129
126
130
# use cartilage regions to fit cylinder to condyles and create anatomic coordinate system 
127
# use cartilage regions to fit cylinder to condyles and create anatomic coordinate system 
131
femur_acs = FemurACS(femur, cart_label=(11, 12, 13, 14, 15))
128
femur_acs = FemurACS(femur, cart_label=(11, 12, 13, 14, 15))
132
femur_acs.fit()
129
femur_acs.fit()
133
```
130
```
134
131
135
The resulting anatomical coorindate system can be used to create arrows & visualize the result: 
132
The resulting anatomical coorindate system can be used to create arrows & visualize the result: 
136
133
137
```python
134
```python
138
AP_arrow = get_arrow(femur_acs.ap_axis, origin=femur_acs.origin )
135
AP_arrow = get_arrow(femur_acs.ap_axis, origin=femur_acs.origin )
139
IS_arrow = get_arrow(femur_acs.is_axis, origin=femur_acs.origin)
136
IS_arrow = get_arrow(femur_acs.is_axis, origin=femur_acs.origin)
140
ML_arrow = get_arrow(femur_acs.ml_axis, origin=femur_acs.origin)
137
ML_arrow = get_arrow(femur_acs.ml_axis, origin=femur_acs.origin)
141
138
142
view(geometries=[femur.mesh, AP_arrow, IS_arrow, ML_arrow])
139
view(geometries=[femur.mesh, AP_arrow, IS_arrow, ML_arrow])
143
```
140
```
144
|*Anatomical Coordinate System - Cartilage Thickness* | *Anatomical Coordinate System - Cartilage Subregions* |
141
|*Anatomical Coordinate System - Cartilage Thickness* | *Anatomical Coordinate System - Cartilage Subregions* |
145
|:---:       |:---:        |
142
|:---:       |:---:        |
146
|![](/images/femur_acs.png)   | ![](/images/femur_subregions.png) |
143
|![](/images/femur_acs.png)   | ![](/images/femur_subregions.png) |
147
144
148
145
149
An example of how the cartilage thickness values are computed:
146
An example of how the cartilage thickness values are computed:
150
147
151
![](/images/cartilage_thickness_analysis.png)
148
![](/images/cartilage_thickness_analysis.png)
152
149
153
150
154
# Development / Contributing
151
# Development / Contributing
155
General information for contributing can be found [here](https://github.com/gattia/pymskt/blob/main/CONTRIBUTING.md)
152
General information for contributing can be found [here](https://github.com/gattia/pymskt/blob/main/CONTRIBUTING.md)
156
153
157
## Tests
154
## Tests
158
- Running tests requires pytest (`conda install pytest` or `pip install pytest`)
155
- Running tests requires pytest (`conda install pytest` or `pip install pytest`)
159
- Run tests using `pytest` or `make test` in the home directory. 
156
- Run tests using `pytest` or `make test` in the home directory. 
160
157
161
## Coverage
158
## Coverage
162
- Coverage results/info requires `coverage` (`conda install coverage` or `pip install coverage`)
159
- Coverage results/info requires `coverage` (`conda install coverage` or `pip install coverage`)
163
- Can get coverage statistics by running: 
160
- Can get coverage statistics by running: 
164
    - `coverage run -m pytest`
161
    - `coverage run -m pytest`
165
    or if using make: 
162
    or if using make: 
166
    - `make coverage`
163
    - `make coverage`
167
164
168
## Notes for development
165
## Notes for development
169
- When updating cython code, it is not re-built when we re-install using the basic `python setup.py install`. Therefore we force it to do this: 
166
- When updating cython code, it is not re-built when we re-install using the basic `python setup.py install`. Therefore we force it to do this: 
170
    - `python setup.py build_ext -i --force`          
167
    - `python setup.py build_ext -i --force`          
171
168
172
### Tests
169
### Tests
173
If you add a new function, or functionality to `pymskt` please add appropriate tests as well. 
170
If you add a new function, or functionality to `pymskt` please add appropriate tests as well. 
174
The tests are located in `/testing` and are organized as: 
171
The tests are located in `/testing` and are organized as: 
175
`/testing/[pymskt_submodule]/[python_filename_being_tested]/[name_of_function_being_tested]_test.py`
172
`/testing/[pymskt_submodule]/[python_filename_being_tested]/[name_of_function_being_tested]_test.py`
176
173
177
The tests use `pytest`. If you are not familiar with `pytest` a brief example is provided [here](https://docs.pytest.org/en/6.2.x/getting-started.html). 
174
The tests use `pytest`. If you are not familiar with `pytest` a brief example is provided [here](https://docs.pytest.org/en/6.2.x/getting-started.html). 
178
175
179
Currently, 37 tests are being skipped for one of 2 (maybe 3) reasons. 1. They arent implemented yet and they are a placeholder. 2. They rely on a function that has small machine-to-machine differences so they dont pass or 3. A breaking change occured since result meshes were last saved. If you want to help but dont know how or where to start, filling in / fixing these tests would be a great place to start! And greatly appreciated.
176
Currently, 37 tests are being skipped for one of 2 (maybe 3) reasons. 1. They arent implemented yet and they are a placeholder. 2. They rely on a function that has small machine-to-machine differences so they dont pass or 3. A breaking change occured since result meshes were last saved. If you want to help but dont know how or where to start, filling in / fixing these tests would be a great place to start! And greatly appreciated.
180
177
181
## Code of Conduct
178
## Code of Conduct
182
We have adopted the code of conduct defined by the [Contributor Covenant](https://www.contributor-covenant.org) to clarify expected behavior in our community. For more information see the [Code of Conduct](https://github.com/gattia/pymskt/blob/main/CODE_OF_CONDUCT.md).
179
We have adopted the code of conduct defined by the [Contributor Covenant](https://www.contributor-covenant.org) to clarify expected behavior in our community. For more information see the [Code of Conduct](https://github.com/gattia/pymskt/blob/main/CODE_OF_CONDUCT.md).