celldetective 1.3.7__tar.gz → 1.3.7.post2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. {celldetective-1.3.7 → celldetective-1.3.7.post2}/PKG-INFO +11 -2
  2. celldetective-1.3.7.post2/celldetective/_version.py +1 -0
  3. celldetective-1.3.7.post2/celldetective/gui/processes/downloader.py +108 -0
  4. celldetective-1.3.7.post2/celldetective/gui/processes/measure_cells.py +346 -0
  5. celldetective-1.3.7.post2/celldetective/gui/processes/segment_cells.py +327 -0
  6. celldetective-1.3.7.post2/celldetective/gui/processes/track_cells.py +298 -0
  7. celldetective-1.3.7.post2/celldetective/gui/processes/train_segmentation_model.py +270 -0
  8. celldetective-1.3.7.post2/celldetective/gui/processes/train_signal_model.py +108 -0
  9. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/io.py +26 -1
  10. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/measure.py +12 -144
  11. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/relative_measurements.py +40 -43
  12. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/signals.py +41 -292
  13. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/tracking.py +16 -22
  14. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/PKG-INFO +11 -2
  15. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/SOURCES.txt +6 -0
  16. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/requires.txt +1 -0
  17. {celldetective-1.3.7 → celldetective-1.3.7.post2}/setup.py +1 -1
  18. celldetective-1.3.7/celldetective/_version.py +0 -1
  19. {celldetective-1.3.7 → celldetective-1.3.7.post2}/LICENSE +0 -0
  20. {celldetective-1.3.7 → celldetective-1.3.7.post2}/README.md +0 -0
  21. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/__init__.py +0 -0
  22. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/__main__.py +0 -0
  23. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/datasets/segmentation_annotations/blank +0 -0
  24. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/datasets/signal_annotations/blank +0 -0
  25. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/events.py +0 -0
  26. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/extra_properties.py +0 -0
  27. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/filters.py +0 -0
  28. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/InitWindow.py +0 -0
  29. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/__init__.py +0 -0
  30. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/about.py +0 -0
  31. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/analyze_block.py +0 -0
  32. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/btrack_options.py +0 -0
  33. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/classifier_widget.py +0 -0
  34. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/configure_new_exp.py +0 -0
  35. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/control_panel.py +0 -0
  36. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/generic_signal_plot.py +0 -0
  37. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/gui_utils.py +0 -0
  38. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  39. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  40. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/cell-populations.json +0 -0
  41. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/exp-structure.json +0 -0
  42. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/feature-btrack.json +0 -0
  43. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/neighborhood.json +0 -0
  44. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  45. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/preprocessing.json +0 -0
  46. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/propagate-classification.json +0 -0
  47. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/track-postprocessing.json +0 -0
  48. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/help/tracking.json +0 -0
  49. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/json_readers.py +0 -0
  50. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/layouts.py +0 -0
  51. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/measurement_options.py +0 -0
  52. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/neighborhood_options.py +0 -0
  53. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/plot_measurements.py +0 -0
  54. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/plot_signals_ui.py +0 -0
  55. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/process_block.py +0 -0
  56. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
  57. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/retrain_signal_model_options.py +0 -0
  58. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/seg_model_loader.py +0 -0
  59. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/signal_annotator.py +0 -0
  60. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/signal_annotator2.py +0 -0
  61. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/signal_annotator_options.py +0 -0
  62. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/styles.py +0 -0
  63. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/survival_ui.py +0 -0
  64. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/tableUI.py +0 -0
  65. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/thresholds_gui.py +0 -0
  66. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/viewers.py +0 -0
  67. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/gui/workers.py +0 -0
  68. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/logo-large.png +0 -0
  69. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/logo.png +0 -0
  70. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/signals_icon.png +0 -0
  71. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/splash-test.png +0 -0
  72. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/splash.png +0 -0
  73. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/splash0.png +0 -0
  74. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/survival2.png +0 -0
  75. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/vignette_signals2.png +0 -0
  76. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/icons/vignette_signals2.svg +0 -0
  77. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/links/zenodo.json +0 -0
  78. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/pair_signal_detection/blank +0 -0
  79. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/blank +0 -0
  80. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
  81. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  82. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
  83. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
  84. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  85. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_generic/blank +0 -0
  86. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/segmentation_targets/blank +0 -0
  87. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/signal_detection/blank +0 -0
  88. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  89. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/tracking_configs/mcf7.json +0 -0
  90. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  91. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/tracking_configs/ricm.json +0 -0
  92. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/models/tracking_configs/ricm2.json +0 -0
  93. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/neighborhood.py +0 -0
  94. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/preprocessing.py +0 -0
  95. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/analyze_signals.py +0 -0
  96. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/measure_cells.py +0 -0
  97. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/measure_relative.py +0 -0
  98. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/segment_cells.py +0 -0
  99. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  100. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/track_cells.py +0 -0
  101. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/train_segmentation_model.py +0 -0
  102. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/scripts/train_signal_model.py +0 -0
  103. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/segmentation.py +0 -0
  104. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective/utils.py +0 -0
  105. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/dependency_links.txt +0 -0
  106. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/entry_points.txt +0 -0
  107. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/not-zip-safe +0 -0
  108. {celldetective-1.3.7 → celldetective-1.3.7.post2}/celldetective.egg-info/top_level.txt +0 -0
  109. {celldetective-1.3.7 → celldetective-1.3.7.post2}/setup.cfg +0 -0
  110. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/__init__.py +0 -0
  111. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_events.py +0 -0
  112. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_filters.py +0 -0
  113. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_io.py +0 -0
  114. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_measure.py +0 -0
  115. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_neighborhood.py +0 -0
  116. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_preprocessing.py +0 -0
  117. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_qt.py +0 -0
  118. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_segmentation.py +0 -0
  119. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_signals.py +0 -0
  120. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_tracking.py +0 -0
  121. {celldetective-1.3.7 → celldetective-1.3.7.post2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: celldetective
3
- Version: 1.3.7
3
+ Version: 1.3.7.post2
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -30,6 +30,7 @@ Requires-Dist: setuptools
30
30
  Requires-Dist: scipy
31
31
  Requires-Dist: seaborn
32
32
  Requires-Dist: opencv-python-headless==4.7.0.72
33
+ Requires-Dist: PyQt5
33
34
  Requires-Dist: liblapack
34
35
  Requires-Dist: gputools
35
36
  Requires-Dist: lmfit
@@ -43,6 +44,14 @@ Requires-Dist: h5py
43
44
  Requires-Dist: cliffs_delta
44
45
  Requires-Dist: requests
45
46
  Requires-Dist: trackpy
47
+ Dynamic: author
48
+ Dynamic: author-email
49
+ Dynamic: description
50
+ Dynamic: description-content-type
51
+ Dynamic: home-page
52
+ Dynamic: license
53
+ Dynamic: requires-dist
54
+ Dynamic: summary
46
55
 
47
56
  # Celldetective
48
57
 
@@ -0,0 +1 @@
1
+ __version__ = "1.3.7.post2"
@@ -0,0 +1,108 @@
1
+ import os
2
+ import ssl
3
+ from tqdm import tqdm
4
+ from multiprocessing import Process
5
+ from glob import glob
6
+ import shutil
7
+ from urllib.request import urlopen
8
+ import zipfile
9
+ import tempfile
10
+ import time
11
+ from pathlib import Path
12
+ import json
13
+
14
+ class DownloadProcess(Process):
15
+
16
+ def __init__(self, queue=None, process_args=None, *args, **kwargs):
17
+
18
+ super().__init__(*args, **kwargs)
19
+
20
+ if process_args is not None:
21
+ for key, value in process_args.items():
22
+ setattr(self, key, value)
23
+
24
+ self.queue = queue
25
+ self.progress = True
26
+
27
+ file_path = Path(os.path.dirname(os.path.realpath(__file__)))
28
+ zenodo_json = os.sep.join([str(file_path.parents[2]),"celldetective", "links", "zenodo.json"])
29
+ print(f"{zenodo_json=}")
30
+
31
+ with open(zenodo_json,"r") as f:
32
+ zenodo_json = json.load(f)
33
+ all_files = list(zenodo_json['files']['entries'].keys())
34
+ all_files_short = [f.replace(".zip","") for f in all_files]
35
+ zenodo_url = zenodo_json['links']['files'].replace('api/','')
36
+ full_links = ["/".join([zenodo_url, f]) for f in all_files]
37
+ index = all_files_short.index(self.file)
38
+
39
+ self.zip_url = full_links[index]
40
+ self.path_to_zip_file = os.sep.join([self.output_dir, 'temp.zip'])
41
+
42
+ self.sum_done = 0
43
+ self.t0 = time.time()
44
+
45
+ def download_url_to_file(self, url, dst):
46
+
47
+ file_size = None
48
+ ssl._create_default_https_context = ssl._create_unverified_context
49
+ u = urlopen(url)
50
+ meta = u.info()
51
+ if hasattr(meta, 'getheaders'):
52
+ content_length = meta.getheaders("Content-Length")
53
+ else:
54
+ content_length = meta.get_all("Content-Length")
55
+ if content_length is not None and len(content_length) > 0:
56
+ file_size = int(content_length[0])
57
+ # We deliberately save it in a temp file and move it after
58
+ dst = os.path.expanduser(dst)
59
+ dst_dir = os.path.dirname(dst)
60
+ f = tempfile.NamedTemporaryFile(delete=False, dir=dst_dir)
61
+
62
+ try:
63
+ with tqdm(total=file_size, disable=not self.progress,
64
+ unit='B', unit_scale=True, unit_divisor=1024) as pbar:
65
+ while True:
66
+ buffer = u.read(8192) #8192
67
+ if len(buffer) == 0:
68
+ break
69
+ f.write(buffer)
70
+ pbar.update(len(buffer))
71
+ self.sum_done+=len(buffer) / file_size * 100
72
+ mean_exec_per_step = (time.time() - self.t0) / (self.sum_done*file_size / 100 + 1)
73
+ pred_time = (file_size - (self.sum_done*file_size / 100 + 1)) * mean_exec_per_step
74
+ self.queue.put([self.sum_done, pred_time])
75
+ f.close()
76
+ shutil.move(f.name, dst)
77
+ finally:
78
+ f.close()
79
+ if os.path.exists(f.name):
80
+ os.remove(f.name)
81
+
82
+ def run(self):
83
+
84
+ self.download_url_to_file(fr"{self.zip_url}",self.path_to_zip_file)
85
+ with zipfile.ZipFile(self.path_to_zip_file, 'r') as zip_ref:
86
+ zip_ref.extractall(self.output_dir)
87
+
88
+ file_to_rename = glob(os.sep.join([self.output_dir,self.file,"*[!.json][!.png][!.h5][!.csv][!.npy][!.tif][!.ini]"]))
89
+ if len(file_to_rename)>0 and not file_to_rename[0].endswith(os.sep) and not self.file.startswith('demo'):
90
+ os.rename(file_to_rename[0], os.sep.join([self.output_dir,self.file,self.file]))
91
+
92
+ os.remove(self.path_to_zip_file)
93
+ self.queue.put([100,0])
94
+ time.sleep(0.5)
95
+
96
+ # Send end signal
97
+ self.queue.put("finished")
98
+ self.queue.close()
99
+
100
+ def end_process(self):
101
+
102
+ self.terminate()
103
+ self.queue.put("finished")
104
+
105
+ def abort_process(self):
106
+
107
+ self.terminate()
108
+ self.queue.put("error")
@@ -0,0 +1,346 @@
1
+ from multiprocessing import Process
2
+ import time
3
+ import datetime
4
+ import os
5
+ import json
6
+ from pathlib import Path, PurePath
7
+
8
+ from celldetective.io import auto_load_number_of_frames, load_frames, locate_labels
9
+ from celldetective.utils import extract_experiment_channels, ConfigSectionMap, _get_img_num_per_channel
10
+ from celldetective.utils import remove_trajectory_measurements, _extract_coordinates_from_features, _remove_invalid_cols
11
+ from celldetective.measure import drop_tonal_features, measure_features, measure_isotropic_intensity, measure_radial_distance_to_center, center_of_mass_to_abs_coordinates
12
+
13
+ from glob import glob
14
+ from tqdm import tqdm
15
+ import numpy as np
16
+ import concurrent.futures
17
+ import pandas as pd
18
+ from natsort import natsorted
19
+ from art import tprint
20
+
21
+
22
+ class MeasurementProcess(Process):
23
+
24
+ def __init__(self, queue=None, process_args=None):
25
+
26
+ super().__init__()
27
+
28
+ self.queue = queue
29
+
30
+ if process_args is not None:
31
+ for key, value in process_args.items():
32
+ setattr(self, key, value)
33
+
34
+ self.column_labels = {'track': "TRACK_ID", 'time': 'FRAME', 'x': 'POSITION_X', 'y': 'POSITION_Y'}
35
+
36
+ tprint("Measure")
37
+
38
+ # Experiment
39
+ self.prepare_folders()
40
+
41
+ self.locate_experiment_config()
42
+ self.extract_experiment_parameters()
43
+ self.read_measurement_instructions()
44
+ self.detect_movie_and_labels()
45
+ self.detect_tracks()
46
+ self.detect_channels()
47
+
48
+ self.check_possible_measurements()
49
+
50
+ self.write_log()
51
+
52
+ self.sum_done = 0
53
+ self.t0 = time.time()
54
+
55
+ def check_possible_measurements(self):
56
+
57
+ if (self.file is None) or (self.intensity_measurement_radii is None):
58
+ self.do_iso_intensities = False
59
+ print('Either no image, no positions or no radii were provided... Isotropic intensities will not be computed...')
60
+ else:
61
+ self.do_iso_intensities = True
62
+
63
+ if self.label_path is None:
64
+ self.do_features = False
65
+ print('No labels were provided... Features will not be computed...')
66
+ else:
67
+ self.do_features = True
68
+
69
+ if self.trajectories is None:
70
+ print('Use features as a substitute for the trajectory table.')
71
+ if 'label' not in self.features:
72
+ self.features.append('label')
73
+
74
+
75
+ def read_measurement_instructions(self):
76
+
77
+ print('Looking for measurement instruction file...')
78
+ instr_path = PurePath(self.expfolder,Path(f"{self.instruction_file}"))
79
+ if os.path.exists(instr_path):
80
+ with open(instr_path, 'r') as f:
81
+ self.instructions = json.load(f)
82
+ print(f"Measurement instruction file successfully loaded...")
83
+ print(f"Instructions: {self.instructions}...")
84
+
85
+ if 'background_correction' in self.instructions:
86
+ self.background_correction = self.instructions['background_correction']
87
+ else:
88
+ self.background_correction = None
89
+
90
+ if 'features' in self.instructions:
91
+ self.features = self.instructions['features']
92
+ else:
93
+ self.features = None
94
+
95
+ if 'border_distances' in self.instructions:
96
+ self.border_distances = self.instructions['border_distances']
97
+ else:
98
+ self.border_distances = None
99
+
100
+ if 'spot_detection' in self.instructions:
101
+ self.spot_detection = self.instructions['spot_detection']
102
+ else:
103
+ self.spot_detection = None
104
+
105
+ if 'haralick_options' in self.instructions:
106
+ self.haralick_options = self.instructions['haralick_options']
107
+ else:
108
+ self.haralick_options = None
109
+
110
+ if 'intensity_measurement_radii' in self.instructions:
111
+ self.intensity_measurement_radii = self.instructions['intensity_measurement_radii']
112
+ else:
113
+ self.intensity_measurement_radii = None
114
+
115
+ if 'isotropic_operations' in self.instructions:
116
+ self.isotropic_operations = self.instructions['isotropic_operations']
117
+ else:
118
+ self.isotropic_operations = None
119
+
120
+ if 'clear_previous' in self.instructions:
121
+ self.clear_previous = self.instructions['clear_previous']
122
+ else:
123
+ self.clear_previous = True
124
+
125
+ else:
126
+ print('No measurement instructions found. Use default measurements.')
127
+ self.features = ['area', 'intensity_mean']
128
+ self.border_distances = None
129
+ self.haralick_options = None
130
+ self.clear_previous = False
131
+ self.background_correction = None
132
+ self.spot_detection = None
133
+ self.intensity_measurement_radii = 10
134
+ self.isotropic_operations = ['mean']
135
+
136
+ if self.features is None:
137
+ self.features = []
138
+
139
+
140
+ def detect_channels(self):
141
+ self.img_num_channels = _get_img_num_per_channel(self.channel_indices, self.len_movie, self.nbr_channels)
142
+
143
+ def write_log(self):
144
+
145
+ features_log=f'features: {self.features}'
146
+ border_distances_log=f'border_distances: {self.border_distances}'
147
+ haralick_options_log=f'haralick_options: {self.haralick_options}'
148
+ background_correction_log=f'background_correction: {self.background_correction}'
149
+ spot_detection_log=f'spot_detection: {self.spot_detection}'
150
+ intensity_measurement_radii_log=f'intensity_measurement_radii: {self.intensity_measurement_radii}'
151
+ isotropic_options_log=f'isotropic_operations: {self.isotropic_operations} \n'
152
+ log='\n'.join([features_log,border_distances_log,haralick_options_log,background_correction_log,spot_detection_log,intensity_measurement_radii_log,isotropic_options_log])
153
+ with open(self.pos + f'log_{self.mode}.txt', 'a') as f:
154
+ f.write(f'{datetime.datetime.now()} MEASURE \n')
155
+ f.write(log+'\n')
156
+
157
+ def prepare_folders(self):
158
+
159
+ if self.mode.lower()=="target" or self.mode.lower()=="targets":
160
+ self.label_folder = "labels_targets"
161
+ self.table_name = "trajectories_targets.csv"
162
+ self.instruction_file = os.sep.join(["configs","measurement_instructions_targets.json"])
163
+
164
+ elif self.mode.lower()=="effector" or self.mode.lower()=="effectors":
165
+ self.label_folder = "labels_effectors"
166
+ self.table_name = "trajectories_effectors.csv"
167
+ self.instruction_file = os.sep.join(["configs","measurement_instructions_effectors.json"])
168
+
169
+ def extract_experiment_parameters(self):
170
+
171
+ self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
172
+ self.spatial_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["pxtoum"])
173
+ self.time_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["frametomin"])
174
+ self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
175
+ self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
176
+ self.shape_y = int(ConfigSectionMap(self.config,"MovieSettings")["shape_y"])
177
+
178
+ self.channel_names, self.channel_indices = extract_experiment_channels(self.config)
179
+ self.nbr_channels = len(self.channel_names)
180
+
181
+ def locate_experiment_config(self):
182
+
183
+ parent1 = Path(self.pos).parent
184
+ self.expfolder = parent1.parent
185
+ self.config = PurePath(self.expfolder,Path("config.ini"))
186
+
187
+ if not os.path.exists(self.config):
188
+ print('The configuration file for the experiment was not found...')
189
+ self.abort_process()
190
+
191
+ def detect_tracks(self):
192
+
193
+ # Load trajectories, add centroid if not in trajectory
194
+ self.trajectories = self.pos+os.sep.join(['output','tables', self.table_name])
195
+ if os.path.exists(self.trajectories):
196
+ print('trajectory exists...')
197
+ self.trajectories = pd.read_csv(self.trajectories)
198
+ if 'TRACK_ID' not in list(self.trajectories.columns):
199
+ self.do_iso_intensities = False
200
+ self.intensity_measurement_radii = None
201
+ if self.clear_previous:
202
+ print('No TRACK_ID... Clear previous measurements...')
203
+ self.trajectories = None #remove_trajectory_measurements(trajectories, column_labels)
204
+ self.do_features = True
205
+ self.features += ['centroid']
206
+ else:
207
+ if self.clear_previous:
208
+ print('TRACK_ID found... Clear previous measurements...')
209
+ self.trajectories = remove_trajectory_measurements(self.trajectories, self.column_labels)
210
+ else:
211
+ self.trajectories = None
212
+ self.do_features = True
213
+ self.features += ['centroid']
214
+ self.do_iso_intensities = False
215
+
216
+ def detect_movie_and_labels(self):
217
+
218
+ self.label_path = natsorted(glob(os.sep.join([self.pos, self.label_folder, '*.tif'])))
219
+ if len(self.label_path)>0:
220
+ print(f"Found {len(self.label_path)} segmented frames...")
221
+ else:
222
+ self.features = None
223
+ self.haralick_options = None
224
+ self.border_distances = None
225
+ self.label_path = None
226
+
227
+ try:
228
+ self.file = glob(self.pos+os.sep.join(["movie", f"{self.movie_prefix}*.tif"]))[0]
229
+ except IndexError:
230
+ self.file = None
231
+ self.haralick_option = None
232
+ self.features = drop_tonal_features(self.features)
233
+
234
+ len_movie_auto = auto_load_number_of_frames(self.file)
235
+ if len_movie_auto is not None:
236
+ self.len_movie = len_movie_auto
237
+
238
+ def parallel_job(self, indices):
239
+
240
+ measurements = []
241
+
242
+ for t in tqdm(indices,desc="frame"):
243
+
244
+ if self.file is not None:
245
+ img = load_frames(self.img_num_channels[:,t], self.file, scale=None, normalize_input=False)
246
+
247
+ if self.label_path is not None:
248
+
249
+ lbl = locate_labels(self.pos, population=self.mode, frames=t)
250
+ if lbl is None:
251
+ continue
252
+
253
+ if self.trajectories is not None:
254
+
255
+ positions_at_t = self.trajectories.loc[self.trajectories[self.column_labels['time']]==t].copy()
256
+
257
+ if self.do_features:
258
+ feature_table = measure_features(img, lbl, features=self.features, border_dist=self.border_distances,
259
+ channels=self.channel_names, haralick_options=self.haralick_options, verbose=False,
260
+ normalisation_list=self.background_correction, spot_detection=self.spot_detection)
261
+ if self.trajectories is None:
262
+ positions_at_t = _extract_coordinates_from_features(feature_table, timepoint=t)
263
+ column_labels = {'track': "ID", 'time': self.column_labels['time'], 'x': self.column_labels['x'],
264
+ 'y': self.column_labels['y']}
265
+ feature_table.rename(columns={'centroid-1': 'POSITION_X', 'centroid-0': 'POSITION_Y'}, inplace=True)
266
+
267
+ if self.do_iso_intensities and not self.trajectories is None:
268
+ iso_table = measure_isotropic_intensity(positions_at_t, img, channels=self.channel_names, intensity_measurement_radii=self.intensity_measurement_radii, column_labels=self.column_labels, operations=self.isotropic_operations, verbose=False)
269
+
270
+ if self.do_iso_intensities and self.do_features and not self.trajectories is None:
271
+ measurements_at_t = iso_table.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
272
+ measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
273
+ elif self.do_iso_intensities * (not self.do_features) * (not self.trajectories is None):
274
+ measurements_at_t = iso_table
275
+ elif self.do_features:
276
+ measurements_at_t = positions_at_t.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
277
+ measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
278
+
279
+ measurements_at_t = center_of_mass_to_abs_coordinates(measurements_at_t)
280
+ measurements_at_t = measure_radial_distance_to_center(measurements_at_t, volume=img.shape, column_labels=self.column_labels)
281
+
282
+ self.sum_done+=1/self.len_movie*100
283
+ mean_exec_per_step = (time.time() - self.t0) / (self.sum_done*self.len_movie / 100 + 1)
284
+ pred_time = (self.len_movie - (self.sum_done*self.len_movie / 100 + 1)) * mean_exec_per_step
285
+ self.queue.put([self.sum_done, pred_time])
286
+
287
+ if measurements_at_t is not None:
288
+ measurements_at_t[self.column_labels['time']] = t
289
+ else:
290
+ measurements_at_t = pd.DataFrame()
291
+
292
+ measurements.append(measurements_at_t)
293
+
294
+ return measurements
295
+
296
+ def run(self):
297
+
298
+ self.indices = list(range(self.img_num_channels.shape[1]))
299
+ chunks = np.array_split(self.indices, self.n_threads)
300
+
301
+ self.timestep_dataframes = []
302
+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.n_threads) as executor:
303
+ results = executor.map(self.parallel_job, chunks) #list(map(lambda x: executor.submit(self.parallel_job, x), chunks))
304
+ try:
305
+ for i,return_value in enumerate(results):
306
+ print(f'Thread {i} completed...')
307
+ self.timestep_dataframes.extend(return_value)
308
+ except Exception as e:
309
+ print("Exception: ", e)
310
+
311
+ print('Measurements successfully performed...')
312
+
313
+ if len(self.timestep_dataframes)>0:
314
+
315
+ df = pd.concat(self.timestep_dataframes)
316
+
317
+ if self.trajectories is not None:
318
+ df = df.sort_values(by=[self.column_labels['track'],self.column_labels['time']])
319
+ df = df.dropna(subset=[self.column_labels['track']])
320
+ else:
321
+ df['ID'] = np.arange(len(df))
322
+ df = df.sort_values(by=[self.column_labels['time'], 'ID'])
323
+
324
+ df = df.reset_index(drop=True)
325
+ df = _remove_invalid_cols(df)
326
+
327
+ df.to_csv(self.pos+os.sep.join(["output", "tables", self.table_name]), index=False)
328
+ print(f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...')
329
+ print('Done.')
330
+ else:
331
+ print('No measurement could be performed. Check your inputs.')
332
+ print('Done.')
333
+
334
+ # Send end signal
335
+ self.queue.put("finished")
336
+ self.queue.close()
337
+
338
+ def end_process(self):
339
+
340
+ self.terminate()
341
+ self.queue.put("finished")
342
+
343
+ def abort_process(self):
344
+
345
+ self.terminate()
346
+ self.queue.put("error")