tau-fibrils-yolo 0.0.6__tar.gz → 0.1.1__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 (40) hide show
  1. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/.github/workflows/release_multiplatform.yml +6 -6
  2. tau_fibrils_yolo-0.1.1/.gitignore +34 -0
  3. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/PKG-INFO +15 -55
  4. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/README.md +7 -52
  5. tau_fibrils_yolo-0.1.1/assets/screenshot.png +0 -0
  6. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/pyproject.toml +6 -2
  7. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/__init__.py +28 -0
  8. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/_version.py +34 -0
  9. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/boxes_utils.py +111 -0
  10. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/cli.py +60 -0
  11. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/model/100ep.pt +0 -0
  12. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/sample/sample.tif +0 -0
  13. tau_fibrils_yolo-0.1.1/src/tau_fibrils_yolo/widget.py +230 -0
  14. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo.egg-info/PKG-INFO +15 -55
  15. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo.egg-info/SOURCES.txt +5 -6
  16. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo.egg-info/requires.txt +2 -1
  17. tau_fibrils_yolo-0.0.6/.github/workflows/release.yml +0 -126
  18. tau_fibrils_yolo-0.0.6/.gitignore +0 -171
  19. tau_fibrils_yolo-0.0.6/assets/screenshot.png +0 -0
  20. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/__init__.py +0 -8
  21. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/_version.py +0 -16
  22. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/_widget.py +0 -294
  23. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/cli.py +0 -102
  24. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/measure.py +0 -91
  25. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/postprocess.py +0 -78
  26. tau_fibrils_yolo-0.0.6/src/tau_fibrils_yolo/predict.py +0 -168
  27. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/LICENSE +0 -0
  28. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/MANIFEST.in +0 -0
  29. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/assets/icon.png +0 -0
  30. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/scripts/00_annotate.py +0 -0
  31. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/scripts/01_shapes_to_labels.py +0 -0
  32. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/scripts/02_split_train_valid.py +0 -0
  33. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/scripts/03_train_yolo.py +0 -0
  34. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/scripts/instructions.md +0 -0
  35. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/setup.cfg +0 -0
  36. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo/__main__.py +0 -0
  37. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo/napari.yaml +0 -0
  38. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo.egg-info/dependency_links.txt +0 -0
  39. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/src/tau_fibrils_yolo.egg-info/entry_points.txt +0 -0
  40. {tau_fibrils_yolo-0.0.6 → tau_fibrils_yolo-0.1.1}/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
@@ -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.9'
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@v2
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@v2
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@v2
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@v2
124
+ uses: actions/download-artifact@v4
125
125
  with:
126
126
  name: executable-macOS
127
127
  path: .
@@ -0,0 +1,34 @@
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
+ trained_models/
31
+ pretrained_models/
32
+ qupath/
33
+ output/
34
+ notebooks/
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: tau-fibrils-yolo
3
- Version: 0.0.6
3
+ Version: 0.1.1
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
@@ -683,18 +686,20 @@ Requires-Dist: numpy
683
686
  Requires-Dist: pandas
684
687
  Requires-Dist: tifffile
685
688
  Requires-Dist: matplotlib
686
- Requires-Dist: pooch==1.8.0
687
689
  Requires-Dist: scikit-image
688
690
  Requires-Dist: scikit-learn
689
691
  Requires-Dist: ultralytics
690
692
  Requires-Dist: opencv-contrib-python-headless
693
+ Requires-Dist: imaging-server-kit==0.1.3
694
+ Requires-Dist: napari-serverkit==0.0.9
695
+ Dynamic: license-file
691
696
 
692
697
  ![EPFL Center for Imaging logo](https://imaging.epfl.ch/resources/logo-for-gitlab.svg)
693
698
  # 🧬 Tau Fibrils Yolo - Object detection in EM images
694
699
 
695
700
  ![screenshot](assets/screenshot.png)
696
701
 
697
- We provide a [YoloV8](https://docs.ultralytics.com/) model for the detection of oriented bounding boxes (OBBs) of Tau fibrils in EM images.
702
+ 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
703
 
699
704
  [[`Installation`](#installation)] [[`Model`](#model)] [[`Usage`](#usage)] [[`Training`](#training)]
700
705
 
@@ -702,13 +707,7 @@ This project is part of a collaboration between the [EPFL Center for Imaging](ht
702
707
 
703
708
  ## Installation
704
709
 
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:
710
+ We recommend performing the installation in a clean Python environment. Install the package from PyPi:
712
711
 
713
712
  ```sh
714
713
  pip install tau-fibrils-yolo
@@ -728,71 +727,32 @@ cd tau-fibrils-yolo
728
727
  pip install -e .
729
728
  ```
730
729
 
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
730
  ## Usage
736
731
 
737
732
  **In Napari**
738
733
 
739
- To use our model in Napari, start the viewer with
734
+ To use the model in Napari, start the viewer with
740
735
 
741
736
  ```sh
742
737
  napari -w tau-fibrils-yolo
743
738
  ```
744
739
 
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()
760
-
761
- boxes, probabilities = detector.predict(your_image)
762
- ```
740
+ or open the plugin from `Plugins > Tau fibrils detection`.
763
741
 
764
- **As a CLI**
742
+ **From the command-line**
765
743
 
766
- Run inference on an image from the command-line. For example:
744
+ Run inference on an image from the command-line:
767
745
 
768
746
  ```sh
769
747
  tau_fibrils_predict_image -i /path/to/folder/image_001.tif
770
748
  ```
771
749
 
772
- The command will save the segmentation next to the image:
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:
750
+ This command will run the YOLO model and save a CSV file containing measurements next to the image:
789
751
 
790
752
  ```
791
753
  folder/
792
754
  ├── image_001.tif
793
755
  ├── image_001_results.csv
794
- ├── image_002.tif
795
- ├── image_002_results.csv
796
756
  ```
797
757
 
798
758
  ## Training
@@ -3,7 +3,7 @@
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 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
- ### 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,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 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()
69
-
70
- boxes, probabilities = detector.predict(your_image)
71
- ```
44
+ or open the plugin from `Plugins > Tau fibrils detection`.
72
45
 
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:
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
@@ -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
 
@@ -24,11 +27,12 @@ dependencies = [
24
27
  "pandas",
25
28
  "tifffile",
26
29
  "matplotlib",
27
- "pooch==1.8.0",
28
30
  "scikit-image",
29
31
  "scikit-learn",
30
32
  "ultralytics",
31
- "opencv-contrib-python-headless"
33
+ "opencv-contrib-python-headless",
34
+ "imaging-server-kit==0.1.3",
35
+ "napari-serverkit==0.0.9",
32
36
  ]
33
37
 
34
38
  [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, napari_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, napari_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.1'
32
+ __version_tuple__ = version_tuple = (0, 1, 1)
33
+
34
+ __commit_id__ = commit_id = 'g697cbb526'
@@ -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)