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.
Files changed (38) hide show
  1. tau_fibrils_yolo-0.0.5/.github/workflows/release.yml → tau_fibrils_yolo-0.1.0/.github/workflows/release_multiplatform.yml +52 -10
  2. tau_fibrils_yolo-0.1.0/.gitignore +33 -0
  3. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/PKG-INFO +20 -55
  4. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/README.md +11 -52
  5. tau_fibrils_yolo-0.1.0/assets/screenshot.png +0 -0
  6. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/pyproject.toml +7 -2
  7. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/__init__.py +28 -0
  8. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/_version.py +34 -0
  9. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/boxes_utils.py +111 -0
  10. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/cli.py +60 -0
  11. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/sample/sample.tif +0 -0
  12. tau_fibrils_yolo-0.1.0/src/tau_fibrils_yolo/widget.py +248 -0
  13. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/PKG-INFO +20 -55
  14. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/SOURCES.txt +5 -6
  15. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/requires.txt +2 -0
  16. tau_fibrils_yolo-0.0.5/.gitignore +0 -171
  17. tau_fibrils_yolo-0.0.5/assets/screenshot.png +0 -0
  18. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/__init__.py +0 -8
  19. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/_version.py +0 -16
  20. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/_widget.py +0 -294
  21. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/cli.py +0 -102
  22. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/measure.py +0 -91
  23. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/postprocess.py +0 -78
  24. tau_fibrils_yolo-0.0.5/src/tau_fibrils_yolo/predict.py +0 -168
  25. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/LICENSE +0 -0
  26. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/MANIFEST.in +0 -0
  27. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/assets/icon.png +0 -0
  28. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/00_annotate.py +0 -0
  29. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/01_shapes_to_labels.py +0 -0
  30. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/02_split_train_valid.py +0 -0
  31. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/03_train_yolo.py +0 -0
  32. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/scripts/instructions.md +0 -0
  33. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/setup.cfg +0 -0
  34. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/__main__.py +0 -0
  35. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo/napari.yaml +0 -0
  36. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/dependency_links.txt +0 -0
  37. {tau_fibrils_yolo-0.0.5 → tau_fibrils_yolo-0.1.0}/src/tau_fibrils_yolo.egg-info/entry_points.txt +0 -0
  38. {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.9"
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 for Windows
74
+ - name: Build executable
75
75
  env:
76
76
  PYAPP_PROJECT_VERSION: ${{ env.VERSION }}
77
- PYAPP_PYTHON_VERSION: '3.9'
77
+ PYAPP_PYTHON_VERSION: '3.10'
78
78
  run: cargo build --release --manifest-path pyapp-latest/Cargo.toml
79
79
 
80
- - name: Archive Windows executable
80
+ - name: Archive executable
81
81
  shell: bash
82
82
  working-directory: pyapp-latest/target/release
83
83
  run: |
84
- EXECUTABLE_NAME=${{ env.PYAPP_PROJECT_NAME }}_${{ runner.os }}_${{ env.VERSION }}.exe
85
- mv pyapp.exe $EXECUTABLE_NAME
86
- tar -czvf ../../../executable-windows.tar.gz $EXECUTABLE_NAME
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@v2
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@v2
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
1
+ Metadata-Version: 2.4
2
2
  Name: tau-fibrils-yolo
3
- Version: 0.0.5
4
- Summary: YoloV8 model for the detection of Tau fibrils in Cryo-EM images.
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
  ![EPFL Center for Imaging logo](https://imaging.epfl.ch/resources/logo-for-gitlab.svg)
693
- # 🧬 Tau Fibrils Yolo - Object detection in Cryo-EM images
699
+ # 🧬 Tau Fibrils Yolo - Object detection in EM images
694
700
 
695
701
  ![screenshot](assets/screenshot.png)
696
702
 
697
- We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in Cryo-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
- [[`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
- ### As a standalone app
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 our model in Napari, start the viewer with
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 Napari menu bar and select `Plugins > Tau fibrils detection`.
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
- boxes, probabilities = detector.predict(your_image)
762
- ```
763
-
764
- **As a CLI**
743
+ **From the command-line**
765
744
 
766
- Run inference on an image from the command-line. For example:
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
- The command will save the segmentation next to the image:
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
- 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:
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
  ![EPFL Center for Imaging logo](https://imaging.epfl.ch/resources/logo-for-gitlab.svg)
2
- # 🧬 Tau Fibrils Yolo - Object detection in Cryo-EM images
2
+ # 🧬 Tau Fibrils Yolo - Object detection in EM images
3
3
 
4
4
  ![screenshot](assets/screenshot.png)
5
5
 
6
- We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in Cryo-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
- [[`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
- ### As a standalone app
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 our model in Napari, start the viewer with
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 Napari menu bar and select `Plugins > Tau fibrils detection`.
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
- boxes, probabilities = detector.predict(your_image)
71
- ```
72
-
73
- **As a CLI**
46
+ **From the command-line**
74
47
 
75
- Run inference on an image from the command-line. For example:
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
- The command will save the segmentation next to the image:
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
- 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:
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
 
@@ -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 Cryo-EM images."
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)