tau-fibrils-yolo 0.0.5__tar.gz → 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tau_fibrils_yolo-0.0.5/.github/workflows/release.yml → tau_fibrils_yolo-0.1.0/.github/workflows/release_multiplatform.yml +52 -10
- tau_fibrils_yolo-0.1.0/.gitignore +33 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/PKG-INFO +20 -55
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/README.md +11 -52
- tau_fibrils_yolo-0.1.0/assets/screenshot.png +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/pyproject.toml +7 -2
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/__init__.py +28 -0
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/_version.py +34 -0
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/boxes_utils.py +111 -0
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/cli.py +60 -0
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/sample/sample.tif +0 -0
- tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/widget.py +248 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/PKG-INFO +20 -55
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/SOURCES.txt +5 -6
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/requires.txt +2 -0
- tau_fibrils_yolo-0.0.5/.gitignore +0 -171
- tau_fibrils_yolo-0.0.5/assets/screenshot.png +0 -0
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/__init__.py +0 -8
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/_version.py +0 -16
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/_widget.py +0 -294
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/cli.py +0 -102
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/measure.py +0 -91
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/postprocess.py +0 -78
- tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/predict.py +0 -168
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/LICENSE +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/MANIFEST.in +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/assets/icon.png +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/00_annotate.py +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/01_shapes_to_labels.py +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/02_split_train_valid.py +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/03_train_yolo.py +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/instructions.md +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/setup.cfg +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/__main__.py +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/napari.yaml +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/dependency_links.txt +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/entry_points.txt +0 -0
- {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/top_level.txt +0 -0
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
- name: Set up Python
|
|
24
24
|
uses: actions/setup-python@v4
|
|
25
25
|
with:
|
|
26
|
-
python-version: "3.
|
|
26
|
+
python-version: "3.10"
|
|
27
27
|
- name: Install dependencies
|
|
28
28
|
run: |
|
|
29
29
|
python -m pip install --upgrade pip
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
runs-on: ${{ matrix.os }}
|
|
43
43
|
strategy:
|
|
44
44
|
matrix:
|
|
45
|
-
os: [windows-latest]
|
|
45
|
+
os: [windows-latest, ubuntu-latest, macos-latest]
|
|
46
46
|
|
|
47
47
|
env:
|
|
48
48
|
PYAPP_PROJECT_NAME: 'tau_fibrils_yolo'
|
|
@@ -71,22 +71,32 @@ jobs:
|
|
|
71
71
|
tar -xzf pyapp-source.tar.gz
|
|
72
72
|
mv pyapp-v* pyapp-latest
|
|
73
73
|
|
|
74
|
-
- name: Build executable
|
|
74
|
+
- name: Build executable
|
|
75
75
|
env:
|
|
76
76
|
PYAPP_PROJECT_VERSION: ${{ env.VERSION }}
|
|
77
|
-
PYAPP_PYTHON_VERSION: '3.
|
|
77
|
+
PYAPP_PYTHON_VERSION: '3.10'
|
|
78
78
|
run: cargo build --release --manifest-path pyapp-latest/Cargo.toml
|
|
79
79
|
|
|
80
|
-
- name: Archive
|
|
80
|
+
- name: Archive executable
|
|
81
81
|
shell: bash
|
|
82
82
|
working-directory: pyapp-latest/target/release
|
|
83
83
|
run: |
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if [ "${{ matrix.os }}" == "windows-latest" ]; then
|
|
85
|
+
EXECUTABLE_NAME=${{ env.PYAPP_PROJECT_NAME }}_${{ runner.os }}_${{ env.VERSION }}.exe
|
|
86
|
+
mv pyapp.exe $EXECUTABLE_NAME
|
|
87
|
+
tar -czvf ../../../executable-windows.tar.gz $EXECUTABLE_NAME
|
|
88
|
+
elif [ "${{ matrix.os }}" == "ubuntu-latest" ]; then
|
|
89
|
+
EXECUTABLE_NAME=${{ env.PYAPP_PROJECT_NAME }}_${{ runner.os }}_${{ env.VERSION }}
|
|
90
|
+
mv pyapp $EXECUTABLE_NAME
|
|
91
|
+
tar -czvf ../../../executable-linux.tar.gz $EXECUTABLE_NAME
|
|
92
|
+
elif [ "${{ matrix.os }}" == "macos-latest" ]; then
|
|
93
|
+
EXECUTABLE_NAME=${{ env.PYAPP_PROJECT_NAME }}_${{ runner.os }}_${{ env.VERSION }}
|
|
94
|
+
mv pyapp $EXECUTABLE_NAME
|
|
95
|
+
tar -czvf ../../../executable-macos.tar.gz $EXECUTABLE_NAME
|
|
96
|
+
fi
|
|
87
97
|
|
|
88
98
|
- name: Upload artifact
|
|
89
|
-
uses: actions/upload-artifact@
|
|
99
|
+
uses: actions/upload-artifact@v4
|
|
90
100
|
with:
|
|
91
101
|
name: executable-${{ runner.os }}
|
|
92
102
|
path: executable-*.tar.gz
|
|
@@ -99,11 +109,23 @@ jobs:
|
|
|
99
109
|
uses: actions/checkout@v2
|
|
100
110
|
|
|
101
111
|
- name: Download Windows artifact
|
|
102
|
-
uses: actions/download-artifact@
|
|
112
|
+
uses: actions/download-artifact@v4
|
|
103
113
|
with:
|
|
104
114
|
name: executable-Windows
|
|
105
115
|
path: .
|
|
106
116
|
|
|
117
|
+
- name: Download Linux artifact
|
|
118
|
+
uses: actions/download-artifact@v4
|
|
119
|
+
with:
|
|
120
|
+
name: executable-Linux
|
|
121
|
+
path: .
|
|
122
|
+
|
|
123
|
+
- name: Download MacOS artifact
|
|
124
|
+
uses: actions/download-artifact@v4
|
|
125
|
+
with:
|
|
126
|
+
name: executable-macOS
|
|
127
|
+
path: .
|
|
128
|
+
|
|
107
129
|
- name: Create Release
|
|
108
130
|
id: create_release
|
|
109
131
|
uses: actions/create-release@v1
|
|
@@ -124,3 +146,23 @@ jobs:
|
|
|
124
146
|
asset_path: ./executable-windows.tar.gz
|
|
125
147
|
asset_name: executable-windows.tar.gz
|
|
126
148
|
asset_content_type: application/gzip
|
|
149
|
+
|
|
150
|
+
- name: Upload Linux executable to release
|
|
151
|
+
uses: actions/upload-release-asset@v1
|
|
152
|
+
env:
|
|
153
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
154
|
+
with:
|
|
155
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
156
|
+
asset_path: ./executable-linux.tar.gz
|
|
157
|
+
asset_name: executable-linux.tar.gz
|
|
158
|
+
asset_content_type: application/gzip
|
|
159
|
+
|
|
160
|
+
- name: Upload MacOS executable to release
|
|
161
|
+
uses: actions/upload-release-asset@v1
|
|
162
|
+
env:
|
|
163
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
164
|
+
with:
|
|
165
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
166
|
+
asset_path: ./executable-macos.tar.gz
|
|
167
|
+
asset_name: executable-macos.tar.gz
|
|
168
|
+
asset_content_type: application/gzip
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
old/
|
|
5
|
+
data/
|
|
6
|
+
env/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.installed.cfg
|
|
14
|
+
*.egg
|
|
15
|
+
.tox/
|
|
16
|
+
.coverage
|
|
17
|
+
.coverage.*
|
|
18
|
+
.cache
|
|
19
|
+
docs/_build/
|
|
20
|
+
.idea/
|
|
21
|
+
venv/
|
|
22
|
+
.vscode/
|
|
23
|
+
.ipynb_checkpoints
|
|
24
|
+
.python-version
|
|
25
|
+
.DS_Store
|
|
26
|
+
**/_version.py
|
|
27
|
+
|
|
28
|
+
push.sh
|
|
29
|
+
todo.txt
|
|
30
|
+
*.pt
|
|
31
|
+
qupath/
|
|
32
|
+
output/
|
|
33
|
+
notebooks/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: tau-fibrils-yolo
|
|
3
|
-
Version: 0.0
|
|
4
|
-
Summary: YoloV8 model for the detection of Tau fibrils in
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: YoloV8 model for the detection of Tau fibrils in EM images.
|
|
5
5
|
Author-email: Mallory Wittwer <mallory.wittwer@epfl.ch>
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
7
7
|
Version 3, 19 November 2007
|
|
@@ -672,6 +672,9 @@ Classifier: License :: OSI Approved :: BSD License
|
|
|
672
672
|
Classifier: Programming Language :: Python :: 3
|
|
673
673
|
Classifier: Programming Language :: Python :: 3.9
|
|
674
674
|
Classifier: Programming Language :: Python :: 3.10
|
|
675
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
676
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
677
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
675
678
|
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
676
679
|
Requires-Python: >=3.9
|
|
677
680
|
Description-Content-Type: text/markdown
|
|
@@ -688,27 +691,24 @@ Requires-Dist: scikit-image
|
|
|
688
691
|
Requires-Dist: scikit-learn
|
|
689
692
|
Requires-Dist: ultralytics
|
|
690
693
|
Requires-Dist: opencv-contrib-python-headless
|
|
694
|
+
Requires-Dist: imaging-server-kit>=0.1.3
|
|
695
|
+
Requires-Dist: napari-serverkit>=0.0.9
|
|
696
|
+
Dynamic: license-file
|
|
691
697
|
|
|
692
698
|

|
|
693
|
-
# 🧬 Tau Fibrils Yolo - Object detection in
|
|
699
|
+
# 🧬 Tau Fibrils Yolo - Object detection in EM images
|
|
694
700
|
|
|
695
701
|

|
|
696
702
|
|
|
697
|
-
We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in
|
|
703
|
+
We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in EM images. The model is integrated as a [Napari](https://napari.org/stable/) plugin.
|
|
698
704
|
|
|
699
|
-
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)]
|
|
705
|
+
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)] [[`Training`](#training)]
|
|
700
706
|
|
|
701
707
|
This project is part of a collaboration between the [EPFL Center for Imaging](https://imaging.epfl.ch/) and the [Laboratory of Biological Electron Microscopy](https://www.lbem.ch/).
|
|
702
708
|
|
|
703
709
|
## Installation
|
|
704
710
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
Download and run the latest installer from the [Releases](https://github.com/EPFL-Center-for-Imaging/tau-fibrils-yolo/releases) page.
|
|
708
|
-
|
|
709
|
-
### As a Python package
|
|
710
|
-
|
|
711
|
-
We recommend performing the installation in a clean Python environment. Install our package from PyPi:
|
|
711
|
+
We recommend performing the installation in a clean Python environment. Install the package from PyPi:
|
|
712
712
|
|
|
713
713
|
```sh
|
|
714
714
|
pip install tau-fibrils-yolo
|
|
@@ -728,48 +728,27 @@ cd tau-fibrils-yolo
|
|
|
728
728
|
pip install -e .
|
|
729
729
|
```
|
|
730
730
|
|
|
731
|
-
## Model
|
|
732
|
-
|
|
733
|
-
The model weights (6.5 Mb) are automatically downloaded from [this repository on Zenodo](https://sandbox.zenodo.org/records/99113) the first time you run inference. The model files are saved in the user home folder in the `.yolo` directory.
|
|
734
|
-
|
|
735
731
|
## Usage
|
|
736
732
|
|
|
737
733
|
**In Napari**
|
|
738
734
|
|
|
739
|
-
To use
|
|
735
|
+
To use the model in Napari, start the viewer with
|
|
740
736
|
|
|
741
737
|
```sh
|
|
742
738
|
napari -w tau-fibrils-yolo
|
|
743
739
|
```
|
|
744
740
|
|
|
745
|
-
or open the
|
|
746
|
-
|
|
747
|
-
Open an image using `File > Open files` or drag-and-drop an image into the viewer window.
|
|
748
|
-
|
|
749
|
-
**Sample data**: To test the model, you can run it on our provided sample image. In Napari, open the image from `File > Open Sample > [TODO - add a sample image]`.
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
**As a library**
|
|
753
|
-
|
|
754
|
-
You can run the model to detect fibrils in an image (represented as a numpy array).
|
|
755
|
-
|
|
756
|
-
```py
|
|
757
|
-
from tau_fibrils_yolo import FibrilsDetector
|
|
758
|
-
|
|
759
|
-
detector = FibrilsDetector()
|
|
741
|
+
or open the plugin from `Plugins > Tau fibrils detection`.
|
|
760
742
|
|
|
761
|
-
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
**As a CLI**
|
|
743
|
+
**From the command-line**
|
|
765
744
|
|
|
766
|
-
Run inference on an image from the command-line
|
|
745
|
+
Run inference on an image from the command-line:
|
|
767
746
|
|
|
768
747
|
```sh
|
|
769
748
|
tau_fibrils_predict_image -i /path/to/folder/image_001.tif
|
|
770
749
|
```
|
|
771
750
|
|
|
772
|
-
|
|
751
|
+
This command will run the YOLO model and save a CSV file containing measurements next to the image:
|
|
773
752
|
|
|
774
753
|
```
|
|
775
754
|
folder/
|
|
@@ -777,23 +756,9 @@ folder/
|
|
|
777
756
|
├── image_001_results.csv
|
|
778
757
|
```
|
|
779
758
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
To run inference in batch on all images in a folder, use:
|
|
783
|
-
|
|
784
|
-
```sh
|
|
785
|
-
tau_fibrils_predict_folder -i /path/to/folder/
|
|
786
|
-
```
|
|
787
|
-
|
|
788
|
-
This will produce:
|
|
759
|
+
## Training
|
|
789
760
|
|
|
790
|
-
|
|
791
|
-
folder/
|
|
792
|
-
├── image_001.tif
|
|
793
|
-
├── image_001_results.csv
|
|
794
|
-
├── image_002.tif
|
|
795
|
-
├── image_002_results.csv
|
|
796
|
-
```
|
|
761
|
+
The instructions for training the model can be found [here](./scripts/instructions.md).
|
|
797
762
|
|
|
798
763
|
## Issues
|
|
799
764
|
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|

|
|
2
|
-
# 🧬 Tau Fibrils Yolo - Object detection in
|
|
2
|
+
# 🧬 Tau Fibrils Yolo - Object detection in EM images
|
|
3
3
|
|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in
|
|
6
|
+
We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in EM images. The model is integrated as a [Napari](https://napari.org/stable/) plugin.
|
|
7
7
|
|
|
8
|
-
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)]
|
|
8
|
+
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)] [[`Training`](#training)]
|
|
9
9
|
|
|
10
10
|
This project is part of a collaboration between the [EPFL Center for Imaging](https://imaging.epfl.ch/) and the [Laboratory of Biological Electron Microscopy](https://www.lbem.ch/).
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Download and run the latest installer from the [Releases](https://github.com/EPFL-Center-for-Imaging/tau-fibrils-yolo/releases) page.
|
|
17
|
-
|
|
18
|
-
### As a Python package
|
|
19
|
-
|
|
20
|
-
We recommend performing the installation in a clean Python environment. Install our package from PyPi:
|
|
14
|
+
We recommend performing the installation in a clean Python environment. Install the package from PyPi:
|
|
21
15
|
|
|
22
16
|
```sh
|
|
23
17
|
pip install tau-fibrils-yolo
|
|
@@ -37,48 +31,27 @@ cd tau-fibrils-yolo
|
|
|
37
31
|
pip install -e .
|
|
38
32
|
```
|
|
39
33
|
|
|
40
|
-
## Model
|
|
41
|
-
|
|
42
|
-
The model weights (6.5 Mb) are automatically downloaded from [this repository on Zenodo](https://sandbox.zenodo.org/records/99113) the first time you run inference. The model files are saved in the user home folder in the `.yolo` directory.
|
|
43
|
-
|
|
44
34
|
## Usage
|
|
45
35
|
|
|
46
36
|
**In Napari**
|
|
47
37
|
|
|
48
|
-
To use
|
|
38
|
+
To use the model in Napari, start the viewer with
|
|
49
39
|
|
|
50
40
|
```sh
|
|
51
41
|
napari -w tau-fibrils-yolo
|
|
52
42
|
```
|
|
53
43
|
|
|
54
|
-
or open the
|
|
55
|
-
|
|
56
|
-
Open an image using `File > Open files` or drag-and-drop an image into the viewer window.
|
|
57
|
-
|
|
58
|
-
**Sample data**: To test the model, you can run it on our provided sample image. In Napari, open the image from `File > Open Sample > [TODO - add a sample image]`.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
**As a library**
|
|
62
|
-
|
|
63
|
-
You can run the model to detect fibrils in an image (represented as a numpy array).
|
|
64
|
-
|
|
65
|
-
```py
|
|
66
|
-
from tau_fibrils_yolo import FibrilsDetector
|
|
67
|
-
|
|
68
|
-
detector = FibrilsDetector()
|
|
44
|
+
or open the plugin from `Plugins > Tau fibrils detection`.
|
|
69
45
|
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
**As a CLI**
|
|
46
|
+
**From the command-line**
|
|
74
47
|
|
|
75
|
-
Run inference on an image from the command-line
|
|
48
|
+
Run inference on an image from the command-line:
|
|
76
49
|
|
|
77
50
|
```sh
|
|
78
51
|
tau_fibrils_predict_image -i /path/to/folder/image_001.tif
|
|
79
52
|
```
|
|
80
53
|
|
|
81
|
-
|
|
54
|
+
This command will run the YOLO model and save a CSV file containing measurements next to the image:
|
|
82
55
|
|
|
83
56
|
```
|
|
84
57
|
folder/
|
|
@@ -86,23 +59,9 @@ folder/
|
|
|
86
59
|
├── image_001_results.csv
|
|
87
60
|
```
|
|
88
61
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
To run inference in batch on all images in a folder, use:
|
|
92
|
-
|
|
93
|
-
```sh
|
|
94
|
-
tau_fibrils_predict_folder -i /path/to/folder/
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This will produce:
|
|
62
|
+
## Training
|
|
98
63
|
|
|
99
|
-
|
|
100
|
-
folder/
|
|
101
|
-
├── image_001.tif
|
|
102
|
-
├── image_001_results.csv
|
|
103
|
-
├── image_002.tif
|
|
104
|
-
├── image_002_results.csv
|
|
105
|
-
```
|
|
64
|
+
The instructions for training the model can be found [here](./scripts/instructions.md).
|
|
106
65
|
|
|
107
66
|
## Issues
|
|
108
67
|
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tau-fibrils-yolo"
|
|
3
3
|
dynamic = ["version"]
|
|
4
|
-
description = "YoloV8 model for the detection of Tau fibrils in
|
|
4
|
+
description = "YoloV8 model for the detection of Tau fibrils in EM images."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
7
7
|
license = {file = "LICENSE"}
|
|
@@ -13,6 +13,9 @@ classifiers = [
|
|
|
13
13
|
"Programming Language :: Python :: 3",
|
|
14
14
|
"Programming Language :: Python :: 3.9",
|
|
15
15
|
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
16
19
|
"Topic :: Scientific/Engineering :: Image Processing",
|
|
17
20
|
]
|
|
18
21
|
|
|
@@ -28,7 +31,9 @@ dependencies = [
|
|
|
28
31
|
"scikit-image",
|
|
29
32
|
"scikit-learn",
|
|
30
33
|
"ultralytics",
|
|
31
|
-
"opencv-contrib-python-headless"
|
|
34
|
+
"opencv-contrib-python-headless",
|
|
35
|
+
"imaging-server-kit>=0.1.3",
|
|
36
|
+
"napari-serverkit>=0.0.9",
|
|
32
37
|
]
|
|
33
38
|
|
|
34
39
|
[project.entry-points."napari.manifest"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from tau_fibrils_yolo.widget import (
|
|
2
|
+
detect_fibrils,
|
|
3
|
+
max_iou_boxes,
|
|
4
|
+
min_distance_boxes,
|
|
5
|
+
boxes_kernel_density,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from qtpy.QtWidgets import QWidget
|
|
9
|
+
import imaging_server_kit as sk
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class YoloDetectorWidget(QWidget):
|
|
13
|
+
def __init__(self, viewer):
|
|
14
|
+
super().__init__()
|
|
15
|
+
multi = sk.combine(
|
|
16
|
+
[detect_fibrils, max_iou_boxes, min_distance_boxes, boxes_kernel_density],
|
|
17
|
+
name="Tau fibrils analysis",
|
|
18
|
+
)
|
|
19
|
+
widget = sk.to_qwidget(multi, viewer)
|
|
20
|
+
self.setLayout(widget.layout())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
from ._version import version as __version__
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from ._version import version as __version__
|
|
27
|
+
except ImportError:
|
|
28
|
+
__version__ = "unknown"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = 'g53b41a1b4'
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
import cv2
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.linalg import norm
|
|
6
|
+
from scipy.ndimage import zoom
|
|
7
|
+
from scipy.spatial import distance_matrix
|
|
8
|
+
from sklearn.neighbors import KernelDensity
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def boxes_min_distance_filter(
|
|
12
|
+
boxes, min_dist_px=5, probas: Optional[np.ndarray] = None
|
|
13
|
+
) -> Any:
|
|
14
|
+
"""Returns a filter matching objects isolated by less than min_dist_px pixels."""
|
|
15
|
+
centers = boxes_centers(boxes)
|
|
16
|
+
dist_matrix = distance_matrix(centers, centers)
|
|
17
|
+
np.fill_diagonal(dist_matrix, np.inf)
|
|
18
|
+
filt = np.min(dist_matrix, axis=1) > min_dist_px
|
|
19
|
+
if probas is not None:
|
|
20
|
+
return boxes[filt], probas[filt]
|
|
21
|
+
else:
|
|
22
|
+
return boxes[filt]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def boxes_iou_filter(
|
|
26
|
+
boxes: np.ndarray, max_iou: float = 0.0, probas: Optional[np.ndarray] = None
|
|
27
|
+
) -> Any:
|
|
28
|
+
"""Removes boxes based on an intersection over union threshold."""
|
|
29
|
+
keep = []
|
|
30
|
+
for i, box_i in enumerate(boxes):
|
|
31
|
+
should_keep_i = True
|
|
32
|
+
box_i = boxes[i]
|
|
33
|
+
for j in keep:
|
|
34
|
+
box_j = boxes[j]
|
|
35
|
+
intersection, _ = cv2.intersectConvexConvex(box_i, box_j)
|
|
36
|
+
area_i = cv2.contourArea(box_i)
|
|
37
|
+
area_j = cv2.contourArea(box_j)
|
|
38
|
+
union = area_i + area_j - intersection
|
|
39
|
+
iou = intersection / union
|
|
40
|
+
if iou >= max_iou:
|
|
41
|
+
should_keep_i = False
|
|
42
|
+
break
|
|
43
|
+
if should_keep_i:
|
|
44
|
+
keep.append(i)
|
|
45
|
+
|
|
46
|
+
if probas is not None:
|
|
47
|
+
return boxes[keep], probas[keep]
|
|
48
|
+
else:
|
|
49
|
+
return boxes[keep]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def clear_border_boxes(boxes: np.ndarray, probas: Optional[np.ndarray] = None) -> Any:
|
|
53
|
+
"""Removes boxes touching the image border."""
|
|
54
|
+
filt = ~(boxes < 0).any(axis=2).any(axis=1)
|
|
55
|
+
if probas is not None:
|
|
56
|
+
return boxes[filt], probas[filt]
|
|
57
|
+
else:
|
|
58
|
+
return boxes[filt]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def boxes_centers(boxes: np.ndarray) -> np.ndarray:
|
|
62
|
+
"""Returns the center coordinates of the boxes."""
|
|
63
|
+
box_cy = (np.max(boxes[..., 1], axis=1) + np.min(boxes[..., 1], axis=1)) / 2
|
|
64
|
+
box_cx = (np.max(boxes[..., 0], axis=1) + np.min(boxes[..., 0], axis=1)) / 2
|
|
65
|
+
box_centers = np.vstack((box_cx, box_cy)).T
|
|
66
|
+
return box_centers
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def boxes_kernel_density_map(boxes, image, gaussian_sigma_px=50, downscale_factor=8):
|
|
70
|
+
"""Returns a kernel density image from box coordinates."""
|
|
71
|
+
grid_size_x = image.shape[0] // downscale_factor
|
|
72
|
+
grid_size_y = image.shape[1] // downscale_factor
|
|
73
|
+
|
|
74
|
+
x_grid, y_grid = np.meshgrid(
|
|
75
|
+
np.linspace(0, grid_size_y - 1, grid_size_y),
|
|
76
|
+
np.linspace(0, grid_size_x - 1, grid_size_x),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
grid_points = np.vstack([y_grid.ravel(), x_grid.ravel()]).T
|
|
80
|
+
|
|
81
|
+
kde = KernelDensity(
|
|
82
|
+
bandwidth=gaussian_sigma_px, kernel="gaussian", algorithm="ball_tree"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
kde.fit(boxes_centers(boxes) / downscale_factor)
|
|
86
|
+
|
|
87
|
+
density_map = np.exp(kde.score_samples(grid_points)).reshape(
|
|
88
|
+
(grid_size_x, grid_size_y)
|
|
89
|
+
)
|
|
90
|
+
density_map = zoom(density_map, zoom=downscale_factor, order=1)
|
|
91
|
+
|
|
92
|
+
return density_map
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def box_measurements(box):
|
|
96
|
+
"""Returns the center, length, and width of an oriented bounding box."""
|
|
97
|
+
p0, p1, p2, p3 = box
|
|
98
|
+
|
|
99
|
+
if norm(p2 - p0) < norm(p1 - p0):
|
|
100
|
+
p0, p3, p2, p1 = box
|
|
101
|
+
|
|
102
|
+
p5 = p0 + (p1 - p0) / 2
|
|
103
|
+
p6 = p3 + (p2 - p3) / 2
|
|
104
|
+
|
|
105
|
+
width = norm(p1 - p0)
|
|
106
|
+
length = norm(p2 - p0)
|
|
107
|
+
|
|
108
|
+
diagonal = p6 - p5
|
|
109
|
+
center = p5 + diagonal / 2
|
|
110
|
+
|
|
111
|
+
return center, length, width
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import tifffile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import argparse
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from tau_fibrils_yolo.widget import detect_fibrils
|
|
8
|
+
from tau_fibrils_yolo.boxes_utils import box_measurements
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def process_input_file_predict(input_image_file):
|
|
12
|
+
image = tifffile.imread(input_image_file)
|
|
13
|
+
|
|
14
|
+
results = detect_fibrils.run(image)
|
|
15
|
+
box_results = results.read("Tau fibrils")
|
|
16
|
+
|
|
17
|
+
boxes = box_results.data
|
|
18
|
+
probas = box_results.meta["features"]["probabilities"]
|
|
19
|
+
|
|
20
|
+
centers_x = []
|
|
21
|
+
centers_y = []
|
|
22
|
+
lengths = []
|
|
23
|
+
widths = []
|
|
24
|
+
for box in boxes:
|
|
25
|
+
center, length, width = box_measurements(box)
|
|
26
|
+
centers_x.append(center[0])
|
|
27
|
+
centers_y.append(center[1])
|
|
28
|
+
lengths.append(length)
|
|
29
|
+
widths.append(width)
|
|
30
|
+
|
|
31
|
+
df = pd.DataFrame(
|
|
32
|
+
{
|
|
33
|
+
"probability": probas,
|
|
34
|
+
"length": lengths,
|
|
35
|
+
"width": widths,
|
|
36
|
+
"center_x": centers_x,
|
|
37
|
+
"center_y": centers_y,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
input_image_path = Path(input_image_file)
|
|
42
|
+
out_file_name = input_image_path.parent / f"{input_image_path.stem}_results.csv"
|
|
43
|
+
|
|
44
|
+
df.to_csv(out_file_name)
|
|
45
|
+
|
|
46
|
+
print("Saved results to ", out_file_name)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def cli_predict_image():
|
|
50
|
+
"""Command-line entry point for model inference."""
|
|
51
|
+
parser = argparse.ArgumentParser(description="Use this command to run inference.")
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"-i",
|
|
54
|
+
type=str,
|
|
55
|
+
required=True,
|
|
56
|
+
help="Input image. Must be a TIF image file.",
|
|
57
|
+
)
|
|
58
|
+
args = parser.parse_args()
|
|
59
|
+
|
|
60
|
+
process_input_file_predict(args.i)
|
|
Binary file
|