cellfinder 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl
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.
Potentially problematic release.
This version of cellfinder might be problematic. Click here for more details.
- cellfinder/__init__.py +7 -3
- cellfinder/main.py +1 -1
- cellfinder/tools/parser.py +2 -2
- cellfinder/tools/prep.py +1 -1
- cellfinder/tools/tools.py +2 -2
- {cellfinder-0.7.0.dist-info → cellfinder-0.8.0.dist-info}/METADATA +45 -16
- {cellfinder-0.7.0.dist-info → cellfinder-0.8.0.dist-info}/RECORD +11 -14
- {cellfinder-0.7.0.dist-info → cellfinder-0.8.0.dist-info}/WHEEL +1 -1
- cellfinder-0.8.0.dist-info/entry_points.txt +2 -0
- cellfinder/train/__init__.py +0 -0
- cellfinder/train/curation.py +0 -355
- cellfinder/train/curation_old.py +0 -287
- cellfinder-0.7.0.dist-info/entry_points.txt +0 -4
- {cellfinder-0.7.0.dist-info → cellfinder-0.8.0.dist-info}/LICENSE +0 -0
- {cellfinder-0.7.0.dist-info → cellfinder-0.8.0.dist-info}/top_level.txt +0 -0
cellfinder/__init__.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
from importlib.metadata import metadata
|
|
2
|
+
|
|
3
|
+
__version__ = metadata("cellfinder")["version"]
|
|
4
|
+
__author__ = metadata("cellfinder")["author-email"]
|
|
5
|
+
__license__ = metadata("cellfinder")["license"]
|
|
6
|
+
|
|
7
|
+
del metadata
|
cellfinder/main.py
CHANGED
cellfinder/tools/parser.py
CHANGED
|
@@ -16,8 +16,8 @@ from brainglobe_utils.general.numerical import (
|
|
|
16
16
|
check_positive_float,
|
|
17
17
|
check_positive_int,
|
|
18
18
|
)
|
|
19
|
-
from brainreg.cli import atlas_parse, geometry_parser, niftyreg_parse
|
|
20
|
-
from brainreg.cli import backend_parse as brainreg_backend_parse
|
|
19
|
+
from brainreg.core.cli import atlas_parse, geometry_parser, niftyreg_parse
|
|
20
|
+
from brainreg.core.cli import backend_parse as brainreg_backend_parse
|
|
21
21
|
from cellfinder_core.download.cli import (
|
|
22
22
|
download_directory_parser,
|
|
23
23
|
model_parser,
|
cellfinder/tools/prep.py
CHANGED
|
@@ -14,7 +14,7 @@ from pathlib import PurePath
|
|
|
14
14
|
from bg_atlasapi import BrainGlobeAtlas
|
|
15
15
|
from brainglobe_utils.general.exceptions import CommandLineInputError
|
|
16
16
|
from brainglobe_utils.general.system import ensure_directory_exists
|
|
17
|
-
from brainreg.paths import Paths as BrainRegPaths
|
|
17
|
+
from brainreg.core.paths import Paths as BrainRegPaths
|
|
18
18
|
from fancylog import fancylog
|
|
19
19
|
|
|
20
20
|
import cellfinder as program_for_log
|
cellfinder/tools/tools.py
CHANGED
|
@@ -80,9 +80,9 @@ def get_number_of_bins_nd(array_size, binning):
|
|
|
80
80
|
:param binning: How many pixels in each edge of nD equal sized bins
|
|
81
81
|
:return:
|
|
82
82
|
"""
|
|
83
|
-
if
|
|
83
|
+
if isinstance(array_size, tuple):
|
|
84
84
|
bins = [int(size / binning) for size in array_size]
|
|
85
|
-
elif
|
|
85
|
+
elif isinstance(array_size, dict):
|
|
86
86
|
bins = [int(size / binning) for size in array_size.values()]
|
|
87
87
|
else:
|
|
88
88
|
raise NotImplementedError(
|
|
@@ -1,13 +1,43 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cellfinder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Automated 3D cell detection and registration of whole-brain images
|
|
5
|
-
|
|
6
|
-
Author: Adam Tyson
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
Author: Christian Niedworok, Charly Rousseau
|
|
6
|
+
Author-email: Adam Tyson <code@adamltyson.com>
|
|
7
|
+
License: BSD 3-Clause License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2020, University College London
|
|
10
|
+
All rights reserved.
|
|
11
|
+
|
|
12
|
+
Redistribution and use in source and binary forms, with or without
|
|
13
|
+
modification, are permitted provided that the following conditions are met:
|
|
14
|
+
|
|
15
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
16
|
+
list of conditions and the following disclaimer.
|
|
17
|
+
|
|
18
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
19
|
+
this list of conditions and the following disclaimer in the documentation
|
|
20
|
+
and/or other materials provided with the distribution.
|
|
21
|
+
|
|
22
|
+
* Neither the name of the copyright holder nor the names of its
|
|
23
|
+
contributors may be used to endorse or promote products derived from
|
|
24
|
+
this software without specific prior written permission.
|
|
25
|
+
|
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
27
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
28
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
29
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
30
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
31
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
32
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
33
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
34
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
35
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
|
+
|
|
37
|
+
Project-URL: source, https://github.com/brainglobe/cellfinder
|
|
38
|
+
Project-URL: bug_tracker, https://github.com/brainglobe/cellfinder/issues
|
|
39
|
+
Project-URL: homepage, https://brainglobe.info
|
|
40
|
+
Project-URL: documentation, https://brainglobe.info/documentation/cellfinder
|
|
11
41
|
Classifier: Development Status :: 3 - Alpha
|
|
12
42
|
Classifier: Operating System :: POSIX :: Linux
|
|
13
43
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
@@ -18,16 +48,16 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
48
|
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
19
49
|
Classifier: Intended Audience :: Developers
|
|
20
50
|
Classifier: Intended Audience :: Science/Research
|
|
21
|
-
Requires-Python: >=3.
|
|
51
|
+
Requires-Python: >=3.9
|
|
22
52
|
Description-Content-Type: text/markdown
|
|
23
53
|
License-File: LICENSE
|
|
24
|
-
Requires-Dist: brainreg
|
|
25
|
-
Requires-Dist: cellfinder-core
|
|
54
|
+
Requires-Dist: brainreg >=1.0.0
|
|
55
|
+
Requires-Dist: cellfinder-core >=0.2.4
|
|
26
56
|
Requires-Dist: configobj
|
|
27
|
-
Requires-Dist: fancylog
|
|
57
|
+
Requires-Dist: fancylog >=0.0.7
|
|
28
58
|
Requires-Dist: imio
|
|
29
|
-
Requires-Dist: brainglobe-utils
|
|
30
|
-
Requires-Dist: multiprocessing-logging
|
|
59
|
+
Requires-Dist: brainglobe-utils >=0.2.5
|
|
60
|
+
Requires-Dist: multiprocessing-logging >=0.3.4
|
|
31
61
|
Requires-Dist: natsort
|
|
32
62
|
Requires-Dist: numpy
|
|
33
63
|
Requires-Dist: pandas
|
|
@@ -40,10 +70,9 @@ Requires-Dist: black ; extra == 'dev'
|
|
|
40
70
|
Requires-Dist: pytest-cov ; extra == 'dev'
|
|
41
71
|
Requires-Dist: pytest ; extra == 'dev'
|
|
42
72
|
Requires-Dist: gitpython ; extra == 'dev'
|
|
43
|
-
Requires-Dist: coverage
|
|
44
|
-
Requires-Dist: bump2version ; extra == 'dev'
|
|
73
|
+
Requires-Dist: coverage >=5.0.3 ; extra == 'dev'
|
|
45
74
|
Requires-Dist: pre-commit ; extra == 'dev'
|
|
46
|
-
Requires-Dist:
|
|
75
|
+
Requires-Dist: setuptools-scm ; extra == 'dev'
|
|
47
76
|
Provides-Extra: napari
|
|
48
77
|
Requires-Dist: napari[pyside2] ; extra == 'napari'
|
|
49
78
|
Requires-Dist: brainglobe-napari-io ; extra == 'napari'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
cellfinder/__init__.py,sha256=
|
|
2
|
-
cellfinder/main.py,sha256=
|
|
1
|
+
cellfinder/__init__.py,sha256=TOTszmwu6-ukckrUEstKsi1A0Yt6aue2P5OPE2NVt0U,203
|
|
2
|
+
cellfinder/main.py,sha256=pIWLWp-rGp2-xDf6E9ehXyt9mjJMYTW8I0KWjBWCq4o,7390
|
|
3
3
|
cellfinder/analyse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
cellfinder/analyse/analyse.py,sha256=8Wf3nUpBqGdu2PuJFIzdHHDnrkSDsk0WZRUj5COCaM0,11010
|
|
5
5
|
cellfinder/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -13,16 +13,13 @@ cellfinder/figures/figures.py,sha256=ughsNeTM6YnBtRakNfMB_jmPOTzaOgpqFdb28SZH4Ts
|
|
|
13
13
|
cellfinder/figures/heatmap.py,sha256=ayKbv-vDhnpdv5vYIayEwzDmU_rmyzPQ7TknRvcouec,1951
|
|
14
14
|
cellfinder/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
cellfinder/tools/image_processing.py,sha256=z27bGjf3Iv3G4Nt1OYzpEnIYQNc4nNomj_QitqvZB78,2269
|
|
16
|
-
cellfinder/tools/parser.py,sha256=
|
|
17
|
-
cellfinder/tools/prep.py,sha256=
|
|
16
|
+
cellfinder/tools/parser.py,sha256=7FJFUi3OJcSpuXm1ikZIJIFen2_Y8FtI-13T-ZIzGiI,13577
|
|
17
|
+
cellfinder/tools/prep.py,sha256=7SqxBdzP4U3tH4oWkYo7vnC79tgqLS5PTDW-KWwjyt4,11124
|
|
18
18
|
cellfinder/tools/system.py,sha256=6iSOLrz2mtKgOIdwjp_VS0-74XQCuaQYCvWAViJgEus,2232
|
|
19
|
-
cellfinder/tools/tools.py,sha256=
|
|
20
|
-
cellfinder/
|
|
21
|
-
cellfinder/
|
|
22
|
-
cellfinder/
|
|
23
|
-
cellfinder-0.
|
|
24
|
-
cellfinder-0.
|
|
25
|
-
cellfinder-0.
|
|
26
|
-
cellfinder-0.7.0.dist-info/entry_points.txt,sha256=g7ZJi8oEOOxNuA3BXT_fAm9RKWtEZ3Vah6M-SlFt2wk,162
|
|
27
|
-
cellfinder-0.7.0.dist-info/top_level.txt,sha256=jyTQzX-tDjbsMr6s-E71Oy0IKQzmHTXSk4ZhpG5EDSE,11
|
|
28
|
-
cellfinder-0.7.0.dist-info/RECORD,,
|
|
19
|
+
cellfinder/tools/tools.py,sha256=Km4Y1p3yQOYi_dyTOZthJXcvUintIzTUYwDkuXGNc0A,3635
|
|
20
|
+
cellfinder-0.8.0.dist-info/LICENSE,sha256=zyXpitCrNwvc33VKBFomd9v6Ahi9x1H5fvfXDxCblM0,1525
|
|
21
|
+
cellfinder-0.8.0.dist-info/METADATA,sha256=LiFR_CUo5hxSYUBO4Un2NrdWc50ymOuym472Syi63ss,11634
|
|
22
|
+
cellfinder-0.8.0.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
23
|
+
cellfinder-0.8.0.dist-info/entry_points.txt,sha256=n3M2y93q1QNL0MnYqyaJ5yWl8j4YJ-OHitghTwiGuvk,52
|
|
24
|
+
cellfinder-0.8.0.dist-info/top_level.txt,sha256=jyTQzX-tDjbsMr6s-E71Oy0IKQzmHTXSk4ZhpG5EDSE,11
|
|
25
|
+
cellfinder-0.8.0.dist-info/RECORD,,
|
cellfinder/train/__init__.py
DELETED
|
File without changes
|
cellfinder/train/curation.py
DELETED
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
import napari
|
|
5
|
-
import numpy as np
|
|
6
|
-
from bg_atlasapi import BrainGlobeAtlas
|
|
7
|
-
from brainglobe_utils.cells.cells import Cell
|
|
8
|
-
from brainglobe_utils.general.system import get_sorted_file_paths
|
|
9
|
-
from brainglobe_utils.IO.cells import save_cells
|
|
10
|
-
from brainreg.paths import Paths as BrainregPaths
|
|
11
|
-
from brainreg_segment.layout.gui_elements import add_button
|
|
12
|
-
from napari.utils.io import magic_imread
|
|
13
|
-
from napari_cellfinder.cellfinder import get_cell_arrays
|
|
14
|
-
from qtpy import QtCore
|
|
15
|
-
from qtpy.QtWidgets import QFileDialog, QGridLayout, QGroupBox, QLabel, QWidget
|
|
16
|
-
|
|
17
|
-
from cellfinder.analyse.analyse import run_analysis
|
|
18
|
-
from cellfinder.main import get_downsampled_space
|
|
19
|
-
|
|
20
|
-
# Constants used throughout
|
|
21
|
-
WINDOW_HEIGHT = 750
|
|
22
|
-
WINDOW_WIDTH = 1500
|
|
23
|
-
COLUMN_WIDTH = 150
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class CurationWidget(QWidget):
|
|
27
|
-
def __init__(
|
|
28
|
-
self,
|
|
29
|
-
viewer,
|
|
30
|
-
):
|
|
31
|
-
super(CurationWidget, self).__init__()
|
|
32
|
-
|
|
33
|
-
self.viewer = viewer
|
|
34
|
-
|
|
35
|
-
self.background_layer = []
|
|
36
|
-
self.background_path = ""
|
|
37
|
-
|
|
38
|
-
self.signal_layer = []
|
|
39
|
-
self.signal_path = ""
|
|
40
|
-
|
|
41
|
-
self.directory = ""
|
|
42
|
-
self.output_directory = None
|
|
43
|
-
|
|
44
|
-
self.setup_main_layout()
|
|
45
|
-
|
|
46
|
-
def setup_main_layout(self):
|
|
47
|
-
"""
|
|
48
|
-
Construct main layout of widget
|
|
49
|
-
"""
|
|
50
|
-
self.layout = QGridLayout()
|
|
51
|
-
self.layout.setContentsMargins(10, 10, 10, 10)
|
|
52
|
-
self.layout.setAlignment(QtCore.Qt.AlignTop)
|
|
53
|
-
self.layout.setSpacing(4)
|
|
54
|
-
|
|
55
|
-
self.add_loading_panel(1)
|
|
56
|
-
|
|
57
|
-
self.status_label = QLabel()
|
|
58
|
-
self.status_label.setText("Ready")
|
|
59
|
-
self.layout.addWidget(self.status_label, 5, 0)
|
|
60
|
-
|
|
61
|
-
self.setLayout(self.layout)
|
|
62
|
-
|
|
63
|
-
def add_loading_panel(self, row, column=0):
|
|
64
|
-
"""
|
|
65
|
-
Loading panel:
|
|
66
|
-
- Load project (sample space)
|
|
67
|
-
- Load project (atlas space)
|
|
68
|
-
- Atlas chooser
|
|
69
|
-
"""
|
|
70
|
-
self.load_data_panel = QGroupBox("Load data")
|
|
71
|
-
self.load_data_layout = QGridLayout()
|
|
72
|
-
self.load_data_layout.setSpacing(15)
|
|
73
|
-
self.load_data_layout.setContentsMargins(10, 10, 10, 10)
|
|
74
|
-
self.load_data_layout.setAlignment(QtCore.Qt.AlignBottom)
|
|
75
|
-
|
|
76
|
-
# self.load_cellfinder_dir_button = add_button(
|
|
77
|
-
# "Load cellfinder project",
|
|
78
|
-
# self.load_data_layout,
|
|
79
|
-
# self.get_cellfinder_directory,
|
|
80
|
-
# 0,
|
|
81
|
-
# 0,
|
|
82
|
-
# minimum_width=COLUMN_WIDTH,
|
|
83
|
-
# )
|
|
84
|
-
|
|
85
|
-
# self.load_background_button = add_button(
|
|
86
|
-
# "Load background",
|
|
87
|
-
# self.load_data_layout,
|
|
88
|
-
# self.get_background,
|
|
89
|
-
# 1,
|
|
90
|
-
# 0,
|
|
91
|
-
# minimum_width=COLUMN_WIDTH,
|
|
92
|
-
# )
|
|
93
|
-
|
|
94
|
-
self.load_signal_button = add_button(
|
|
95
|
-
"Load signal",
|
|
96
|
-
self.load_data_layout,
|
|
97
|
-
self.get_signal,
|
|
98
|
-
2,
|
|
99
|
-
0,
|
|
100
|
-
minimum_width=COLUMN_WIDTH,
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
self.add_cells_button = add_button(
|
|
104
|
-
"Add cell count",
|
|
105
|
-
self.load_data_layout,
|
|
106
|
-
self.add_cell_count,
|
|
107
|
-
3,
|
|
108
|
-
0,
|
|
109
|
-
minimum_width=COLUMN_WIDTH,
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
self.add_cells_button = add_button(
|
|
113
|
-
"Load cell count",
|
|
114
|
-
self.load_data_layout,
|
|
115
|
-
self.load_cells,
|
|
116
|
-
4,
|
|
117
|
-
0,
|
|
118
|
-
minimum_width=COLUMN_WIDTH,
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
self.save_cells_button = add_button(
|
|
122
|
-
"Save cells",
|
|
123
|
-
self.load_data_layout,
|
|
124
|
-
self.save_cell_count,
|
|
125
|
-
5,
|
|
126
|
-
0,
|
|
127
|
-
minimum_width=COLUMN_WIDTH,
|
|
128
|
-
)
|
|
129
|
-
self.analyse_cells_button = add_button(
|
|
130
|
-
"Analyse cells",
|
|
131
|
-
self.load_data_layout,
|
|
132
|
-
self.analyse_cells,
|
|
133
|
-
6,
|
|
134
|
-
0,
|
|
135
|
-
minimum_width=COLUMN_WIDTH,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
self.load_data_layout.setColumnMinimumWidth(0, COLUMN_WIDTH)
|
|
139
|
-
self.load_data_panel.setLayout(self.load_data_layout)
|
|
140
|
-
self.load_data_panel.setVisible(True)
|
|
141
|
-
self.layout.addWidget(self.load_data_panel, row, column, 1, 1)
|
|
142
|
-
|
|
143
|
-
def get_cellfinder_directory(self):
|
|
144
|
-
self.status_label.setText("Loading...")
|
|
145
|
-
options = QFileDialog.Options()
|
|
146
|
-
options |= QFileDialog.DontUseNativeDialog
|
|
147
|
-
cellfinder_directory = QFileDialog.getExistingDirectory(
|
|
148
|
-
self,
|
|
149
|
-
"Select cellfinder directory",
|
|
150
|
-
options=options,
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
if not cellfinder_directory:
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
if self.directory != cellfinder_directory:
|
|
157
|
-
self.directory = Path(cellfinder_directory)
|
|
158
|
-
else:
|
|
159
|
-
print(f"{str(cellfinder_directory)} already loaded.")
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
# Otherwise, proceed loading brainreg dir
|
|
163
|
-
self.load_cellfinder_directory()
|
|
164
|
-
self.status_label.setText("Ready...")
|
|
165
|
-
|
|
166
|
-
def load_cellfinder_directory(self):
|
|
167
|
-
try:
|
|
168
|
-
self.viewer.open(str(self.directory), plugin="cellfinder")
|
|
169
|
-
except ValueError:
|
|
170
|
-
print(
|
|
171
|
-
f"The directory ({self.directory}) does not appear to be "
|
|
172
|
-
f"a cellfinder directory, please try again."
|
|
173
|
-
)
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
def get_background(self):
|
|
177
|
-
self.background_layer, self.background_path = self.get_data(
|
|
178
|
-
name="background", visible=False
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
def get_signal(self):
|
|
182
|
-
self.signal_layer, self.signal_path = self.get_data(name="signal")
|
|
183
|
-
self.status_label.setText("Ready")
|
|
184
|
-
|
|
185
|
-
def get_data(self, name="", visible=True):
|
|
186
|
-
self.status_label.setText("Loading...")
|
|
187
|
-
options = QFileDialog.Options()
|
|
188
|
-
options |= QFileDialog.DontUseNativeDialog
|
|
189
|
-
directory = QFileDialog.getExistingDirectory(
|
|
190
|
-
self,
|
|
191
|
-
f"Select {name} channel",
|
|
192
|
-
options=options,
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
if not directory:
|
|
196
|
-
return
|
|
197
|
-
|
|
198
|
-
if self.directory != directory:
|
|
199
|
-
self.directory = Path(directory)
|
|
200
|
-
else:
|
|
201
|
-
print(f"{str(directory)} already loaded.")
|
|
202
|
-
return
|
|
203
|
-
|
|
204
|
-
return self.load_data(name=name, visible=visible), directory
|
|
205
|
-
|
|
206
|
-
def load_data(self, name="", visible=True):
|
|
207
|
-
try:
|
|
208
|
-
img_paths = get_sorted_file_paths(
|
|
209
|
-
self.directory, file_extension=".tif"
|
|
210
|
-
)
|
|
211
|
-
images = magic_imread(img_paths, use_dask=True, stack=True)
|
|
212
|
-
return self.viewer.add_image(images)
|
|
213
|
-
# return self.viewer.open(
|
|
214
|
-
# str(self.directory), name=name, visible=visible
|
|
215
|
-
# )
|
|
216
|
-
except ValueError:
|
|
217
|
-
print(
|
|
218
|
-
f"The directory ({self.directory}) cannot be "
|
|
219
|
-
f"loaded, please try again."
|
|
220
|
-
)
|
|
221
|
-
return
|
|
222
|
-
|
|
223
|
-
def add_cell_count(self):
|
|
224
|
-
self.cell_layer = self.viewer.add_points(
|
|
225
|
-
np.empty((0, 3)),
|
|
226
|
-
symbol="ring",
|
|
227
|
-
n_dimensional=True,
|
|
228
|
-
size=10,
|
|
229
|
-
opacity=0.6,
|
|
230
|
-
face_color="lightgoldenrodyellow",
|
|
231
|
-
name="cells",
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
def load_cells(self):
|
|
235
|
-
options = QFileDialog.Options()
|
|
236
|
-
options |= QFileDialog.DontUseNativeDialog
|
|
237
|
-
filename = QFileDialog.getOpenFileName(
|
|
238
|
-
self,
|
|
239
|
-
"Select cell file...",
|
|
240
|
-
filter="cellfinder xml files (*.xml)",
|
|
241
|
-
options=options,
|
|
242
|
-
)
|
|
243
|
-
cells, _ = get_cell_arrays(filename[0])
|
|
244
|
-
|
|
245
|
-
self.cell_layer = self.viewer.add_points(
|
|
246
|
-
cells,
|
|
247
|
-
symbol="ring",
|
|
248
|
-
n_dimensional=True,
|
|
249
|
-
size=10,
|
|
250
|
-
opacity=0.6,
|
|
251
|
-
face_color="lightgoldenrodyellow",
|
|
252
|
-
name="cells",
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
def save_cell_count(self):
|
|
256
|
-
self.status_label.setText("Saving cells")
|
|
257
|
-
print("Saving cells")
|
|
258
|
-
self.get_output_directory()
|
|
259
|
-
filename = self.output_directory / "cells.xml"
|
|
260
|
-
|
|
261
|
-
cells_to_save = []
|
|
262
|
-
for idx, point in enumerate(self.cell_layer.data):
|
|
263
|
-
cell = Cell([point[2], point[1], point[0]], Cell.CELL)
|
|
264
|
-
cells_to_save.append(cell)
|
|
265
|
-
|
|
266
|
-
save_cells(cells_to_save, str(filename))
|
|
267
|
-
|
|
268
|
-
self.status_label.setText("Ready")
|
|
269
|
-
print("Done!")
|
|
270
|
-
|
|
271
|
-
def get_output_directory(self):
|
|
272
|
-
if self.output_directory is None:
|
|
273
|
-
options = QFileDialog.Options()
|
|
274
|
-
options |= QFileDialog.DontUseNativeDialog
|
|
275
|
-
self.output_directory = QFileDialog.getExistingDirectory(
|
|
276
|
-
self,
|
|
277
|
-
"Select output directory",
|
|
278
|
-
options=options,
|
|
279
|
-
)
|
|
280
|
-
self.output_directory = Path(self.output_directory)
|
|
281
|
-
|
|
282
|
-
def analyse_cells(self):
|
|
283
|
-
self.status_label.setText("Analysing cells")
|
|
284
|
-
print("Analysing cells")
|
|
285
|
-
|
|
286
|
-
self.get_output_directory()
|
|
287
|
-
self.get_brainreg_directory()
|
|
288
|
-
|
|
289
|
-
analyse_cell_positions(
|
|
290
|
-
self.cell_layer.data,
|
|
291
|
-
self.brainreg_directory,
|
|
292
|
-
self.signal_path,
|
|
293
|
-
self.output_directory,
|
|
294
|
-
)
|
|
295
|
-
self.status_label.setText("Ready")
|
|
296
|
-
|
|
297
|
-
def get_brainreg_directory(self):
|
|
298
|
-
options = QFileDialog.Options()
|
|
299
|
-
options |= QFileDialog.DontUseNativeDialog
|
|
300
|
-
self.brainreg_directory = QFileDialog.getExistingDirectory(
|
|
301
|
-
self,
|
|
302
|
-
"Select brainreg directory",
|
|
303
|
-
options=options,
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def analyse_cell_positions(
|
|
308
|
-
points, brainreg_directory, signal_path, output_directory
|
|
309
|
-
):
|
|
310
|
-
brainreg_paths = BrainregPaths(brainreg_directory)
|
|
311
|
-
|
|
312
|
-
with open(brainreg_paths.metadata_path) as json_file:
|
|
313
|
-
metadata = json.load(json_file)
|
|
314
|
-
|
|
315
|
-
atlas = BrainGlobeAtlas(metadata["atlas"])
|
|
316
|
-
|
|
317
|
-
downsampled_space = get_downsampled_space(
|
|
318
|
-
atlas, brainreg_paths.boundaries_file_path
|
|
319
|
-
)
|
|
320
|
-
deformation_field_paths = [
|
|
321
|
-
brainreg_paths.deformation_field_0,
|
|
322
|
-
brainreg_paths.deformation_field_1,
|
|
323
|
-
brainreg_paths.deformation_field_2,
|
|
324
|
-
]
|
|
325
|
-
|
|
326
|
-
run_analysis(
|
|
327
|
-
points,
|
|
328
|
-
signal_path,
|
|
329
|
-
metadata["orientation"],
|
|
330
|
-
metadata["voxel_sizes"],
|
|
331
|
-
atlas,
|
|
332
|
-
deformation_field_paths,
|
|
333
|
-
downsampled_space,
|
|
334
|
-
output_directory / "downsampled.points",
|
|
335
|
-
output_directory / "atlas.points",
|
|
336
|
-
output_directory / "points.npy",
|
|
337
|
-
brainreg_paths.volume_csv_path,
|
|
338
|
-
output_directory / "all_points.csv",
|
|
339
|
-
output_directory / "summary.csv",
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
print("Done")
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def main():
|
|
346
|
-
print("Loading curation GUI.\n ")
|
|
347
|
-
with napari.gui_qt():
|
|
348
|
-
viewer = napari.Viewer(title="Curation GUI")
|
|
349
|
-
viewer.window.resize(WINDOW_WIDTH, WINDOW_HEIGHT)
|
|
350
|
-
widget = CurationWidget(viewer)
|
|
351
|
-
viewer.window.add_dock_widget(widget, name="Curation", area="right")
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if __name__ == "__main__":
|
|
355
|
-
main()
|
cellfinder/train/curation_old.py
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
import napari
|
|
5
|
-
import numpy as np
|
|
6
|
-
from brainglobe_utils.cells.cells import Cell
|
|
7
|
-
from brainglobe_utils.general.list import unique_elements_lists
|
|
8
|
-
from brainglobe_utils.general.system import (
|
|
9
|
-
ensure_directory_exists,
|
|
10
|
-
get_sorted_file_paths,
|
|
11
|
-
)
|
|
12
|
-
from brainglobe_utils.IO.cells import cells_xml_to_df, get_cells, save_cells
|
|
13
|
-
from brainglobe_utils.IO.yaml import save_yaml
|
|
14
|
-
from napari.utils.io import magic_imread
|
|
15
|
-
from qtpy.QtWidgets import QApplication
|
|
16
|
-
|
|
17
|
-
import cellfinder.tools.parser as cellfinder_parse
|
|
18
|
-
from cellfinder.extract.extract_cubes import main as extract_cubes_main
|
|
19
|
-
|
|
20
|
-
OUTPUT_NAME = "curated_cells.xml"
|
|
21
|
-
CURATED_POINTS = []
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def parser():
|
|
25
|
-
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
|
|
26
|
-
parser = curation_parser(parser)
|
|
27
|
-
parser = cellfinder_parse.pixel_parser(parser)
|
|
28
|
-
parser = cellfinder_parse.misc_parse(parser)
|
|
29
|
-
parser = cellfinder_parse.cube_extract_parse(parser)
|
|
30
|
-
return parser
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def curation_parser(parser):
|
|
34
|
-
parser.add_argument(
|
|
35
|
-
dest="signal_image_paths", type=str, help="Signal images"
|
|
36
|
-
)
|
|
37
|
-
parser.add_argument(
|
|
38
|
-
dest="background_image_paths",
|
|
39
|
-
type=str,
|
|
40
|
-
help="Background images",
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
parser.add_argument(
|
|
44
|
-
dest="cells_xml", type=str, help="Path to the .xml cell file"
|
|
45
|
-
)
|
|
46
|
-
parser.add_argument(
|
|
47
|
-
"--output",
|
|
48
|
-
"-o",
|
|
49
|
-
type=str,
|
|
50
|
-
default=None,
|
|
51
|
-
help="Output directory for curation results",
|
|
52
|
-
)
|
|
53
|
-
parser.add_argument(
|
|
54
|
-
"--symbol", type=str, default="ring", help="Marker symbol."
|
|
55
|
-
)
|
|
56
|
-
parser.add_argument(
|
|
57
|
-
"--marker-size", type=int, default=15, help="Marker size."
|
|
58
|
-
)
|
|
59
|
-
parser.add_argument(
|
|
60
|
-
"--opacity", type=float, default=0.6, help="Opacity of the markers."
|
|
61
|
-
)
|
|
62
|
-
return parser
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def get_cell_labels_arrays(
|
|
66
|
-
cells_file, new_order=[2, 1, 0], type_column="type"
|
|
67
|
-
):
|
|
68
|
-
df = cells_xml_to_df(cells_file)
|
|
69
|
-
|
|
70
|
-
labels = df[type_column]
|
|
71
|
-
labels = labels.to_numpy()
|
|
72
|
-
cells_df = df.drop(columns=[type_column])
|
|
73
|
-
cells = cells_df[cells_df.columns[new_order]]
|
|
74
|
-
cells = cells.to_numpy()
|
|
75
|
-
|
|
76
|
-
# convert to boolean
|
|
77
|
-
labels = labels == 2
|
|
78
|
-
return cells, labels
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def main():
|
|
82
|
-
args = parser().parse_args()
|
|
83
|
-
# args = define_pixel_sizes(args)
|
|
84
|
-
|
|
85
|
-
if args.output is None:
|
|
86
|
-
output = Path(args.cells_xml)
|
|
87
|
-
output_directory = output.parent
|
|
88
|
-
print(
|
|
89
|
-
f"No output directory given, so setting output "
|
|
90
|
-
f"directory to: {output_directory}"
|
|
91
|
-
)
|
|
92
|
-
else:
|
|
93
|
-
output_directory = Path(args.output)
|
|
94
|
-
|
|
95
|
-
ensure_directory_exists(str(output_directory))
|
|
96
|
-
output_filename = output_directory / OUTPUT_NAME
|
|
97
|
-
|
|
98
|
-
img_paths = get_sorted_file_paths(
|
|
99
|
-
args.signal_image_paths, file_extension=".tif"
|
|
100
|
-
)
|
|
101
|
-
cells, labels = get_cell_labels_arrays(args.cells_xml)
|
|
102
|
-
|
|
103
|
-
properties = {"cell": labels}
|
|
104
|
-
|
|
105
|
-
with napari.gui_qt():
|
|
106
|
-
viewer = napari.Viewer(title="Cellfinder cell curation")
|
|
107
|
-
images = magic_imread(img_paths, use_dask=True, stack=True)
|
|
108
|
-
viewer.add_image(images)
|
|
109
|
-
face_color_cycle = ["lightskyblue", "lightgoldenrodyellow"]
|
|
110
|
-
viewer.add_points(
|
|
111
|
-
cells,
|
|
112
|
-
properties=properties,
|
|
113
|
-
symbol=args.symbol,
|
|
114
|
-
n_dimensional=True,
|
|
115
|
-
size=args.marker_size,
|
|
116
|
-
face_color="cell",
|
|
117
|
-
face_color_cycle=face_color_cycle,
|
|
118
|
-
name="Cell candidates",
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
@viewer.bind_key("t")
|
|
122
|
-
def toggle_point_property(viewer):
|
|
123
|
-
"""Toggle point type"""
|
|
124
|
-
selected_points = list(viewer.layers[1].selected_data)
|
|
125
|
-
if selected_points:
|
|
126
|
-
selected_properties = viewer.layers[1].properties["cell"][
|
|
127
|
-
selected_points
|
|
128
|
-
]
|
|
129
|
-
toggled_properties = np.logical_not(selected_properties)
|
|
130
|
-
viewer.layers[1].properties["cell"][
|
|
131
|
-
selected_points
|
|
132
|
-
] = toggled_properties
|
|
133
|
-
|
|
134
|
-
# Add curated cells to list
|
|
135
|
-
CURATED_POINTS.extend(selected_points)
|
|
136
|
-
print(
|
|
137
|
-
f"{len(selected_points)} points "
|
|
138
|
-
f"toggled and added to the list "
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
# refresh the properties colour
|
|
142
|
-
viewer.layers[1].refresh_colors(update_color_mapping=False)
|
|
143
|
-
|
|
144
|
-
@viewer.bind_key("c")
|
|
145
|
-
def confirm_point_property(viewer):
|
|
146
|
-
"""Confirm point type"""
|
|
147
|
-
selected_points = list(viewer.layers[1].selected_data)
|
|
148
|
-
if selected_points:
|
|
149
|
-
# Add curated cells to list
|
|
150
|
-
CURATED_POINTS.extend(selected_points)
|
|
151
|
-
print(
|
|
152
|
-
f"{len(selected_points)} points "
|
|
153
|
-
f"confirmed and added to the list "
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
@viewer.bind_key("Alt-Q")
|
|
157
|
-
def save_curation(viewer):
|
|
158
|
-
"""Save file"""
|
|
159
|
-
if not CURATED_POINTS:
|
|
160
|
-
print("No cells have been confirmed or toggled, not saving")
|
|
161
|
-
else:
|
|
162
|
-
unique_cells = unique_elements_lists(CURATED_POINTS)
|
|
163
|
-
points = viewer.layers[1].data[unique_cells]
|
|
164
|
-
labels = viewer.layers[1].properties["cell"][unique_cells]
|
|
165
|
-
labels = labels.astype("int")
|
|
166
|
-
labels = labels + 1
|
|
167
|
-
|
|
168
|
-
cells_to_save = []
|
|
169
|
-
for idx, point in enumerate(points):
|
|
170
|
-
cell = Cell([point[2], point[1], point[0]], labels[idx])
|
|
171
|
-
cells_to_save.append(cell)
|
|
172
|
-
|
|
173
|
-
print(f"Saving results to: {output_filename}")
|
|
174
|
-
save_cells(cells_to_save, output_filename)
|
|
175
|
-
print("Done!")
|
|
176
|
-
|
|
177
|
-
@viewer.bind_key("Alt-E")
|
|
178
|
-
def start_cube_extraction(viewer):
|
|
179
|
-
"""Extract cubes for training"""
|
|
180
|
-
|
|
181
|
-
if not output_filename.exists():
|
|
182
|
-
print(
|
|
183
|
-
"No curation results have been saved. "
|
|
184
|
-
"Please save before extracting cubes"
|
|
185
|
-
)
|
|
186
|
-
else:
|
|
187
|
-
print(f"Saving cubes to: {output_directory}")
|
|
188
|
-
run_extraction(
|
|
189
|
-
output_filename,
|
|
190
|
-
output_directory,
|
|
191
|
-
args.signal_image_paths,
|
|
192
|
-
args.background_image_paths,
|
|
193
|
-
args.cube_depth,
|
|
194
|
-
args.cube_width,
|
|
195
|
-
args.cube_height,
|
|
196
|
-
args.voxel_sizes,
|
|
197
|
-
args.network_voxel_sizes,
|
|
198
|
-
args.max_ram,
|
|
199
|
-
args.n_free_cpus,
|
|
200
|
-
args.save_empty_cubes,
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
print("Saving yaml file to use for training")
|
|
204
|
-
save_yaml_file(output_directory)
|
|
205
|
-
|
|
206
|
-
print("Closing window")
|
|
207
|
-
QApplication.closeAllWindows()
|
|
208
|
-
print(
|
|
209
|
-
"Finished! You may now annotate more "
|
|
210
|
-
"datasets, or go straight to training"
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def run_extraction(
|
|
215
|
-
output_filename,
|
|
216
|
-
output_directory,
|
|
217
|
-
signal_paths,
|
|
218
|
-
background_paths,
|
|
219
|
-
cube_depth,
|
|
220
|
-
cube_width,
|
|
221
|
-
cube_height,
|
|
222
|
-
voxel_sizes,
|
|
223
|
-
network_voxel_sizes,
|
|
224
|
-
max_ram,
|
|
225
|
-
n_free_cpus,
|
|
226
|
-
save_empty_cubes,
|
|
227
|
-
):
|
|
228
|
-
planes_paths = {}
|
|
229
|
-
planes_paths[0] = get_sorted_file_paths(
|
|
230
|
-
signal_paths, file_extension=".tif"
|
|
231
|
-
)
|
|
232
|
-
planes_paths[1] = get_sorted_file_paths(
|
|
233
|
-
background_paths, file_extension=".tif"
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
all_candidates = get_cells(str(output_filename))
|
|
237
|
-
|
|
238
|
-
cells = [c for c in all_candidates if c.is_cell()]
|
|
239
|
-
non_cells = [c for c in all_candidates if not c.is_cell()]
|
|
240
|
-
|
|
241
|
-
to_extract = {"cells": cells, "non_cells": non_cells}
|
|
242
|
-
|
|
243
|
-
for cell_type, cell_list in to_extract.items():
|
|
244
|
-
print(f"Extracting type: {cell_type}")
|
|
245
|
-
cell_type_output_directory = output_directory / cell_type
|
|
246
|
-
print(f"Saving to: {cell_type_output_directory}")
|
|
247
|
-
ensure_directory_exists(str(cell_type_output_directory))
|
|
248
|
-
extract_cubes_main(
|
|
249
|
-
cell_list,
|
|
250
|
-
cell_type_output_directory,
|
|
251
|
-
planes_paths,
|
|
252
|
-
cube_depth,
|
|
253
|
-
cube_width,
|
|
254
|
-
cube_height,
|
|
255
|
-
voxel_sizes,
|
|
256
|
-
network_voxel_sizes,
|
|
257
|
-
max_ram,
|
|
258
|
-
n_free_cpus,
|
|
259
|
-
save_empty_cubes,
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def save_yaml_file(output_directory):
|
|
264
|
-
yaml_filename = output_directory / "training.yml"
|
|
265
|
-
yaml_section = [
|
|
266
|
-
{
|
|
267
|
-
"cube_dir": str(output_directory / "cells"),
|
|
268
|
-
"cell_def": "",
|
|
269
|
-
"type": "cell",
|
|
270
|
-
"signal_channel": 0,
|
|
271
|
-
"bg_channel": 1,
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
"cube_dir": str(output_directory / "non_cells"),
|
|
275
|
-
"cell_def": "",
|
|
276
|
-
"type": "no_cell",
|
|
277
|
-
"signal_channel": 0,
|
|
278
|
-
"bg_channel": 1,
|
|
279
|
-
},
|
|
280
|
-
]
|
|
281
|
-
|
|
282
|
-
yaml_contents = {"data": yaml_section}
|
|
283
|
-
save_yaml(yaml_contents, yaml_filename)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if __name__ == "__main__":
|
|
287
|
-
main()
|
|
File without changes
|
|
File without changes
|