spacr 0.0.1__py3-none-any.whl → 0.0.6__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.
- spacr/__init__.py +6 -2
- spacr/__main__.py +0 -2
- spacr/alpha.py +807 -0
- spacr/annotate_app.py +118 -120
- spacr/chris.py +50 -0
- spacr/cli.py +25 -187
- spacr/core.py +1611 -389
- spacr/deep_spacr.py +696 -0
- spacr/foldseek.py +779 -0
- spacr/get_alfafold_structures.py +72 -0
- spacr/graph_learning.py +320 -0
- spacr/graph_learning_lap.py +84 -0
- spacr/gui.py +145 -0
- spacr/gui_2.py +90 -0
- spacr/gui_classify_app.py +187 -0
- spacr/gui_mask_app.py +149 -174
- spacr/gui_measure_app.py +116 -109
- spacr/gui_sim_app.py +0 -0
- spacr/gui_utils.py +679 -139
- spacr/io.py +620 -469
- spacr/mask_app.py +116 -9
- spacr/measure.py +178 -84
- spacr/models/cp/toxo_pv_lumen.CP_model +0 -0
- spacr/old_code.py +255 -1
- spacr/plot.py +263 -100
- spacr/sequencing.py +1130 -0
- spacr/sim.py +634 -122
- spacr/timelapse.py +343 -53
- spacr/train.py +195 -22
- spacr/umap.py +0 -689
- spacr/utils.py +1530 -188
- spacr-0.0.6.dist-info/METADATA +118 -0
- spacr-0.0.6.dist-info/RECORD +39 -0
- {spacr-0.0.1.dist-info → spacr-0.0.6.dist-info}/WHEEL +1 -1
- spacr-0.0.6.dist-info/entry_points.txt +9 -0
- spacr-0.0.1.dist-info/METADATA +0 -64
- spacr-0.0.1.dist-info/RECORD +0 -26
- spacr-0.0.1.dist-info/entry_points.txt +0 -5
- {spacr-0.0.1.dist-info → spacr-0.0.6.dist-info}/LICENSE +0 -0
- {spacr-0.0.1.dist-info → spacr-0.0.6.dist-info}/top_level.txt +0 -0
spacr/annotate_app.py
CHANGED
@@ -13,38 +13,17 @@ from ttkthemes import ThemedTk
|
|
13
13
|
|
14
14
|
from .logger import log_function_call
|
15
15
|
|
16
|
-
from .gui_utils import ScrollableFrame, set_default_font, set_dark_style, create_dark_mode
|
16
|
+
from .gui_utils import ScrollableFrame, set_default_font, set_dark_style, create_dark_mode, style_text_boxes, create_menu_bar
|
17
17
|
|
18
18
|
class ImageApp:
|
19
|
-
|
20
|
-
A class representing an image application.
|
21
|
-
|
22
|
-
Attributes:
|
23
|
-
- root (tkinter.Tk): The root window of the application.
|
24
|
-
- db_path (str): The path to the SQLite database.
|
25
|
-
- index (int): The index of the current page of images.
|
26
|
-
- grid_rows (int): The number of rows in the image grid.
|
27
|
-
- grid_cols (int): The number of columns in the image grid.
|
28
|
-
- image_size (tuple): The size of the displayed images.
|
29
|
-
- annotation_column (str): The column name for image annotations in the database.
|
30
|
-
- image_type (str): The type of images to display.
|
31
|
-
- channels (list): The channels to filter in the images.
|
32
|
-
- images (dict): A dictionary mapping labels to loaded images.
|
33
|
-
- pending_updates (dict): A dictionary of pending image annotation updates.
|
34
|
-
- labels (list): A list of label widgets for displaying images.
|
35
|
-
- terminate (bool): A flag indicating whether the application should terminate.
|
36
|
-
- update_queue (Queue): A queue for storing image annotation updates.
|
37
|
-
- status_label (tkinter.Label): A label widget for displaying status messages.
|
38
|
-
- db_update_thread (threading.Thread): A thread for updating the database.
|
39
|
-
"""
|
40
|
-
|
41
|
-
def _init_(self, root, db_path, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate'):
|
19
|
+
def __init__(self, root, db_path, src, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate'):
|
42
20
|
"""
|
43
21
|
Initializes an instance of the ImageApp class.
|
44
22
|
|
45
23
|
Parameters:
|
46
24
|
- root (tkinter.Tk): The root window of the application.
|
47
25
|
- db_path (str): The path to the SQLite database.
|
26
|
+
- src (str): The source directory that should be upstream of 'data' in the paths.
|
48
27
|
- image_type (str): The type of images to display.
|
49
28
|
- channels (list): The channels to filter in the images.
|
50
29
|
- grid_rows (int): The number of rows in the image grid.
|
@@ -52,9 +31,9 @@ class ImageApp:
|
|
52
31
|
- image_size (tuple): The size of the displayed images.
|
53
32
|
- annotation_column (str): The column name for image annotations in the database.
|
54
33
|
"""
|
55
|
-
|
56
34
|
self.root = root
|
57
35
|
self.db_path = db_path
|
36
|
+
self.src = src
|
58
37
|
self.index = 0
|
59
38
|
self.grid_rows = grid_rows
|
60
39
|
self.grid_cols = grid_cols
|
@@ -65,7 +44,7 @@ class ImageApp:
|
|
65
44
|
self.images = {}
|
66
45
|
self.pending_updates = {}
|
67
46
|
self.labels = []
|
68
|
-
|
47
|
+
self.adjusted_to_original_paths = {}
|
69
48
|
self.terminate = False
|
70
49
|
self.update_queue = Queue()
|
71
50
|
self.status_label = Label(self.root, text="", font=("Arial", 12))
|
@@ -78,6 +57,68 @@ class ImageApp:
|
|
78
57
|
label = Label(root)
|
79
58
|
label.grid(row=i // grid_cols, column=i % grid_cols)
|
80
59
|
self.labels.append(label)
|
60
|
+
|
61
|
+
def load_images(self):
|
62
|
+
"""
|
63
|
+
Loads and displays images with annotations.
|
64
|
+
|
65
|
+
This method retrieves image paths and annotations from a SQLite database,
|
66
|
+
loads the images using a ThreadPoolExecutor for parallel processing,
|
67
|
+
adds colored borders to images based on their annotations,
|
68
|
+
and displays the images in the corresponding labels.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
None
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
None
|
75
|
+
"""
|
76
|
+
for label in self.labels:
|
77
|
+
label.config(image='')
|
78
|
+
|
79
|
+
self.images = {}
|
80
|
+
|
81
|
+
conn = sqlite3.connect(self.db_path)
|
82
|
+
c = conn.cursor()
|
83
|
+
if self.image_type:
|
84
|
+
c.execute(f"SELECT png_path, {self.annotation_column} FROM png_list WHERE png_path LIKE ? LIMIT ?, ?", (f"%{self.image_type}%", self.index, self.grid_rows * self.grid_cols))
|
85
|
+
else:
|
86
|
+
c.execute(f"SELECT png_path, {self.annotation_column} FROM png_list LIMIT ?, ?", (self.index, self.grid_rows * self.grid_cols))
|
87
|
+
|
88
|
+
paths = c.fetchall()
|
89
|
+
conn.close()
|
90
|
+
|
91
|
+
adjusted_paths = []
|
92
|
+
for path, annotation in paths:
|
93
|
+
if not path.startswith(self.src):
|
94
|
+
parts = path.split('/data/')
|
95
|
+
if len(parts) > 1:
|
96
|
+
new_path = os.path.join(self.src, 'data', parts[1])
|
97
|
+
self.adjusted_to_original_paths[new_path] = path
|
98
|
+
adjusted_paths.append((new_path, annotation))
|
99
|
+
else:
|
100
|
+
adjusted_paths.append((path, annotation))
|
101
|
+
else:
|
102
|
+
adjusted_paths.append((path, annotation))
|
103
|
+
|
104
|
+
with ThreadPoolExecutor() as executor:
|
105
|
+
loaded_images = list(executor.map(self.load_single_image, adjusted_paths))
|
106
|
+
|
107
|
+
for i, (img, annotation) in enumerate(loaded_images):
|
108
|
+
if annotation:
|
109
|
+
border_color = 'teal' if annotation == 1 else 'red'
|
110
|
+
img = self.add_colored_border(img, border_width=5, border_color=border_color)
|
111
|
+
|
112
|
+
photo = ImageTk.PhotoImage(img)
|
113
|
+
label = self.labels[i]
|
114
|
+
self.images[label] = photo
|
115
|
+
label.config(image=photo)
|
116
|
+
|
117
|
+
path = adjusted_paths[i][0]
|
118
|
+
label.bind('<Button-1>', self.get_on_image_click(path, label, img))
|
119
|
+
label.bind('<Button-3>', self.get_on_image_click(path, label, img))
|
120
|
+
|
121
|
+
self.root.update()
|
81
122
|
|
82
123
|
@staticmethod
|
83
124
|
def normalize_image(img):
|
@@ -148,55 +189,6 @@ class ImageApp:
|
|
148
189
|
|
149
190
|
return Image.merge("RGB", (r, g, b))
|
150
191
|
|
151
|
-
def load_images(self):
|
152
|
-
"""
|
153
|
-
Loads and displays images with annotations.
|
154
|
-
|
155
|
-
This method retrieves image paths and annotations from a SQLite database,
|
156
|
-
loads the images using a ThreadPoolExecutor for parallel processing,
|
157
|
-
adds colored borders to images based on their annotations,
|
158
|
-
and displays the images in the corresponding labels.
|
159
|
-
|
160
|
-
Args:
|
161
|
-
None
|
162
|
-
|
163
|
-
Returns:
|
164
|
-
None
|
165
|
-
"""
|
166
|
-
for label in self.labels:
|
167
|
-
label.config(image='')
|
168
|
-
|
169
|
-
self.images = {}
|
170
|
-
|
171
|
-
conn = sqlite3.connect(self.db_path)
|
172
|
-
c = conn.cursor()
|
173
|
-
if self.image_type:
|
174
|
-
c.execute(f"SELECT png_path, {self.annotation_column} FROM png_list WHERE png_path LIKE ? LIMIT ?, ?", (f"%{self.image_type}%", self.index, self.grid_rows * self.grid_cols))
|
175
|
-
else:
|
176
|
-
c.execute(f"SELECT png_path, {self.annotation_column} FROM png_list LIMIT ?, ?", (self.index, self.grid_rows * self.grid_cols))
|
177
|
-
|
178
|
-
paths = c.fetchall()
|
179
|
-
conn.close()
|
180
|
-
|
181
|
-
with ThreadPoolExecutor() as executor:
|
182
|
-
loaded_images = list(executor.map(self.load_single_image, paths))
|
183
|
-
|
184
|
-
for i, (img, annotation) in enumerate(loaded_images):
|
185
|
-
if annotation:
|
186
|
-
border_color = 'teal' if annotation == 1 else 'red'
|
187
|
-
img = self.add_colored_border(img, border_width=5, border_color=border_color)
|
188
|
-
|
189
|
-
photo = ImageTk.PhotoImage(img)
|
190
|
-
label = self.labels[i]
|
191
|
-
self.images[label] = photo
|
192
|
-
label.config(image=photo)
|
193
|
-
|
194
|
-
path = paths[i][0]
|
195
|
-
label.bind('<Button-1>', self.get_on_image_click(path, label, img))
|
196
|
-
label.bind('<Button-3>', self.get_on_image_click(path, label, img))
|
197
|
-
|
198
|
-
self.root.update()
|
199
|
-
|
200
192
|
def load_single_image(self, path_annotation_tuple):
|
201
193
|
"""
|
202
194
|
Loads a single image from the given path and annotation tuple.
|
@@ -230,14 +222,15 @@ class ImageApp:
|
|
230
222
|
function: The callback function for the image click event.
|
231
223
|
"""
|
232
224
|
def on_image_click(event):
|
233
|
-
|
234
225
|
new_annotation = 1 if event.num == 1 else (2 if event.num == 3 else None)
|
235
226
|
|
236
|
-
|
237
|
-
|
227
|
+
original_path = self.adjusted_to_original_paths.get(path, path)
|
228
|
+
|
229
|
+
if original_path in self.pending_updates and self.pending_updates[original_path] == new_annotation:
|
230
|
+
self.pending_updates[original_path] = None
|
238
231
|
new_annotation = None
|
239
232
|
else:
|
240
|
-
self.pending_updates[
|
233
|
+
self.pending_updates[original_path] = new_annotation
|
241
234
|
|
242
235
|
print(f"Image {os.path.split(path)[1]} annotated: {new_annotation}")
|
243
236
|
|
@@ -261,38 +254,38 @@ class ImageApp:
|
|
261
254
|
"""))
|
262
255
|
|
263
256
|
def update_database_worker(self):
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
257
|
+
"""
|
258
|
+
Worker function that continuously updates the database with pending updates from the update queue.
|
259
|
+
It retrieves the pending updates from the queue, updates the corresponding records in the database,
|
260
|
+
and resets the text in the HTML and status label.
|
261
|
+
"""
|
262
|
+
conn = sqlite3.connect(self.db_path)
|
263
|
+
c = conn.cursor()
|
264
|
+
|
265
|
+
display(HTML("<div id='unique_id'>Initial Text</div>"))
|
266
|
+
|
267
|
+
while True:
|
268
|
+
if self.terminate:
|
269
|
+
conn.close()
|
270
|
+
break
|
271
|
+
|
272
|
+
if not self.update_queue.empty():
|
273
|
+
ImageApp.update_html("Do not exit, Updating database...")
|
274
|
+
self.status_label.config(text='Do not exit, Updating database...')
|
275
|
+
|
276
|
+
pending_updates = self.update_queue.get()
|
277
|
+
for path, new_annotation in pending_updates.items():
|
278
|
+
if new_annotation is None:
|
279
|
+
c.execute(f'UPDATE png_list SET {self.annotation_column} = NULL WHERE png_path = ?', (path,))
|
280
|
+
else:
|
281
|
+
c.execute(f'UPDATE png_list SET {self.annotation_column} = ? WHERE png_path = ?', (new_annotation, path))
|
282
|
+
conn.commit()
|
283
|
+
|
284
|
+
# Reset the text
|
285
|
+
ImageApp.update_html('')
|
286
|
+
self.status_label.config(text='')
|
287
|
+
self.root.update()
|
288
|
+
time.sleep(0.1)
|
296
289
|
|
297
290
|
def update_gui_text(self, text):
|
298
291
|
"""
|
@@ -356,12 +349,13 @@ class ImageApp:
|
|
356
349
|
self.root.destroy()
|
357
350
|
print(f'Quit application')
|
358
351
|
|
359
|
-
def annotate(
|
352
|
+
def annotate(src, image_type=None, channels=None, geom="1000x1100", img_size=(200, 200), rows=5, columns=5, annotation_column='annotate'):
|
360
353
|
"""
|
361
354
|
Annotates images in a database using a graphical user interface.
|
362
355
|
|
363
356
|
Args:
|
364
357
|
db (str): The path to the SQLite database.
|
358
|
+
src (str): The source directory that should be upstream of 'data' in the paths.
|
365
359
|
image_type (str, optional): The type of images to load from the database. Defaults to None.
|
366
360
|
channels (str, optional): The channels of the images to load from the database. Defaults to None.
|
367
361
|
geom (str, optional): The geometry of the GUI window. Defaults to "1000x1100".
|
@@ -370,7 +364,10 @@ def annotate(db, image_type=None, channels=None, geom="1000x1100", img_size=(200
|
|
370
364
|
columns (int, optional): The number of columns in the image grid. Defaults to 5.
|
371
365
|
annotation_column (str, optional): The name of the annotation column in the database table. Defaults to 'annotate'.
|
372
366
|
"""
|
373
|
-
|
367
|
+
db = os.path.join(src, 'measurements/measurements.db')
|
368
|
+
#print('src', src)
|
369
|
+
#print('db', db)
|
370
|
+
|
374
371
|
conn = sqlite3.connect(db)
|
375
372
|
c = conn.cursor()
|
376
373
|
c.execute('PRAGMA table_info(png_list)')
|
@@ -382,8 +379,7 @@ def annotate(db, image_type=None, channels=None, geom="1000x1100", img_size=(200
|
|
382
379
|
|
383
380
|
root = tk.Tk()
|
384
381
|
root.geometry(geom)
|
385
|
-
app = ImageApp(root, db, image_type=image_type, channels=channels, image_size=img_size, grid_rows=rows, grid_cols=columns, annotation_column=annotation_column)
|
386
|
-
|
382
|
+
app = ImageApp(root, db, src, image_type=image_type, channels=channels, image_size=img_size, grid_rows=rows, grid_cols=columns, annotation_column=annotation_column)
|
387
383
|
next_button = tk.Button(root, text="Next", command=app.next_page)
|
388
384
|
next_button.grid(row=app.grid_rows, column=app.grid_cols - 1)
|
389
385
|
back_button = tk.Button(root, text="Back", command=app.previous_page)
|
@@ -394,6 +390,7 @@ def annotate(db, image_type=None, channels=None, geom="1000x1100", img_size=(200
|
|
394
390
|
app.load_images()
|
395
391
|
root.mainloop()
|
396
392
|
|
393
|
+
|
397
394
|
def check_for_duplicates(db):
|
398
395
|
"""
|
399
396
|
Check for duplicates in the given SQLite database.
|
@@ -419,13 +416,14 @@ def check_for_duplicates(db):
|
|
419
416
|
conn.commit()
|
420
417
|
conn.close()
|
421
418
|
|
422
|
-
|
419
|
+
#@log_function_call
|
423
420
|
def initiate_annotation_app_root(width, height):
|
424
421
|
theme = 'breeze'
|
425
422
|
root = ThemedTk(theme=theme)
|
426
423
|
style = ttk.Style(root)
|
427
424
|
set_dark_style(style)
|
428
|
-
|
425
|
+
style_text_boxes(style)
|
426
|
+
set_default_font(root, font_name="Arial", size=8)
|
429
427
|
root.geometry(f"{width}x{height}")
|
430
428
|
root.title("Annotation App")
|
431
429
|
|
@@ -473,6 +471,7 @@ def initiate_annotation_app_root(width, height):
|
|
473
471
|
new_root = tk.Tk()
|
474
472
|
new_root.geometry(f"{width}x{height}")
|
475
473
|
new_root.title("Mask Application")
|
474
|
+
|
476
475
|
|
477
476
|
# Start the annotation application in the new root window
|
478
477
|
app_instance = annotate(db, image_type, channels, annotation_column, geom, img_size, rows, columns)
|
@@ -482,7 +481,7 @@ def initiate_annotation_app_root(width, height):
|
|
482
481
|
create_dark_mode(root, style, console_output=None)
|
483
482
|
|
484
483
|
run_button = ttk.Button(scrollable_frame.scrollable_frame, text="Run", command=run_app)
|
485
|
-
run_button.grid(row=row, column=0, columnspan=2, pady=10)
|
484
|
+
run_button.grid(row=row, column=0, columnspan=2, pady=10, padx=10)
|
486
485
|
|
487
486
|
return root
|
488
487
|
|
@@ -491,5 +490,4 @@ def gui_annotation():
|
|
491
490
|
root.mainloop()
|
492
491
|
|
493
492
|
if __name__ == "__main__":
|
494
|
-
gui_annotation()
|
495
|
-
|
493
|
+
gui_annotation()
|
spacr/chris.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
import numpy as np
|
3
|
+
from .core import _permutation_importance, _shap_analysis
|
4
|
+
|
5
|
+
def join_measurments_and_annotation(src, tables = ['cell', 'nucleus', 'pathogen','cytoplasm']):
|
6
|
+
|
7
|
+
from .io import _read_and_merge_data, _read_db
|
8
|
+
|
9
|
+
db_loc = [src+'/measurements/measurements.db']
|
10
|
+
loc = src+'/measurements/measurements.db'
|
11
|
+
df, _ = _read_and_merge_data(db_loc,
|
12
|
+
tables,
|
13
|
+
verbose=True,
|
14
|
+
include_multinucleated=True,
|
15
|
+
include_multiinfected=True,
|
16
|
+
include_noninfected=True)
|
17
|
+
|
18
|
+
paths_df = _read_db(loc, tables=['png_list'])
|
19
|
+
|
20
|
+
merged_df = pd.merge(df, paths_df[0], on='prcfo', how='left')
|
21
|
+
|
22
|
+
return merged_df
|
23
|
+
|
24
|
+
def plate_heatmap(src, model_type='xgboost', variable='predictions', grouping='mean', min_max='allq', cmap='viridis', channel_of_interest=3, min_count=25, n_estimators=100, col_to_compare='col', pos='c1', neg='c2', exclude=None, n_repeats=10, clean=True, nr_to_plot=20, verbose=False, n_jobs=-1):
|
25
|
+
from .io import _read_and_merge_data
|
26
|
+
from .plot import _plot_plates
|
27
|
+
|
28
|
+
db_loc = [src+'/measurements/measurements.db']
|
29
|
+
tables = ['cell', 'nucleus', 'pathogen','cytoplasm']
|
30
|
+
include_multinucleated, include_multiinfected, include_noninfected = True, 2.0, True
|
31
|
+
|
32
|
+
df = join_measurments_and_annotation(src, tables=['cell', 'nucleus', 'pathogen', 'cytoplasm'])
|
33
|
+
|
34
|
+
if not channel_of_interest is None:
|
35
|
+
df['recruitment'] = df[f'pathogen_channel_{channel_of_interest}_mean_intensity']/df[f'cytoplasm_channel_{channel_of_interest}_mean_intensity']
|
36
|
+
feature_string = f'channel_{channel_of_interest}'
|
37
|
+
else:
|
38
|
+
feature_string = None
|
39
|
+
|
40
|
+
output = _permutation_importance(df, feature_string, col_to_compare, pos, neg, exclude, n_repeats, clean, nr_to_plot, n_estimators=n_estimators, random_state=42, model_type=model_type, n_jobs=n_jobs)
|
41
|
+
|
42
|
+
_shap_analysis(output[3], output[4], output[5])
|
43
|
+
|
44
|
+
features = output[0].select_dtypes(include=[np.number]).columns.tolist()
|
45
|
+
|
46
|
+
if not variable in features:
|
47
|
+
raise ValueError(f"Variable {variable} not found in the dataframe. Please choose one of the following: {features}")
|
48
|
+
|
49
|
+
plate_heatmap = _plot_plates(output[0], variable, grouping, min_max, cmap, min_count)
|
50
|
+
return [output, plate_heatmap]
|
spacr/cli.py
CHANGED
@@ -4,200 +4,38 @@ Copyright © 2023 Howard Hughes Medical Institute, Authored by Carsen Stringer a
|
|
4
4
|
|
5
5
|
import argparse
|
6
6
|
|
7
|
+
import argparse
|
8
|
+
|
7
9
|
|
8
10
|
def get_arg_parser():
|
9
|
-
""" Parses command line arguments for
|
11
|
+
""" Parses command line arguments for spacr main functions
|
10
12
|
|
11
13
|
Note: this function has to be in a separate file to allow autodoc to work for CLI.
|
12
14
|
The autodoc_mock_imports in conf.py does not work for sphinx-argparse sometimes,
|
13
15
|
see https://github.com/ashb/sphinx-argparse/issues/9#issue-1097057823
|
14
16
|
"""
|
15
|
-
|
16
|
-
parser = argparse.ArgumentParser(description="
|
17
|
-
|
18
|
-
# misc settings
|
19
|
-
parser.add_argument("--version", action="store_true",
|
20
|
-
help="show cellpose version info")
|
21
|
-
parser.add_argument(
|
22
|
-
"--verbose", action="store_true",
|
23
|
-
help="show information about running and settings and save to log")
|
24
|
-
parser.add_argument("--Zstack", action="store_true", help="run GUI in 3D mode")
|
25
|
-
|
26
|
-
# settings for CPU vs GPU
|
17
|
+
|
18
|
+
parser = argparse.ArgumentParser(description="SPACR Mask App Command Line Parameters")
|
27
19
|
hardware_args = parser.add_argument_group("Hardware Arguments")
|
28
|
-
hardware_args.add_argument("--use_gpu", action="store_true",
|
29
|
-
help="use gpu if torch with cuda installed")
|
30
|
-
hardware_args.add_argument(
|
31
|
-
"--gpu_device", required=False, default="0", type=str,
|
32
|
-
help="which gpu device to use, use an integer for torch, or mps for M1")
|
33
|
-
hardware_args.add_argument("--check_mkl", action="store_true",
|
34
|
-
help="check if mkl working")
|
35
|
-
|
36
|
-
# settings for locating and formatting images
|
37
20
|
input_img_args = parser.add_argument_group("Input Image Arguments")
|
38
|
-
|
21
|
+
#model_args = parser.add_argument_group("Model Arguments")
|
22
|
+
#algorithm_args = parser.add_argument_group("Algorithm Arguments")
|
23
|
+
#training_args = parser.add_argument_group("Training Arguments")
|
24
|
+
#output_args = parser.add_argument_group("Output Arguments")
|
25
|
+
|
26
|
+
# misc settings
|
27
|
+
parser.add_argument("--version", action="store_true",
|
28
|
+
help="show version info")
|
29
|
+
# misc settings
|
30
|
+
parser.add_argument("--headless", action="store_true",
|
31
|
+
help="run the app without the gui")
|
32
|
+
|
33
|
+
parser.add_argument("--verbose", action="store_true",
|
34
|
+
help="show information about running and settings and save to log")
|
35
|
+
|
36
|
+
hardware_args.add_argument("--gpu_device", required=False, default="0", type=str,
|
37
|
+
help="which gpu device to use, use an integer for torch, or mps for M1")
|
38
|
+
|
39
|
+
input_img_args.add_argument("--src", default=[], type=str,
|
39
40
|
help="folder containing data to run or train on.")
|
40
|
-
|
41
|
-
"--image_path", default=[], type=str, help=
|
42
|
-
"if given and --dir not given, run on single image instead of folder (cannot train with this option)"
|
43
|
-
)
|
44
|
-
input_img_args.add_argument(
|
45
|
-
"--look_one_level_down", action="store_true",
|
46
|
-
help="run processing on all subdirectories of current folder")
|
47
|
-
input_img_args.add_argument("--img_filter", default=[], type=str,
|
48
|
-
help="end string for images to run on")
|
49
|
-
input_img_args.add_argument(
|
50
|
-
"--channel_axis", default=None, type=int,
|
51
|
-
help="axis of image which corresponds to image channels")
|
52
|
-
input_img_args.add_argument("--z_axis", default=None, type=int,
|
53
|
-
help="axis of image which corresponds to Z dimension")
|
54
|
-
input_img_args.add_argument(
|
55
|
-
"--chan", default=0, type=int, help=
|
56
|
-
"channel to segment; 0: GRAY, 1: RED, 2: GREEN, 3: BLUE. Default: %(default)s")
|
57
|
-
input_img_args.add_argument(
|
58
|
-
"--chan2", default=0, type=int, help=
|
59
|
-
"nuclear channel (if cyto, optional); 0: NONE, 1: RED, 2: GREEN, 3: BLUE. Default: %(default)s"
|
60
|
-
)
|
61
|
-
input_img_args.add_argument("--invert", action="store_true",
|
62
|
-
help="invert grayscale channel")
|
63
|
-
input_img_args.add_argument(
|
64
|
-
"--all_channels", action="store_true", help=
|
65
|
-
"use all channels in image if using own model and images with special channels")
|
66
|
-
|
67
|
-
# model settings
|
68
|
-
model_args = parser.add_argument_group("Model Arguments")
|
69
|
-
model_args.add_argument("--pretrained_model", required=False, default="cyto",
|
70
|
-
type=str,
|
71
|
-
help="model to use for running or starting training")
|
72
|
-
model_args.add_argument("--restore_type", required=False, default=None,
|
73
|
-
type=str,
|
74
|
-
help="model to use for image restoration")
|
75
|
-
model_args.add_argument("--chan2_restore", action="store_true",
|
76
|
-
help="use nuclei restore model for second channel")
|
77
|
-
model_args.add_argument(
|
78
|
-
"--add_model", required=False, default=None, type=str,
|
79
|
-
help="model path to copy model to hidden .cellpose folder for using in GUI/CLI")
|
80
|
-
|
81
|
-
# algorithm settings
|
82
|
-
algorithm_args = parser.add_argument_group("Algorithm Arguments")
|
83
|
-
algorithm_args.add_argument(
|
84
|
-
"--no_resample", action="store_true", help=
|
85
|
-
"disable dynamics on full image (makes algorithm faster for images with large diameters)"
|
86
|
-
)
|
87
|
-
algorithm_args.add_argument(
|
88
|
-
"--no_interp", action="store_true",
|
89
|
-
help="do not interpolate when running dynamics (was default)")
|
90
|
-
algorithm_args.add_argument("--no_norm", action="store_true",
|
91
|
-
help="do not normalize images (normalize=False)")
|
92
|
-
algorithm_args.add_argument(
|
93
|
-
"--do_3D", action="store_true",
|
94
|
-
help="process images as 3D stacks of images (nplanes x nchan x Ly x Lx")
|
95
|
-
algorithm_args.add_argument(
|
96
|
-
"--diameter", required=False, default=30., type=float, help=
|
97
|
-
"cell diameter, if 0 will use the diameter of the training labels used in the model, or with built-in model will estimate diameter for each image"
|
98
|
-
)
|
99
|
-
algorithm_args.add_argument(
|
100
|
-
"--stitch_threshold", required=False, default=0.0, type=float,
|
101
|
-
help="compute masks in 2D then stitch together masks with IoU>0.9 across planes"
|
102
|
-
)
|
103
|
-
algorithm_args.add_argument(
|
104
|
-
"--min_size", required=False, default=15, type=int,
|
105
|
-
help="minimum number of pixels per mask, can turn off with -1")
|
106
|
-
|
107
|
-
algorithm_args.add_argument(
|
108
|
-
"--flow_threshold", default=0.4, type=float, help=
|
109
|
-
"flow error threshold, 0 turns off this optional QC step. Default: %(default)s")
|
110
|
-
algorithm_args.add_argument(
|
111
|
-
"--cellprob_threshold", default=0, type=float,
|
112
|
-
help="cellprob threshold, default is 0, decrease to find more and larger masks")
|
113
|
-
algorithm_args.add_argument(
|
114
|
-
"--niter", default=0, type=int,
|
115
|
-
help="niter, number of iterations for dynamics for mask creation, default of 0 means it is proportional to diameter, set to a larger number like 2000 for very long ROIs")
|
116
|
-
|
117
|
-
algorithm_args.add_argument("--anisotropy", required=False, default=1.0, type=float,
|
118
|
-
help="anisotropy of volume in 3D")
|
119
|
-
algorithm_args.add_argument("--exclude_on_edges", action="store_true",
|
120
|
-
help="discard masks which touch edges of image")
|
121
|
-
algorithm_args.add_argument(
|
122
|
-
"--augment", action="store_true",
|
123
|
-
help="tiles image with overlapping tiles and flips overlapped regions to augment"
|
124
|
-
)
|
125
|
-
|
126
|
-
# output settings
|
127
|
-
output_args = parser.add_argument_group("Output Arguments")
|
128
|
-
output_args.add_argument(
|
129
|
-
"--save_png", action="store_true",
|
130
|
-
help="save masks as png and outlines as text file for ImageJ")
|
131
|
-
output_args.add_argument(
|
132
|
-
"--save_tif", action="store_true",
|
133
|
-
help="save masks as tif and outlines as text file for ImageJ")
|
134
|
-
output_args.add_argument("--no_npy", action="store_true",
|
135
|
-
help="suppress saving of npy")
|
136
|
-
output_args.add_argument(
|
137
|
-
"--savedir", default=None, type=str, help=
|
138
|
-
"folder to which segmentation results will be saved (defaults to input image directory)"
|
139
|
-
)
|
140
|
-
output_args.add_argument(
|
141
|
-
"--dir_above", action="store_true", help=
|
142
|
-
"save output folders adjacent to image folder instead of inside it (off by default)"
|
143
|
-
)
|
144
|
-
output_args.add_argument("--in_folders", action="store_true",
|
145
|
-
help="flag to save output in folders (off by default)")
|
146
|
-
output_args.add_argument(
|
147
|
-
"--save_flows", action="store_true", help=
|
148
|
-
"whether or not to save RGB images of flows when masks are saved (disabled by default)"
|
149
|
-
)
|
150
|
-
output_args.add_argument(
|
151
|
-
"--save_outlines", action="store_true", help=
|
152
|
-
"whether or not to save RGB outline images when masks are saved (disabled by default)"
|
153
|
-
)
|
154
|
-
output_args.add_argument(
|
155
|
-
"--save_rois", action="store_true",
|
156
|
-
help="whether or not to save ImageJ compatible ROI archive (disabled by default)"
|
157
|
-
)
|
158
|
-
output_args.add_argument(
|
159
|
-
"--save_txt", action="store_true",
|
160
|
-
help="flag to enable txt outlines for ImageJ (disabled by default)")
|
161
|
-
output_args.add_argument(
|
162
|
-
"--save_mpl", action="store_true",
|
163
|
-
help="save a figure of image/mask/flows using matplotlib (disabled by default). "
|
164
|
-
"This is slow, especially with large images.")
|
165
|
-
|
166
|
-
# training settings
|
167
|
-
training_args = parser.add_argument_group("Training Arguments")
|
168
|
-
training_args.add_argument("--train", action="store_true",
|
169
|
-
help="train network using images in dir")
|
170
|
-
training_args.add_argument("--train_size", action="store_true",
|
171
|
-
help="train size network at end of training")
|
172
|
-
training_args.add_argument("--test_dir", default=[], type=str,
|
173
|
-
help="folder containing test data (optional)")
|
174
|
-
training_args.add_argument(
|
175
|
-
"--mask_filter", default="_masks", type=str, help=
|
176
|
-
"end string for masks to run on. use '_seg.npy' for manual annotations from the GUI. Default: %(default)s"
|
177
|
-
)
|
178
|
-
training_args.add_argument(
|
179
|
-
"--diam_mean", default=30., type=float, help=
|
180
|
-
"mean diameter to resize cells to during training -- if starting from pretrained models it cannot be changed from 30.0"
|
181
|
-
)
|
182
|
-
training_args.add_argument("--learning_rate", default=0.2, type=float,
|
183
|
-
help="learning rate. Default: %(default)s")
|
184
|
-
training_args.add_argument("--weight_decay", default=0.00001, type=float,
|
185
|
-
help="weight decay. Default: %(default)s")
|
186
|
-
training_args.add_argument("--n_epochs", default=500, type=int,
|
187
|
-
help="number of epochs. Default: %(default)s")
|
188
|
-
training_args.add_argument("--batch_size", default=8, type=int,
|
189
|
-
help="batch size. Default: %(default)s")
|
190
|
-
training_args.add_argument(
|
191
|
-
"--min_train_masks", default=5, type=int, help=
|
192
|
-
"minimum number of masks a training image must have to be used. Default: %(default)s"
|
193
|
-
)
|
194
|
-
training_args.add_argument("--SGD", default=1, type=int, help="use SGD")
|
195
|
-
training_args.add_argument(
|
196
|
-
"--save_every", default=100, type=int,
|
197
|
-
help="number of epochs to skip between saves. Default: %(default)s")
|
198
|
-
training_args.add_argument(
|
199
|
-
"--model_name_out", default=None, type=str,
|
200
|
-
help="Name of model to save as, defaults to name describing model architecture. "
|
201
|
-
"Model is saved in the folder specified by --dir in models subfolder.")
|
202
|
-
|
203
|
-
return parser
|
41
|
+
return parser
|