tau-fibrils-yolo 0.0.6__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.6 → tau_fibrils_yolo-0.1.0}/.github/workflows/release_multiplatform.yml +6 -6
- tau_fibrils_yolo-0.1.0/.gitignore +33 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/PKG-INFO +15 -54
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/README.md +7 -52
- tau_fibrils_yolo-0.1.0/assets/screenshot.png +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/pyproject.toml +6 -1
- 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.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/PKG-INFO +15 -54
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/SOURCES.txt +4 -6
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/requires.txt +2 -0
- tau_fibrils_yolo-0.0.6/.github/workflows/release.yml +0 -126
- tau_fibrils_yolo-0.0.6/.gitignore +0 -171
- tau_fibrils_yolo-0.0.6/assets/screenshot.png +0 -0
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/__init__.py +0 -8
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/_version.py +0 -16
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/_widget.py +0 -294
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/cli.py +0 -102
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/measure.py +0 -91
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/postprocess.py +0 -78
- tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/predict.py +0 -168
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/LICENSE +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/MANIFEST.in +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/assets/icon.png +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/scripts/00_annotate.py +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/scripts/01_shapes_to_labels.py +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/scripts/02_split_train_valid.py +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/scripts/03_train_yolo.py +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/scripts/instructions.md +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/setup.cfg +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/__main__.py +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/napari.yaml +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/dependency_links.txt +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/entry_points.txt +0 -0
- {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/top_level.txt +0 -0
{tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.0}/.github/workflows/release_multiplatform.yml
RENAMED
|
@@ -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
|
|
@@ -74,7 +74,7 @@ jobs:
|
|
|
74
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
80
|
- name: Archive executable
|
|
@@ -96,7 +96,7 @@ jobs:
|
|
|
96
96
|
fi
|
|
97
97
|
|
|
98
98
|
- name: Upload artifact
|
|
99
|
-
uses: actions/upload-artifact@
|
|
99
|
+
uses: actions/upload-artifact@v4
|
|
100
100
|
with:
|
|
101
101
|
name: executable-${{ runner.os }}
|
|
102
102
|
path: executable-*.tar.gz
|
|
@@ -109,19 +109,19 @@ jobs:
|
|
|
109
109
|
uses: actions/checkout@v2
|
|
110
110
|
|
|
111
111
|
- name: Download Windows artifact
|
|
112
|
-
uses: actions/download-artifact@
|
|
112
|
+
uses: actions/download-artifact@v4
|
|
113
113
|
with:
|
|
114
114
|
name: executable-Windows
|
|
115
115
|
path: .
|
|
116
116
|
|
|
117
117
|
- name: Download Linux artifact
|
|
118
|
-
uses: actions/download-artifact@
|
|
118
|
+
uses: actions/download-artifact@v4
|
|
119
119
|
with:
|
|
120
120
|
name: executable-Linux
|
|
121
121
|
path: .
|
|
122
122
|
|
|
123
123
|
- name: Download MacOS artifact
|
|
124
|
-
uses: actions/download-artifact@
|
|
124
|
+
uses: actions/download-artifact@v4
|
|
125
125
|
with:
|
|
126
126
|
name: executable-macOS
|
|
127
127
|
path: .
|
|
@@ -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,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: tau-fibrils-yolo
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
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
|
|
@@ -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,13 +691,16 @@ 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
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 EM images.
|
|
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
705
|
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)] [[`Training`](#training)]
|
|
700
706
|
|
|
@@ -702,13 +708,7 @@ This project is part of a collaboration between the [EPFL Center for Imaging](ht
|
|
|
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,71 +728,32 @@ 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()
|
|
760
|
-
|
|
761
|
-
boxes, probabilities = detector.predict(your_image)
|
|
762
|
-
```
|
|
741
|
+
or open the plugin from `Plugins > Tau fibrils detection`.
|
|
763
742
|
|
|
764
|
-
**
|
|
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
|
-
|
|
773
|
-
|
|
774
|
-
```
|
|
775
|
-
folder/
|
|
776
|
-
├── image_001.tif
|
|
777
|
-
├── image_001_results.csv
|
|
778
|
-
```
|
|
779
|
-
|
|
780
|
-
Optionally, you can use the `-r` flag to also rescale the image by a given factor.
|
|
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:
|
|
751
|
+
This command will run the YOLO model and save a CSV file containing measurements next to the image:
|
|
789
752
|
|
|
790
753
|
```
|
|
791
754
|
folder/
|
|
792
755
|
├── image_001.tif
|
|
793
756
|
├── image_001_results.csv
|
|
794
|
-
├── image_002.tif
|
|
795
|
-
├── image_002_results.csv
|
|
796
757
|
```
|
|
797
758
|
|
|
798
759
|
## Training
|
|
@@ -3,7 +3,7 @@
|
|
|
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 EM images.
|
|
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
8
|
[[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)] [[`Training`](#training)]
|
|
9
9
|
|
|
@@ -11,13 +11,7 @@ This project is part of a collaboration between the [EPFL Center for Imaging](ht
|
|
|
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,71 +31,32 @@ 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()
|
|
69
|
-
|
|
70
|
-
boxes, probabilities = detector.predict(your_image)
|
|
71
|
-
```
|
|
44
|
+
or open the plugin from `Plugins > Tau fibrils detection`.
|
|
72
45
|
|
|
73
|
-
**
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
folder/
|
|
85
|
-
├── image_001.tif
|
|
86
|
-
├── image_001_results.csv
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Optionally, you can use the `-r` flag to also rescale the image by a given factor.
|
|
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:
|
|
54
|
+
This command will run the YOLO model and save a CSV file containing measurements next to the image:
|
|
98
55
|
|
|
99
56
|
```
|
|
100
57
|
folder/
|
|
101
58
|
├── image_001.tif
|
|
102
59
|
├── image_001_results.csv
|
|
103
|
-
├── image_002.tif
|
|
104
|
-
├── image_002_results.csv
|
|
105
60
|
```
|
|
106
61
|
|
|
107
62
|
## Training
|
|
Binary file
|
|
@@ -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
|