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 CHANGED
@@ -1,3 +1,7 @@
1
- __version__ = "0.7.0"
2
- __author__ = "Adam Tyson, Christian Niedworok, Charly Rousseau"
3
- __license__ = "BSD-3-Clause"
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
@@ -42,7 +42,7 @@ def cells_exist(points_file):
42
42
 
43
43
  def main():
44
44
  suppress_tf_logging(tf_suppress_log_messages)
45
- from brainreg.main import main as register
45
+ from brainreg.core.main import main as register
46
46
 
47
47
  from cellfinder.tools import prep
48
48
 
@@ -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 type(array_size) is tuple:
83
+ if isinstance(array_size, tuple):
84
84
  bins = [int(size / binning) for size in array_size]
85
- elif type(array_size) is dict:
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.7.0
3
+ Version: 0.8.0
4
4
  Summary: Automated 3D cell detection and registration of whole-brain images
5
- Home-page: https://brainglobe.info/cellfinder
6
- Author: Adam Tyson, Christian Niedworok, Charly Rousseau
7
- Author-email: code@adamltyson.com
8
- Project-URL: Source Code, https://github.com/brainglobe/cellfinder
9
- Project-URL: Bug Tracker, https://github.com/brainglobe/cellfinder/issues
10
- Project-URL: Documentation, https://docs.brainglobe.info/cellfinder
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.8
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 (>=0.2.4)
54
+ Requires-Dist: brainreg >=1.0.0
55
+ Requires-Dist: cellfinder-core >=0.2.4
26
56
  Requires-Dist: configobj
27
- Requires-Dist: fancylog (>=0.0.7)
57
+ Requires-Dist: fancylog >=0.0.7
28
58
  Requires-Dist: imio
29
- Requires-Dist: brainglobe-utils (>=0.2.5)
30
- Requires-Dist: multiprocessing-logging (>=0.3.4)
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 (>=5.0.3) ; extra == 'dev'
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: flake8 ; extra == 'dev'
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=Y0Iscj_uSldCL3OCYBpfjPquQ-dH2VAwtb1p4Mixr7s,115
2
- cellfinder/main.py,sha256=tMuq_GWHs8dsEew0RwwwKeDsFby9sZXvv5rSE354E5E,7385
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=1kwryFA7hEBKrsbXkW0iEl03AAGqi4Ss7RkCkv9-l_c,13567
17
- cellfinder/tools/prep.py,sha256=bCEdUCsq_1sew_owuCCtEPn3YlEvTRu9WbePLzqGUk4,11119
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=0HqnTg0S1avKMQtb2SkiG43jvLTa-QhxNlujvztpubI,3627
20
- cellfinder/train/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- cellfinder/train/curation.py,sha256=qVwjqONEOPIMb0m4QDe5nCw86Rzt_LF3-2HFeQGrjbI,10588
22
- cellfinder/train/curation_old.py,sha256=peduW8pDuOlhqSoj91EXcy0bb3z7G1h8IdRvie-JxJ4,9019
23
- cellfinder-0.7.0.dist-info/LICENSE,sha256=zyXpitCrNwvc33VKBFomd9v6Ahi9x1H5fvfXDxCblM0,1525
24
- cellfinder-0.7.0.dist-info/METADATA,sha256=F7E6erjHB8V8-7aTwa7X_gPMvBi3yNg2oVvVt2F6bTU,9900
25
- cellfinder-0.7.0.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.0)
2
+ Generator: bdist_wheel (0.41.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ cellfinder = cellfinder.main:main
File without changes
@@ -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()
@@ -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()
@@ -1,4 +0,0 @@
1
- [console_scripts]
2
- cellfinder = cellfinder.main:main
3
- cellfinder_curate = cellfinder.train.curation_old:main
4
- cellfinder_curate_new = cellfinder.train.curation:main