spacr 0.2.3__py3-none-any.whl → 0.2.5__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/app_annotate.py +3 -4
- spacr/core.py +100 -282
- spacr/gui.py +20 -38
- spacr/gui_core.py +406 -499
- spacr/gui_elements.py +395 -60
- spacr/gui_utils.py +393 -73
- spacr/io.py +130 -50
- spacr/measure.py +199 -154
- spacr/plot.py +108 -42
- spacr/resources/font/open_sans/OFL.txt +93 -0
- spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- spacr/resources/font/open_sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- spacr/resources/font/open_sans/README.txt +100 -0
- spacr/resources/font/open_sans/static/OpenSans-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-SemiBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
- spacr/resources/icons/logo.pdf +2786 -6
- spacr/resources/icons/logo_spacr.png +0 -0
- spacr/resources/icons/logo_spacr_1.png +0 -0
- spacr/settings.py +12 -87
- spacr/utils.py +45 -10
- {spacr-0.2.3.dist-info → spacr-0.2.5.dist-info}/METADATA +5 -1
- spacr-0.2.5.dist-info/RECORD +100 -0
- spacr-0.2.3.dist-info/RECORD +0 -58
- {spacr-0.2.3.dist-info → spacr-0.2.5.dist-info}/LICENSE +0 -0
- {spacr-0.2.3.dist-info → spacr-0.2.5.dist-info}/WHEEL +0 -0
- {spacr-0.2.3.dist-info → spacr-0.2.5.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.3.dist-info → spacr-0.2.5.dist-info}/top_level.txt +0 -0
spacr/app_annotate.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import tkinter as tk
|
2
2
|
from tkinter import ttk
|
3
3
|
from .gui import MainApp
|
4
|
-
from .gui_elements import set_dark_style
|
4
|
+
from .gui_elements import set_dark_style, spacrButton
|
5
5
|
|
6
6
|
def initiate_annotation_app(parent_frame):
|
7
7
|
from .gui_utils import generate_annotate_fields, annotate_app
|
@@ -20,8 +20,6 @@ def initiate_annotation_app(parent_frame):
|
|
20
20
|
settings['img_size'] = list(map(int, settings['img_size'].split(','))) # Convert string to list of integers
|
21
21
|
settings['percentiles'] = list(map(int, settings['percentiles'].split(','))) # Convert string to list of integers
|
22
22
|
settings['normalize'] = settings['normalize'].lower() == 'true'
|
23
|
-
settings['rows'] = int(settings['rows'])
|
24
|
-
settings['columns'] = int(settings['columns'])
|
25
23
|
|
26
24
|
try:
|
27
25
|
settings['measurement'] = settings['measurement'].split(',') if settings['measurement'] else None
|
@@ -40,9 +38,10 @@ def initiate_annotation_app(parent_frame):
|
|
40
38
|
settings[key] = None
|
41
39
|
|
42
40
|
settings_window.destroy()
|
41
|
+
|
43
42
|
annotate_app(parent_frame, settings)
|
44
43
|
|
45
|
-
start_button =
|
44
|
+
start_button = spacrButton(settings_window, text="annotate", command=start_annotation_app, show_text=False)
|
46
45
|
start_button.pack(pady=10)
|
47
46
|
|
48
47
|
def start_annotate_app():
|
spacr/core.py
CHANGED
@@ -39,6 +39,10 @@ matplotlib.use('Agg')
|
|
39
39
|
|
40
40
|
from .logger import log_function_call
|
41
41
|
|
42
|
+
import warnings
|
43
|
+
warnings.filterwarnings("ignore", message="3D stack used, but stitch_threshold=0 and do_3D=False, so masks are made per plane only")
|
44
|
+
|
45
|
+
|
42
46
|
def analyze_plaques(folder):
|
43
47
|
summary_data = []
|
44
48
|
details_data = []
|
@@ -80,7 +84,6 @@ def analyze_plaques(folder):
|
|
80
84
|
|
81
85
|
print(f"Analysis completed and saved to database '{db_name}'.")
|
82
86
|
|
83
|
-
|
84
87
|
def train_cellpose(settings):
|
85
88
|
|
86
89
|
from .io import _load_normalized_images_and_labels, _load_images_and_labels
|
@@ -974,7 +977,7 @@ def generate_dataset(src, file_metadata=None, experiment='TSG101_screen', sample
|
|
974
977
|
def apply_model_to_tar(tar_path, model_path, file_type='cell_png', image_size=224, batch_size=64, normalize=True, preload='images', n_jobs=10, threshold=0.5, verbose=False):
|
975
978
|
|
976
979
|
from .io import TarImageDataset
|
977
|
-
from .utils import process_vision_results
|
980
|
+
from .utils import process_vision_results, print_progress
|
978
981
|
|
979
982
|
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
980
983
|
if normalize:
|
@@ -1015,15 +1018,22 @@ def apply_model_to_tar(tar_path, model_path, file_type='cell_png', image_size=22
|
|
1015
1018
|
|
1016
1019
|
prediction_pos_probs = []
|
1017
1020
|
filenames_list = []
|
1021
|
+
time_ls = []
|
1018
1022
|
gc.collect()
|
1019
1023
|
with torch.no_grad():
|
1020
1024
|
for batch_idx, (batch_images, filenames) in enumerate(data_loader, start=1):
|
1025
|
+
start = time.time()
|
1021
1026
|
images = batch_images.to(torch.float).to(device)
|
1022
1027
|
outputs = model(images)
|
1023
1028
|
batch_prediction_pos_prob = torch.sigmoid(outputs).cpu().numpy()
|
1024
1029
|
prediction_pos_probs.extend(batch_prediction_pos_prob.tolist())
|
1025
1030
|
filenames_list.extend(filenames)
|
1026
|
-
|
1031
|
+
stop = time.time()
|
1032
|
+
duration = stop - start
|
1033
|
+
time_ls.append(duration)
|
1034
|
+
files_processed = batch_idx*batch_size
|
1035
|
+
files_to_process = len(data_loader)
|
1036
|
+
print_progress(files_processed, files_to_process, n_jobs=n_jobs, time_ls=time_ls, batch_size=batch_size, operation_type="Tar dataset")
|
1027
1037
|
|
1028
1038
|
data = {'path':filenames_list, 'pred':prediction_pos_probs}
|
1029
1039
|
df = pd.DataFrame(data, index=None)
|
@@ -1037,6 +1047,7 @@ def apply_model_to_tar(tar_path, model_path, file_type='cell_png', image_size=22
|
|
1037
1047
|
def apply_model(src, model_path, image_size=224, batch_size=64, normalize=True, n_jobs=10):
|
1038
1048
|
|
1039
1049
|
from .io import NoClassDataset
|
1050
|
+
from .utils import print_progress
|
1040
1051
|
|
1041
1052
|
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
1042
1053
|
|
@@ -1065,14 +1076,22 @@ def apply_model(src, model_path, image_size=224, batch_size=64, normalize=True,
|
|
1065
1076
|
model = model.to(device)
|
1066
1077
|
prediction_pos_probs = []
|
1067
1078
|
filenames_list = []
|
1079
|
+
time_ls = []
|
1068
1080
|
with torch.no_grad():
|
1069
1081
|
for batch_idx, (batch_images, filenames) in enumerate(data_loader, start=1):
|
1082
|
+
start = time.time()
|
1070
1083
|
images = batch_images.to(torch.float).to(device)
|
1071
1084
|
outputs = model(images)
|
1072
1085
|
batch_prediction_pos_prob = torch.sigmoid(outputs).cpu().numpy()
|
1073
1086
|
prediction_pos_probs.extend(batch_prediction_pos_prob.tolist())
|
1074
1087
|
filenames_list.extend(filenames)
|
1075
|
-
|
1088
|
+
stop = time.time()
|
1089
|
+
duration = stop - start
|
1090
|
+
time_ls.append(duration)
|
1091
|
+
files_processed = batch_idx*batch_size
|
1092
|
+
files_to_process = len(data_loader)
|
1093
|
+
print_progress(files_processed, files_to_process, n_jobs=n_jobs, time_ls=time_ls, batch_size=batch_size, operation_type="Generating predictions")
|
1094
|
+
|
1076
1095
|
data = {'path':filenames_list, 'pred':prediction_pos_probs}
|
1077
1096
|
df = pd.DataFrame(data, index=None)
|
1078
1097
|
df.to_csv(result_loc, index=True, header=True, mode='w')
|
@@ -1164,12 +1183,14 @@ def training_dataset_from_annotation(db_path, dst, annotation_column='test', ann
|
|
1164
1183
|
return class_paths
|
1165
1184
|
|
1166
1185
|
def generate_dataset_from_lists(dst, class_data, classes, test_split=0.1):
|
1186
|
+
from .utils import print_progress
|
1167
1187
|
# Make sure that the length of class_data matches the length of classes
|
1168
1188
|
if len(class_data) != len(classes):
|
1169
1189
|
raise ValueError("class_data and classes must have the same length.")
|
1170
1190
|
|
1171
1191
|
total_files = sum(len(data) for data in class_data)
|
1172
1192
|
processed_files = 0
|
1193
|
+
time_ls = []
|
1173
1194
|
|
1174
1195
|
for cls, data in zip(classes, class_data):
|
1175
1196
|
# Create directories
|
@@ -1183,15 +1204,21 @@ def generate_dataset_from_lists(dst, class_data, classes, test_split=0.1):
|
|
1183
1204
|
|
1184
1205
|
# Copy train files
|
1185
1206
|
for path in train_data:
|
1207
|
+
start = time.time()
|
1186
1208
|
shutil.copy(path, os.path.join(train_class_dir, os.path.basename(path)))
|
1187
1209
|
processed_files += 1
|
1188
|
-
|
1210
|
+
duration = time.time() - start
|
1211
|
+
time_ls.append(duration)
|
1212
|
+
print_progress(processed_files, total_files, n_jobs=1, time_ls=None, batch_size=None, operation_type="Copying files for Train dataset")
|
1189
1213
|
|
1190
1214
|
# Copy test files
|
1191
1215
|
for path in test_data:
|
1216
|
+
start = time.time()
|
1192
1217
|
shutil.copy(path, os.path.join(test_class_dir, os.path.basename(path)))
|
1193
1218
|
processed_files += 1
|
1194
|
-
|
1219
|
+
duration = time.time() - start
|
1220
|
+
time_ls.append(duration)
|
1221
|
+
print_progress(processed_files, total_files, n_jobs=1, time_ls=None, batch_size=None, operation_type="Copying files for Test dataset")
|
1195
1222
|
|
1196
1223
|
# Print summary
|
1197
1224
|
for cls in classes:
|
@@ -1667,9 +1694,9 @@ def analyze_recruitment(src, metadata_settings={}, advanced_settings={}):
|
|
1667
1694
|
def preprocess_generate_masks(src, settings={}):
|
1668
1695
|
|
1669
1696
|
from .io import preprocess_img_data, _load_and_concatenate_arrays
|
1670
|
-
from .plot import
|
1671
|
-
from .utils import _pivot_counts_table, check_mask_folder, adjust_cell_masks
|
1672
|
-
from .settings import set_default_settings_preprocess_generate_masks
|
1697
|
+
from .plot import plot_image_mask_overlay, plot_arrays
|
1698
|
+
from .utils import _pivot_counts_table, check_mask_folder, adjust_cell_masks, print_progress
|
1699
|
+
from .settings import set_default_settings_preprocess_generate_masks
|
1673
1700
|
|
1674
1701
|
settings = set_default_settings_preprocess_generate_masks(src, settings)
|
1675
1702
|
settings_df = pd.DataFrame(list(settings.items()), columns=['Key', 'Value'])
|
@@ -1702,20 +1729,43 @@ def preprocess_generate_masks(src, settings={}):
|
|
1702
1729
|
|
1703
1730
|
if settings['preprocess']:
|
1704
1731
|
settings, src = preprocess_img_data(settings)
|
1705
|
-
|
1732
|
+
|
1733
|
+
files_to_process = 3
|
1706
1734
|
if settings['masks']:
|
1707
1735
|
mask_src = os.path.join(src, 'norm_channel_stack')
|
1708
1736
|
if settings['cell_channel'] != None:
|
1737
|
+
start = time.time()
|
1709
1738
|
if check_mask_folder(src, 'cell_mask_stack'):
|
1710
1739
|
generate_cellpose_masks(mask_src, settings, 'cell')
|
1740
|
+
stop = time.time()
|
1741
|
+
duration = (stop - start)
|
1742
|
+
time_ls.append(duration)
|
1743
|
+
files_processed += 1
|
1744
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type=f'cell_mask_gen')
|
1711
1745
|
|
1712
1746
|
if settings['nucleus_channel'] != None:
|
1747
|
+
start = time.time()
|
1713
1748
|
if check_mask_folder(src, 'nucleus_mask_stack'):
|
1714
1749
|
generate_cellpose_masks(mask_src, settings, 'nucleus')
|
1750
|
+
stop = time.time()
|
1751
|
+
duration = (stop - start)
|
1752
|
+
time_ls.append(duration)
|
1753
|
+
files_processed += 1
|
1754
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type=f'nucleus_mask_gen')
|
1715
1755
|
|
1716
1756
|
if settings['pathogen_channel'] != None:
|
1757
|
+
start = time.time()
|
1717
1758
|
if check_mask_folder(src, 'pathogen_mask_stack'):
|
1759
|
+
stop = time.time()
|
1760
|
+
duration = (stop - start)
|
1761
|
+
time_ls.append(duration)
|
1762
|
+
files_processed += 1
|
1718
1763
|
generate_cellpose_masks(mask_src, settings, 'pathogen')
|
1764
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type=f'pathogen_mask_gen')
|
1765
|
+
|
1766
|
+
#if settings['organelle'] != None:
|
1767
|
+
# if check_mask_folder(src, 'organelle_mask_stack'):
|
1768
|
+
# generate_cellpose_masks(mask_src, settings, 'organelle')
|
1719
1769
|
|
1720
1770
|
if settings['adjust_cells']:
|
1721
1771
|
if settings['pathogen_channel'] != None and settings['cell_channel'] != None and settings['nucleus_channel'] != None:
|
@@ -1724,12 +1774,8 @@ def preprocess_generate_masks(src, settings={}):
|
|
1724
1774
|
cell_folder = os.path.join(mask_src, 'cell_mask_stack')
|
1725
1775
|
nuclei_folder = os.path.join(mask_src, 'nucleus_mask_stack')
|
1726
1776
|
parasite_folder = os.path.join(mask_src, 'pathogen_mask_stack')
|
1727
|
-
#
|
1777
|
+
#organelle_folder = os.path.join(mask_src, 'organelle_mask_stack')
|
1728
1778
|
|
1729
|
-
#process_masks(cell_folder, image_folder, settings['cell_channel'], settings['batch_size'], n_clusters=2, plot=settings['plot'])
|
1730
|
-
#process_masks(nuclei_folder, image_folder, settings['nucleus_channel'], settings['batch_size'], n_clusters=2, plot=settings['plot'])
|
1731
|
-
#process_masks(parasite_folder, image_folder, settings['pathogen_channel'], settings['batch_size'], n_clusters=2, plot=settings['plot'])
|
1732
|
-
|
1733
1779
|
adjust_cell_masks(parasite_folder, cell_folder, nuclei_folder, overlap_threshold=5, perimeter_threshold=30)
|
1734
1780
|
stop = time.time()
|
1735
1781
|
adjust_time = (stop-start)/60
|
@@ -1743,38 +1789,28 @@ def preprocess_generate_masks(src, settings={}):
|
|
1743
1789
|
|
1744
1790
|
if settings['plot']:
|
1745
1791
|
if not settings['timelapse']:
|
1746
|
-
plot_dims = len(settings['channels'])
|
1747
|
-
overlay_channels = [2,1,0]
|
1748
|
-
cell_mask_dim = nucleus_mask_dim = pathogen_mask_dim = None
|
1749
|
-
plot_counter = plot_dims
|
1750
|
-
|
1751
|
-
if settings['cell_channel'] is not None:
|
1752
|
-
cell_mask_dim = plot_counter
|
1753
|
-
plot_counter += 1
|
1754
|
-
|
1755
|
-
if settings['nucleus_channel'] is not None:
|
1756
|
-
nucleus_mask_dim = plot_counter
|
1757
|
-
plot_counter += 1
|
1758
|
-
|
1759
|
-
if settings['pathogen_channel'] is not None:
|
1760
|
-
pathogen_mask_dim = plot_counter
|
1761
|
-
|
1762
|
-
overlay_channels = [settings['nucleus_channel'], settings['pathogen_channel'], settings['cell_channel']]
|
1763
|
-
overlay_channels = [element for element in overlay_channels if element is not None]
|
1764
|
-
|
1765
|
-
plot_settings = set_default_plot_merge_settings()
|
1766
|
-
plot_settings['channel_dims'] = settings['channels']
|
1767
|
-
plot_settings['cell_mask_dim'] = cell_mask_dim
|
1768
|
-
plot_settings['nucleus_mask_dim'] = nucleus_mask_dim
|
1769
|
-
plot_settings['pathogen_mask_dim'] = pathogen_mask_dim
|
1770
|
-
plot_settings['overlay_chans'] = overlay_channels
|
1771
|
-
plot_settings['nr'] = settings['examples_to_plot']
|
1772
1792
|
|
1773
1793
|
if settings['test_mode'] == True:
|
1774
|
-
|
1794
|
+
settings['examples_to_plot'] = len(os.path.join(src,'merged'))
|
1775
1795
|
|
1776
1796
|
try:
|
1777
|
-
|
1797
|
+
merged_src = os.path.join(src,'merged')
|
1798
|
+
files = os.listdir(merged_src)
|
1799
|
+
random.shuffle(files)
|
1800
|
+
time_ls = []
|
1801
|
+
|
1802
|
+
for i, file in enumerate(files):
|
1803
|
+
start = time.time()
|
1804
|
+
if i+1 <= settings['examples_to_plot']:
|
1805
|
+
file_path = os.path.join(merged_src, file)
|
1806
|
+
plot_image_mask_overlay(file_path, settings['channels'], settings['cell_channel'], settings['nucleus_channel'], settings['pathogen_channel'], figuresize=10, normalize=True, thickness=3, save_pdf=True)
|
1807
|
+
stop = time.time()
|
1808
|
+
duration = stop-start
|
1809
|
+
time_ls.append(duration)
|
1810
|
+
files_processed = i+1
|
1811
|
+
files_to_process = settings['examples_to_plot']
|
1812
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type="Plot mask outlines")
|
1813
|
+
print("Successfully completed run")
|
1778
1814
|
except Exception as e:
|
1779
1815
|
print(f'Failed to plot image mask overly. Error: {e}')
|
1780
1816
|
else:
|
@@ -1788,16 +1824,13 @@ def preprocess_generate_masks(src, settings={}):
|
|
1788
1824
|
def identify_masks_finetune(settings):
|
1789
1825
|
|
1790
1826
|
from .plot import print_mask_and_flows
|
1791
|
-
from .utils import get_files_from_dir, resize_images_and_labels
|
1827
|
+
from .utils import get_files_from_dir, resize_images_and_labels, print_progress
|
1792
1828
|
from .io import _load_normalized_images_and_labels, _load_images_and_labels
|
1793
1829
|
from .settings import get_identify_masks_finetune_default_settings
|
1794
1830
|
|
1795
1831
|
settings = get_identify_masks_finetune_default_settings(settings)
|
1796
|
-
|
1797
|
-
#User defined settings
|
1798
1832
|
src=settings['src']
|
1799
1833
|
dst=settings['dst']
|
1800
|
-
|
1801
1834
|
model_name=settings['model_name']
|
1802
1835
|
custom_model=settings['custom_model']
|
1803
1836
|
channels = settings['channels']
|
@@ -1903,8 +1936,12 @@ def identify_masks_finetune(settings):
|
|
1903
1936
|
stop = time.time()
|
1904
1937
|
duration = (stop - start)
|
1905
1938
|
time_ls.append(duration)
|
1906
|
-
|
1907
|
-
|
1939
|
+
files_processed = len(images)
|
1940
|
+
files_to_process = file_index+1
|
1941
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls)
|
1942
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type="")
|
1943
|
+
|
1944
|
+
|
1908
1945
|
if verbose:
|
1909
1946
|
if resize:
|
1910
1947
|
stack = resizescikit(stack, dims, preserve_range=True, anti_aliasing=False).astype(stack.dtype)
|
@@ -1917,212 +1954,6 @@ def identify_masks_finetune(settings):
|
|
1917
1954
|
gc.collect()
|
1918
1955
|
return
|
1919
1956
|
|
1920
|
-
def identify_masks(src, object_type, model_name, batch_size, channels, diameter, minimum_size, maximum_size, filter_intensity, flow_threshold=30, cellprob_threshold=1, figuresize=25, cmap='inferno', refine_masks=True, filter_size=True, filter_dimm=True, remove_border_objects=False, verbose=False, plot=False, merge=False, save=True, start_at=0, file_type='.npz', net_avg=True, resample=True, timelapse=False, timelapse_displacement=None, timelapse_frame_limits=None, timelapse_memory=3, timelapse_remove_transient=False, timelapse_mode='btrack', timelapse_objects='cell'):
|
1921
|
-
"""
|
1922
|
-
Identify masks from the source images.
|
1923
|
-
|
1924
|
-
Args:
|
1925
|
-
src (str): Path to the source images.
|
1926
|
-
object_type (str): Type of object to identify.
|
1927
|
-
model_name (str): Name of the model to use for identification.
|
1928
|
-
batch_size (int): Number of images to process in each batch.
|
1929
|
-
channels (list): List of channel names.
|
1930
|
-
diameter (float): Diameter of the objects to identify.
|
1931
|
-
minimum_size (int): Minimum size of objects to keep.
|
1932
|
-
maximum_size (int): Maximum size of objects to keep.
|
1933
|
-
flow_threshold (int, optional): Threshold for flow detection. Defaults to 30.
|
1934
|
-
cellprob_threshold (int, optional): Threshold for cell probability. Defaults to 1.
|
1935
|
-
figuresize (int, optional): Size of the figure. Defaults to 25.
|
1936
|
-
cmap (str, optional): Colormap for plotting. Defaults to 'inferno'.
|
1937
|
-
refine_masks (bool, optional): Flag indicating whether to refine masks. Defaults to True.
|
1938
|
-
filter_size (bool, optional): Flag indicating whether to filter based on size. Defaults to True.
|
1939
|
-
filter_dimm (bool, optional): Flag indicating whether to filter based on intensity. Defaults to True.
|
1940
|
-
remove_border_objects (bool, optional): Flag indicating whether to remove border objects. Defaults to False.
|
1941
|
-
verbose (bool, optional): Flag indicating whether to display verbose output. Defaults to False.
|
1942
|
-
plot (bool, optional): Flag indicating whether to plot the masks. Defaults to False.
|
1943
|
-
merge (bool, optional): Flag indicating whether to merge adjacent objects. Defaults to False.
|
1944
|
-
save (bool, optional): Flag indicating whether to save the masks. Defaults to True.
|
1945
|
-
start_at (int, optional): Index to start processing from. Defaults to 0.
|
1946
|
-
file_type (str, optional): File type for saving the masks. Defaults to '.npz'.
|
1947
|
-
net_avg (bool, optional): Flag indicating whether to use network averaging. Defaults to True.
|
1948
|
-
resample (bool, optional): Flag indicating whether to resample the images. Defaults to True.
|
1949
|
-
timelapse (bool, optional): Flag indicating whether to generate a timelapse. Defaults to False.
|
1950
|
-
timelapse_displacement (float, optional): Displacement threshold for timelapse. Defaults to None.
|
1951
|
-
timelapse_frame_limits (tuple, optional): Frame limits for timelapse. Defaults to None.
|
1952
|
-
timelapse_memory (int, optional): Memory for timelapse. Defaults to 3.
|
1953
|
-
timelapse_remove_transient (bool, optional): Flag indicating whether to remove transient objects in timelapse. Defaults to False.
|
1954
|
-
timelapse_mode (str, optional): Mode for timelapse. Defaults to 'btrack'.
|
1955
|
-
timelapse_objects (str, optional): Objects to track in timelapse. Defaults to 'cell'.
|
1956
|
-
|
1957
|
-
Returns:
|
1958
|
-
None
|
1959
|
-
"""
|
1960
|
-
|
1961
|
-
from .utils import _masks_to_masks_stack, _filter_cp_masks, _get_cellpose_batch_size
|
1962
|
-
from .io import _create_database, _save_object_counts_to_database, _check_masks, _get_avg_object_size
|
1963
|
-
from .timelapse import _npz_to_movie, _btrack_track_cells, _trackpy_track_cells
|
1964
|
-
from .plot import plot_masks
|
1965
|
-
|
1966
|
-
#Note add logic that handles batches of size 1 as these will break the code batches must all be > 2 images
|
1967
|
-
gc.collect()
|
1968
|
-
|
1969
|
-
if not torch.cuda.is_available():
|
1970
|
-
print(f'Torch CUDA is not available, using CPU')
|
1971
|
-
|
1972
|
-
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
1973
|
-
model = cp_models.Cellpose(gpu=True, model_type=model_name, device=device)
|
1974
|
-
|
1975
|
-
if file_type == '.npz':
|
1976
|
-
paths = [os.path.join(src, file) for file in os.listdir(src) if file.endswith('.npz')]
|
1977
|
-
else:
|
1978
|
-
paths = [os.path.join(src, file) for file in os.listdir(src) if file.endswith('.png')]
|
1979
|
-
if timelapse:
|
1980
|
-
print(f'timelaps is only compatible with npz files')
|
1981
|
-
return
|
1982
|
-
|
1983
|
-
chans = [2, 1] if model_name == 'cyto2' else [0,0] if model_name == 'nucleus' else [2,0] if model_name == 'cyto' else [2, 0]
|
1984
|
-
|
1985
|
-
if verbose == True:
|
1986
|
-
print(f'source: {src}')
|
1987
|
-
print()
|
1988
|
-
print(f'Settings: object_type: {object_type}, minimum_size: {minimum_size}, maximum_size:{maximum_size}, figuresize:{figuresize}, cmap:{cmap}, , net_avg:{net_avg}, resample:{resample}')
|
1989
|
-
print()
|
1990
|
-
print(f'Cellpose settings: Model: {model_name}, batch_size: {batch_size}, channels: {channels}, cellpose_chans: {chans}, diameter:{diameter}, flow_threshold:{flow_threshold}, cellprob_threshold:{cellprob_threshold}')
|
1991
|
-
print()
|
1992
|
-
print(f'Bool Settings: verbose:{verbose}, plot:{plot}, merge:{merge}, save:{save}, start_at:{start_at}, file_type:{file_type}, timelapse:{timelapse}')
|
1993
|
-
print()
|
1994
|
-
|
1995
|
-
count_loc = os.path.dirname(src)+'/measurements/measurements.db'
|
1996
|
-
os.makedirs(os.path.dirname(src)+'/measurements', exist_ok=True)
|
1997
|
-
_create_database(count_loc)
|
1998
|
-
|
1999
|
-
average_sizes = []
|
2000
|
-
time_ls = []
|
2001
|
-
for file_index, path in enumerate(paths):
|
2002
|
-
|
2003
|
-
name = os.path.basename(path)
|
2004
|
-
name, ext = os.path.splitext(name)
|
2005
|
-
if file_type == '.npz':
|
2006
|
-
if start_at:
|
2007
|
-
print(f'starting at file index:{start_at}')
|
2008
|
-
if file_index < start_at:
|
2009
|
-
continue
|
2010
|
-
output_folder = os.path.join(os.path.dirname(path), object_type+'_mask_stack')
|
2011
|
-
os.makedirs(output_folder, exist_ok=True)
|
2012
|
-
overall_average_size = 0
|
2013
|
-
with np.load(path) as data:
|
2014
|
-
stack = data['data']
|
2015
|
-
filenames = data['filenames']
|
2016
|
-
if timelapse:
|
2017
|
-
if len(stack) != batch_size:
|
2018
|
-
print(f'Changed batch_size:{batch_size} to {len(stack)}, data length:{len(stack)}')
|
2019
|
-
batch_size = len(stack)
|
2020
|
-
if isinstance(timelapse_frame_limits, list):
|
2021
|
-
if len(timelapse_frame_limits) >= 2:
|
2022
|
-
stack = stack[timelapse_frame_limits[0]: timelapse_frame_limits[1], :, :, :].astype(stack.dtype)
|
2023
|
-
filenames = filenames[timelapse_frame_limits[0]: timelapse_frame_limits[1]]
|
2024
|
-
batch_size = len(stack)
|
2025
|
-
print(f'Cut batch an indecies: {timelapse_frame_limits}, New batch_size: {batch_size} ')
|
2026
|
-
|
2027
|
-
for i in range(0, stack.shape[0], batch_size):
|
2028
|
-
mask_stack = []
|
2029
|
-
start = time.time()
|
2030
|
-
|
2031
|
-
if stack.shape[3] == 1:
|
2032
|
-
batch = stack[i: i+batch_size, :, :, [0,0]].astype(stack.dtype)
|
2033
|
-
else:
|
2034
|
-
batch = stack[i: i+batch_size, :, :, channels].astype(stack.dtype)
|
2035
|
-
|
2036
|
-
batch_filenames = filenames[i: i+batch_size].tolist()
|
2037
|
-
|
2038
|
-
if not plot:
|
2039
|
-
batch, batch_filenames = _check_masks(batch, batch_filenames, output_folder)
|
2040
|
-
if batch.size == 0:
|
2041
|
-
print(f'Processing: {file_index}/{len(paths)}: Images/N100pz {batch.shape[0]}')
|
2042
|
-
#print(f'Processing {file_index}/{len(paths)}: Images/N100pz {batch.shape[0]}', end='\r', flush=True)
|
2043
|
-
continue
|
2044
|
-
if batch.max() > 1:
|
2045
|
-
batch = batch / batch.max()
|
2046
|
-
|
2047
|
-
if timelapse:
|
2048
|
-
stitch_threshold=100.0
|
2049
|
-
movie_path = os.path.join(os.path.dirname(src), 'movies')
|
2050
|
-
os.makedirs(movie_path, exist_ok=True)
|
2051
|
-
save_path = os.path.join(movie_path, f'timelapse_{object_type}_{name}.mp4')
|
2052
|
-
_npz_to_movie(batch, batch_filenames, save_path, fps=2)
|
2053
|
-
else:
|
2054
|
-
stitch_threshold=0.0
|
2055
|
-
|
2056
|
-
cellpose_batch_size = _get_cellpose_batch_size()
|
2057
|
-
|
2058
|
-
masks, flows, _, _ = model.eval(x=batch,
|
2059
|
-
batch_size=cellpose_batch_size,
|
2060
|
-
normalize=False,
|
2061
|
-
channels=chans,
|
2062
|
-
channel_axis=3,
|
2063
|
-
diameter=diameter,
|
2064
|
-
flow_threshold=flow_threshold,
|
2065
|
-
cellprob_threshold=cellprob_threshold,
|
2066
|
-
rescale=None,
|
2067
|
-
resample=resample,
|
2068
|
-
stitch_threshold=stitch_threshold,
|
2069
|
-
progress=None)
|
2070
|
-
|
2071
|
-
print('Masks shape',masks.shape)
|
2072
|
-
if timelapse:
|
2073
|
-
_save_object_counts_to_database(masks, object_type, batch_filenames, count_loc, added_string='_timelapse')
|
2074
|
-
if object_type in timelapse_objects:
|
2075
|
-
if timelapse_mode == 'btrack':
|
2076
|
-
if not timelapse_displacement is None:
|
2077
|
-
radius = timelapse_displacement
|
2078
|
-
else:
|
2079
|
-
radius = 100
|
2080
|
-
|
2081
|
-
n_jobs = os.cpu_count()-2
|
2082
|
-
if n_jobs < 1:
|
2083
|
-
n_jobs = 1
|
2084
|
-
|
2085
|
-
mask_stack = _btrack_track_cells(src, name, batch_filenames, object_type, plot, save, masks_3D=masks, mode=timelapse_mode, timelapse_remove_transient=timelapse_remove_transient, radius=radius, n_jobs=n_jobs)
|
2086
|
-
if timelapse_mode == 'trackpy':
|
2087
|
-
mask_stack = _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelapse_displacement, timelapse_memory, timelapse_remove_transient, plot, save, timelapse_mode)
|
2088
|
-
|
2089
|
-
else:
|
2090
|
-
mask_stack = _masks_to_masks_stack(masks)
|
2091
|
-
|
2092
|
-
else:
|
2093
|
-
_save_object_counts_to_database(masks, object_type, batch_filenames, count_loc, added_string='_before_filtration')
|
2094
|
-
mask_stack = _filter_cp_masks(masks, flows, filter_size, filter_intensity, minimum_size, maximum_size, remove_border_objects, merge, batch, plot, figuresize)
|
2095
|
-
_save_object_counts_to_database(mask_stack, object_type, batch_filenames, count_loc, added_string='_after_filtration')
|
2096
|
-
|
2097
|
-
if not np.any(mask_stack):
|
2098
|
-
average_obj_size = 0
|
2099
|
-
else:
|
2100
|
-
average_obj_size = _get_avg_object_size(mask_stack)
|
2101
|
-
|
2102
|
-
average_sizes.append(average_obj_size)
|
2103
|
-
overall_average_size = np.mean(average_sizes) if len(average_sizes) > 0 else 0
|
2104
|
-
|
2105
|
-
stop = time.time()
|
2106
|
-
duration = (stop - start)
|
2107
|
-
time_ls.append(duration)
|
2108
|
-
average_time = np.mean(time_ls) if len(time_ls) > 0 else 0
|
2109
|
-
time_in_min = average_time/60
|
2110
|
-
time_per_mask = average_time/batch_size
|
2111
|
-
print(f'Processing: {len(paths)} files with {batch_size} imgs: {(file_index+1)*(batch_size+1)}/{(len(paths))*(batch_size+1)}: Time/batch {time_in_min:.3f} min: Time/mask {time_per_mask:.3f}sec: {object_type} size: {overall_average_size:.3f} px2')
|
2112
|
-
#print(f'Processing {len(paths)} files with {batch_size} imgs: {(file_index+1)*(batch_size+1)}/{(len(paths))*(batch_size+1)}: Time/batch {time_in_min:.3f} min: Time/mask {time_per_mask:.3f}sec: {object_type} size: {overall_average_size:.3f} px2', end='\r', flush=True)
|
2113
|
-
if not timelapse:
|
2114
|
-
if plot:
|
2115
|
-
plot_masks(batch, mask_stack, flows, figuresize=figuresize, cmap=cmap, nr=batch_size, file_type='.npz')
|
2116
|
-
if save:
|
2117
|
-
if file_type == '.npz':
|
2118
|
-
for mask_index, mask in enumerate(mask_stack):
|
2119
|
-
output_filename = os.path.join(output_folder, batch_filenames[mask_index])
|
2120
|
-
np.save(output_filename, mask)
|
2121
|
-
mask_stack = []
|
2122
|
-
batch_filenames = []
|
2123
|
-
gc.collect()
|
2124
|
-
return
|
2125
|
-
|
2126
1957
|
def all_elements_match(list1, list2):
|
2127
1958
|
# Check if all elements in list1 are in list2
|
2128
1959
|
return all(element in list2 for element in list1)
|
@@ -2141,7 +1972,7 @@ def prepare_batch_for_cellpose(batch):
|
|
2141
1972
|
|
2142
1973
|
def generate_cellpose_masks(src, settings, object_type):
|
2143
1974
|
|
2144
|
-
from .utils import _masks_to_masks_stack, _filter_cp_masks, _get_cellpose_batch_size, _get_cellpose_channels, _choose_model, mask_object_count
|
1975
|
+
from .utils import _masks_to_masks_stack, _filter_cp_masks, _get_cellpose_batch_size, _get_cellpose_channels, _choose_model, mask_object_count, print_progress
|
2145
1976
|
from .io import _create_database, _save_object_counts_to_database, _check_masks, _get_avg_object_size
|
2146
1977
|
from .timelapse import _npz_to_movie, _btrack_track_cells, _trackpy_track_cells
|
2147
1978
|
from .plot import plot_masks
|
@@ -2187,7 +2018,7 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2187
2018
|
|
2188
2019
|
if object_type == 'pathogen' and not settings['pathogen_model'] is None:
|
2189
2020
|
model_name = settings['pathogen_model']
|
2190
|
-
|
2021
|
+
|
2191
2022
|
model = _choose_model(model_name, device, object_type=object_type, restore_type=None, object_settings=object_settings)
|
2192
2023
|
|
2193
2024
|
chans = [2, 1] if model_name == 'cyto2' else [0,0] if model_name == 'nucleus' else [2,0] if model_name == 'cyto' else [2, 0] if model_name == 'cyto3' else [2, 0]
|
@@ -2199,16 +2030,18 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2199
2030
|
|
2200
2031
|
average_sizes = []
|
2201
2032
|
time_ls = []
|
2033
|
+
|
2202
2034
|
for file_index, path in enumerate(paths):
|
2203
2035
|
name = os.path.basename(path)
|
2204
2036
|
name, ext = os.path.splitext(name)
|
2205
2037
|
output_folder = os.path.join(os.path.dirname(path), object_type+'_mask_stack')
|
2206
2038
|
os.makedirs(output_folder, exist_ok=True)
|
2207
2039
|
overall_average_size = 0
|
2040
|
+
|
2208
2041
|
with np.load(path) as data:
|
2209
2042
|
stack = data['data']
|
2210
2043
|
filenames = data['filenames']
|
2211
|
-
|
2044
|
+
|
2212
2045
|
for i, filename in enumerate(filenames):
|
2213
2046
|
output_path = os.path.join(output_folder, filename)
|
2214
2047
|
|
@@ -2233,11 +2066,9 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2233
2066
|
filenames = filenames[timelapse_frame_limits[0]: timelapse_frame_limits[1]]
|
2234
2067
|
batch_size = len(stack)
|
2235
2068
|
print(f'Cut batch at indecies: {timelapse_frame_limits}, New batch_size: {batch_size} ')
|
2236
|
-
|
2069
|
+
|
2237
2070
|
for i in range(0, stack.shape[0], batch_size):
|
2238
2071
|
mask_stack = []
|
2239
|
-
start = time.time()
|
2240
|
-
|
2241
2072
|
if stack.shape[3] == 1:
|
2242
2073
|
batch = stack[i: i+batch_size, :, :, [0,0]].astype(stack.dtype)
|
2243
2074
|
else:
|
@@ -2248,7 +2079,6 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2248
2079
|
if not settings['plot']:
|
2249
2080
|
batch, batch_filenames = _check_masks(batch, batch_filenames, output_folder)
|
2250
2081
|
if batch.size == 0:
|
2251
|
-
print(f'Processing {file_index}/{len(paths)}: Images/npz {batch.shape[0]}')
|
2252
2082
|
continue
|
2253
2083
|
|
2254
2084
|
batch = prepare_batch_for_cellpose(batch)
|
@@ -2259,16 +2089,6 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2259
2089
|
save_path = os.path.join(movie_path, f'timelapse_{object_type}_{name}.mp4')
|
2260
2090
|
_npz_to_movie(batch, batch_filenames, save_path, fps=2)
|
2261
2091
|
|
2262
|
-
if settings['verbose']:
|
2263
|
-
print(f'Processing {file_index}/{len(paths)}: Images/npz {batch.shape[0]}')
|
2264
|
-
|
2265
|
-
#cellpose_normalize_dict = {'lowhigh':[0.0,1.0], #pass in normalization values for 0.0 and 1.0 as list [low, high] if None all other keys ignored
|
2266
|
-
# 'sharpen':object_settings['diameter']/4, #recommended to be 1/4-1/8 diameter of cells in pixels
|
2267
|
-
# 'normalize':True, #(if False, all following parameters ignored)
|
2268
|
-
# 'percentile':[2,98], #[perc_low, perc_high]
|
2269
|
-
# 'tile_norm':224, #normalize by tile set to e.g. 100 for normailize window to be 100 px
|
2270
|
-
# 'norm3D':True} #compute normalization across entire z-stack rather than plane-by-plane in stitching mode.
|
2271
|
-
|
2272
2092
|
output = model.eval(x=batch,
|
2273
2093
|
batch_size=cellpose_batch_size,
|
2274
2094
|
normalize=False,
|
@@ -2378,14 +2198,8 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2378
2198
|
|
2379
2199
|
average_sizes.append(average_obj_size)
|
2380
2200
|
overall_average_size = np.mean(average_sizes) if len(average_sizes) > 0 else 0
|
2201
|
+
print(f'object_size:{object_type}: {overall_average_size:.3f} px2')
|
2381
2202
|
|
2382
|
-
stop = time.time()
|
2383
|
-
duration = (stop - start)
|
2384
|
-
time_ls.append(duration)
|
2385
|
-
average_time = np.mean(time_ls) if len(time_ls) > 0 else 0
|
2386
|
-
time_in_min = average_time/60
|
2387
|
-
time_per_mask = average_time/batch_size
|
2388
|
-
print(f'Processing {len(paths)} files with {batch_size} imgs: {(file_index+1)*(batch_size+1)}/{(len(paths))*(batch_size+1)}: Time/batch {time_in_min:.3f} min: Time/mask {time_per_mask:.3f}sec: {object_type} size: {overall_average_size:.3f} px2')
|
2389
2203
|
if not timelapse:
|
2390
2204
|
if settings['plot']:
|
2391
2205
|
plot_masks(batch, mask_stack, flows, figuresize=figuresize, cmap='inferno', nr=batch_size)
|
@@ -2396,6 +2210,7 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2396
2210
|
np.save(output_filename, mask)
|
2397
2211
|
mask_stack = []
|
2398
2212
|
batch_filenames = []
|
2213
|
+
|
2399
2214
|
gc.collect()
|
2400
2215
|
torch.cuda.empty_cache()
|
2401
2216
|
return
|
@@ -2403,7 +2218,7 @@ def generate_cellpose_masks(src, settings, object_type):
|
|
2403
2218
|
def generate_masks_from_imgs(src, model, model_name, batch_size, diameter, cellprob_threshold, flow_threshold, grayscale, save, normalize, channels, percentiles, circular, invert, plot, resize, target_height, target_width, remove_background, background, Signal_to_noise, verbose):
|
2404
2219
|
|
2405
2220
|
from .io import _load_images_and_labels, _load_normalized_images_and_labels
|
2406
|
-
from .utils import resize_images_and_labels, resizescikit
|
2221
|
+
from .utils import resize_images_and_labels, resizescikit, print_progress
|
2407
2222
|
from .plot import print_mask_and_flows
|
2408
2223
|
|
2409
2224
|
dst = os.path.join(src, model_name)
|
@@ -2462,8 +2277,11 @@ def generate_masks_from_imgs(src, model, model_name, batch_size, diameter, cellp
|
|
2462
2277
|
stop = time.time()
|
2463
2278
|
duration = (stop - start)
|
2464
2279
|
time_ls.append(duration)
|
2465
|
-
|
2466
|
-
|
2280
|
+
files_processed = file_index+1
|
2281
|
+
files_to_process = len(images)
|
2282
|
+
|
2283
|
+
print_progress(files_processed, files_to_process, n_jobs=1, time_ls=time_ls, batch_size=None, operation_type="Generating masks")
|
2284
|
+
|
2467
2285
|
if plot:
|
2468
2286
|
if resize:
|
2469
2287
|
stack = resizescikit(stack, dims, preserve_range=True, anti_aliasing=False).astype(stack.dtype)
|