batoolset 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,653 @@
1
+ import os.path
2
+ from skimage import measure
3
+ from skimage.measure import regionprops
4
+ import numpy as np
5
+ from batoolset.img import Img, RGB_to_int24, int24_to_RGB
6
+ from timeit import default_timer as timer
7
+
8
+ # if the stuff has been done by the module then
9
+ from batoolset.colors.colorgen import get_forbidden_colors_int24
10
+ from batoolset.ta.tracking.registration import pre_register_images, apply_translation
11
+ from batoolset.files.tools import assign_random_ID_to_missing_cells, get_TA_file, first_image_tracking
12
+ from batoolset.ta.tracking.tracking_error_detector_and_fixer import find_vertices, associate_cell_to_its_neighbors2, \
13
+ associate_cells_to_neighbors_ID_in_dict, compute_neighbor_score, optimize_score, get_cells_in_image_n_fisrt_pixel, \
14
+ map_track_id_to_label, apply_color_to_labels
15
+
16
+ # TODO also finalize this tracking code and offer it as a registration
17
+ # also offer it as a check for segmentation --> try run the wshed locally with that
18
+
19
+ # TODO --> if two or more cells match then maybe try to find the best fit
20
+ # --> a good idea --> maybe could use area or cell elongation as the main criterion
21
+
22
+
23
+ # def sort_rps_by_area(rps):
24
+ # --> TODO add the possibility to warp
25
+ # also do a code to reconnect tracks that I may also use to MT the tracking --> I may need to know how to handle shared colored cell list or do two by two and do a code that can handle the junction of al the two by two pairs --> TODO
26
+ # indeed try to do that
27
+ # hack the other tracking code so that it does not need the cells
28
+ # TODO add checks...
29
+ # I still need to have and store all the cells to avoid duplicating IDs --> also need check that this is done properly ...
30
+
31
+ # le code doit surement etre ok --> à finaliser... et à tester
32
+ # en fait le code peut aussi etre utilisé pour de la segmentation --> à essayer...
33
+ # --> warper une segmentation existante et l'appliquer au suivant et si une autre seg est dispo alors voir si on peut prendre le meilleur des deux mondes...
34
+
35
+ # TODO --> also finalize the code so that it can be used on a regular image to track
36
+ # if first image --> need generate the iamge then I need to be sure whether the stuff is working or not
37
+ # I need to have the already assigned colors passed in too
38
+ from batoolset.tools.early_stopper_class import early_stop
39
+ from batoolset.utils.loadlist import loadlist
40
+
41
+ def match_by_max_overlap(name_t1, name_t0, channel_of_interest=None, assigned_IDs=[], recursive_assignment=True, warp_using_mermaid_if_map_is_available=True, pre_register=True):
42
+ """
43
+ Match cells between two timepoints based on maximizing overlap.
44
+
45
+ Args:
46
+ name_t1 (str): Filename of the first timepoint.
47
+ name_t0 (str): Filename of the second timepoint.
48
+ channel_of_interest (str): Name of the channel of interest.
49
+ assigned_IDs (list): List of already assigned cell IDs.
50
+ recursive_assignment (bool): Flag indicating whether to perform recursive assignment.
51
+ warp_using_mermaid_if_map_is_available (bool): Flag indicating whether to warp using Mermaid if a map is available.
52
+ pre_register (bool): Flag indicating whether to perform pre-registration.
53
+
54
+ Returns:
55
+ None
56
+ """
57
+
58
+ # Get the filename of the first timepoint without the extension
59
+ filename1_without_ext = os.path.splitext(name_t1)[0]
60
+
61
+ # Load the hand-corrected mask for the first timepoint
62
+ mask_t1 = Img(os.path.join(filename1_without_ext, 'handCorrection.tif'))
63
+
64
+ # Load the warped and resized cell tracks for the second timepoint
65
+ int_24_warped_track_t0 = RGB_to_int24(Img(os.path.join(os.path.splitext(name_t0)[0], 'tracked_cells_resized.tif')))
66
+
67
+ if warp_using_mermaid_if_map_is_available:
68
+ try:
69
+ from personal.mermaid.deep_warping_uing_mermaid_minimal import warp_image_directly_using_phi
70
+
71
+ filename0_without_ext = os.path.splitext(name_t0)[0]
72
+
73
+ if os.path.exists(os.path.join(filename0_without_ext, 'mermaid_map.tif')):
74
+ # Warp the cell tracks using Mermaid if the map is available
75
+ warp_map = Img(os.path.join(filename0_without_ext, 'mermaid_map.tif'))
76
+ int_24_warped_track_t0 = warp_image_directly_using_phi(int_24_warped_track_t0, warp_map, pre_registration=name_t0 if pre_register else None).astype(np.uint32)
77
+ else:
78
+ if pre_register:
79
+ # Perform pre-registration if specified
80
+ trans_dim_0, trans_dim_1 = _pre_reg(name_t0, name_t1, channel_of_interest)
81
+ int_24_warped_track_t0 = apply_translation(int_24_warped_track_t0, -trans_dim_0, -trans_dim_1)
82
+ except:
83
+ print("Mermaid registration failed... continuing without")
84
+ if pre_register:
85
+ # Perform pre-registration if specified
86
+ trans_dim_0, trans_dim_1 = _pre_reg(name_t0, name_t1, channel_of_interest)
87
+ int_24_warped_track_t0 = apply_translation(int_24_warped_track_t0, -trans_dim_0, -trans_dim_1)
88
+ else:
89
+ if pre_register:
90
+ # Perform pre-registration if specified
91
+ trans_dim_0, trans_dim_1 = _pre_reg(name_t0, name_t1, channel_of_interest)
92
+ int_24_warped_track_t0 = apply_translation(int_24_warped_track_t0, -trans_dim_0, -trans_dim_1)
93
+
94
+ # Convert the mask to label image
95
+ if len(mask_t1.shape) == 3:
96
+ mask_t1 = mask_t1[..., 0]
97
+
98
+ label_t1 = measure.label(mask_t1, connectivity=1, background=255)
99
+
100
+ rps_label_t1 = regionprops(label_t1)
101
+
102
+ track_t1 = np.zeros_like(mask_t1, dtype=np.uint64)
103
+
104
+ matched_IDs = []
105
+
106
+ # Iterate over the labeled regions in the first timepoint, sorted by area in descending order
107
+ for rps in sorted(rps_label_t1, key=lambda r: r.area, reverse=True):
108
+ if track_t1[rps.coords[0][0], rps.coords[0][1]] != 0:
109
+ # Skip the region if it has already been assigned
110
+ continue
111
+
112
+ pixels = int_24_warped_track_t0[rps.coords[:, 0], rps.coords[:, 1]]
113
+ unique, counts = np.unique(pixels, return_counts=True)
114
+
115
+ color_to_assign = unique[np.argmax(counts)]
116
+
117
+ if color_to_assign in matched_IDs:
118
+ # Skip the region if the assigned color has already been matched
119
+ continue
120
+
121
+ matched_IDs.append(color_to_assign)
122
+
123
+ track_t1[rps.coords[:, 0], rps.coords[:, 1]] = color_to_assign
124
+
125
+ track_t1[label_t1 == 0] = 0xFFFFFF
126
+
127
+ if recursive_assignment:
128
+ # Perform recursive assignment to further identify cells
129
+ run_swapping_correction_recursively_to_further_identify_cells(track_t1, int_24_warped_track_t0, label_t1, rps_label_t1, assigned_IDs, filename1_without_ext, MAX_ITER=15)
130
+ else:
131
+ # I need at least to make sure that all the black cells have been assigned an ID
132
+ track_t1 = assign_random_ID_to_missing_cells(track_t1, label_t1, regprps=rps_label_t1,
133
+ assigned_ids=assigned_IDs)
134
+
135
+ # Save the tracked cells for the first timepoint
136
+ Img(int24_to_RGB(track_t1)).save(get_TA_file(filename1_without_ext, 'tracked_cells_resized.tif'), mode='raw')
137
+
138
+ def _pre_reg(name_t0, name_t1, channel_of_interest):
139
+ """
140
+ Perform pre-registration between two images.
141
+
142
+ Args:
143
+ name_t0 (str): Filename of the first image.
144
+ name_t1 (str): Filename of the second image.
145
+ channel_of_interest (str): Name of the channel of interest.
146
+
147
+ Returns:
148
+ tuple: Tuple containing the translation dimensions (trans_dim_0, trans_dim_1).
149
+ """
150
+
151
+ I0 = Img(name_t0)
152
+ if channel_of_interest is not None and len(I0.shape) > 2:
153
+ I0 = I0[..., channel_of_interest]
154
+ I1 = Img(name_t1)
155
+ if channel_of_interest is not None and len(I1.shape) > 2:
156
+ I1 = I1[..., channel_of_interest]
157
+ trans_dim_0, trans_dim_1 = pre_register_images(orig_t0=I0, orig_t1=I1)
158
+ return trans_dim_0, trans_dim_1
159
+
160
+
161
+ def get_matched_ids(rps_t1_mask, tracks):
162
+ """
163
+ Get the matched cell IDs from the labeled regions.
164
+
165
+ Args:
166
+ rps_t1_mask (list): List of labeled regions from the first timepoint mask.
167
+ tracks (ndarray): Array containing the cell tracks.
168
+
169
+ Returns:
170
+ list: List of matched cell IDs.
171
+ """
172
+
173
+ matched_cells_ids = []
174
+
175
+ for iii, region in enumerate(rps_t1_mask):
176
+ color = tracks[region.coords[0][0], region.coords[0][1]]
177
+ if color == 0:
178
+ # missing_cells_t1.append(iii)
179
+ pass
180
+ else:
181
+ matched_cells_ids.append(color)
182
+
183
+ return matched_cells_ids
184
+
185
+
186
+ def run_swapping_correction_recursively_to_further_identify_cells(tracks, tracked_cells_t0, labels_t1, rps_t1_mask,
187
+ assigned_ids, filename1_without_ext, MAX_ITER=15):
188
+ start_all = timer()
189
+ # print('intermediate time before swap correction0', timer() - start_loop)
190
+
191
+ # THIS IS STARTING FROM HERE THAT I SHOULD USE THE NEW SCORING AND SWAPPING ALGO --> TODO
192
+ # Img(int24_to_RGB(tracks)).save(get_TA_file(filename1_without_ext, 'tracked_cells_resized.tif'),mode='raw')
193
+
194
+ ##################################################################################NEO CODE
195
+
196
+ # en fait c'est très bon j'ai juste à peaufiner pr sauver du temps de processing et aussi ajouter le score --> avec un nb max de recursion
197
+ # prevent analysing too many times the images
198
+
199
+ # get score and if not imrpoving anymore --> early stop and if improves get a max nb of recursion and really speed up the whole process
200
+ # see how to better handle missing cells without reprocessing everything !!!
201
+
202
+
203
+
204
+ # just for mapping
205
+ track_t_cur = tracks
206
+ track_t_minus_1 = tracked_cells_t0
207
+
208
+ # recursion is really needed but I don't need do all that for the recursion
209
+ # assign new cell
210
+
211
+ # could compare this to the other
212
+ # vertices_t_minus_1 = find_vertices(track_t_minus_1, return_vertices=True, return_bonds=False)
213
+ vertices_t_minus_1 = np.stack(np.where(track_t_minus_1 == 0xFFFFFF), axis=1)
214
+ # vertices_t_cur = find_vertices(track_t_cur, return_vertices=True, return_bonds=False)
215
+ vertices_t_cur = np.stack(np.where(track_t_cur == 0xFFFFFF), axis=1)
216
+
217
+ # print('vertices_t_minus_1',vertices_t_minus_1)
218
+ # print('vertices_t_cur',vertices_t_cur)
219
+
220
+ # print('sum all', np.sum(vertices_t_minus_1-vertices_t_cur))
221
+ # somehow the two images are the same --> did I do a mistake somewhere ???
222
+
223
+ # print(vertices_t_minus_1.shape)
224
+
225
+ # plt.imshow(vertices_t_minus_1)
226
+ # plt.show()
227
+
228
+ # maybe also if too many rejected changes --> ignore
229
+ # DO I NEED SO MUCH PYRAMIDAL REG WITH SUCH A POWERFUL ALGO ??? --> probably not ??? --> check that and really compare to the other method and clean code heavily !!!
230
+
231
+ cells_and_their_neighbors_minus_1 = np.unique(
232
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_minus_1, track_t_minus_1)), axis=0)
233
+ cells_and_their_neighbors_minus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_minus_1)
234
+
235
+
236
+ # cells_in_t_minus_1 = np.unique(track_t_minus_1)
237
+ # print('neighbs found', cells_and_their_neighbors_minus_1[10287288])
238
+
239
+
240
+ # il y a des bugs dans ce code --> maybe recode all
241
+ # some of the cells are not
242
+
243
+ initial_score = -1
244
+
245
+ # it's better but there are still some swapping --> need be fixed
246
+ for lll in range(MAX_ITER):
247
+ start_loop = timer()
248
+
249
+ # print(get_vx_neighbors(vertices, RGB24img=img)) # is that slow??? --
250
+
251
+ # get_vx_neighbors(vertices_t_minus_1, RGB24img=track_t_minus_1) # ça marche et pas trop long par contre ça me donne juste la correspondance one to one avec le vx array ce qui est peut etre ce que je veux d'ailleurs mais faut pas changer l'ordre
252
+
253
+ # ce truc est slow --> can I speed up using vertices --> most likely yes
254
+ # print(np.unique(np.asarray(associate_cell_to_its_neighbors(img)), axis=0)) # really get cell neighbors # ça a l'air de marcher # maybe I can speed up by using just the vertices or not ???? --> think about it
255
+ # print(associate_cell_to_its_neighbors(img)) # really get cell neighbors # ça a l'air de marcher # maybe I can speed up by using just the vertices or not ???? --> think about it
256
+ # aussi voir comment associer les vertices à une seule cellule --> car très utile
257
+ # print() # a bit faster indeed but not outstanding
258
+
259
+ # get cells and their neigbs for -1 and 0 and do a scoring --> will highlight potential swapping and or division and or other things in a way --> REALLY TRY THAT
260
+
261
+ cells_and_their_neighbors_cur = np.unique(
262
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_cur, track_t_cur)), axis=0)
263
+ cells_and_their_neighbors_cur = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur)
264
+
265
+
266
+ # because this is the label of the cell and not its id ???
267
+ # print('difference', set(cells_and_their_neighbors_cur.keys())-set(cells_and_their_neighbors_minus_1.keys())) # this difference is 0 --> but why
268
+ # print('difference2', set(cells_and_their_neighbors_minus_1.keys())-set(cells_and_their_neighbors_cur.keys())) # this difference is 0 --> but why # both differences are 0 --> does not make any sense then
269
+ # print('1',len(cells_and_their_neighbors_cur.keys())) # both exactly have the same size --> have I done a mistake ???
270
+ # print('2',len(cells_and_their_neighbors_minus_1.keys()))
271
+
272
+
273
+
274
+
275
+
276
+ # FOR DEBUG
277
+ # print('cells_and_their_neighbors_minus_1', cells_and_their_neighbors_minus_1)
278
+ # print('cells_and_their_neighbors_cur', cells_and_their_neighbors_cur)
279
+
280
+ # print('neighbs found2', cells_and_their_neighbors_minus_1[10287288])
281
+ # print('neighbs found', cells_and_their_neighbors_cur[10287288])
282
+ # print('cells_and_their_neighbors_plus_1', cells_and_their_neighbors_plus_1)
283
+
284
+ # for all the common cells --> compute a score
285
+ # nb of matching neighbs / total nb of neighbs in both
286
+
287
+ # create and color
288
+
289
+ # cells_present_in_t_cur_but_absent_in_t_plus_1 = []
290
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score={}
291
+ # matching_neighorhood_score_t_cur_with_t_plus_1 = np.zeros_like(track_t_cur, dtype=float)
292
+ #
293
+ # compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_plus_1,cells_present_in_t_cur_but_absent_in_t_plus_1, cells_present_in_t_cur_but_absent_in_t_plus_1_score, matching_neighorhood_score_t_cur_with_t_plus_1)
294
+
295
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
296
+ # if cell in cells_and_their_neighbors_plus_1:
297
+ # # compute score and color cell
298
+ # neigbsb = cells_and_their_neighbors_plus_1[cell]
299
+ # score = (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
300
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell]=score
301
+ # matching_neighorhood_score_t_cur_with_t_plus_1[track_t_cur == cell] = score
302
+ # else:
303
+ # cells_present_in_t_cur_but_absent_in_t_plus_1.append(cell)
304
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell] = 0
305
+
306
+ cells_present_in_t_cur_but_absent_in_t_minus_1 = []
307
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score = {}
308
+
309
+ # matching_neighorhood_score_t_cur_with_t_minus_1 = np.zeros_like(track_t_cur, dtype=float)
310
+
311
+ score = compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
312
+ cells_present_in_t_cur_but_absent_in_t_minus_1,
313
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score)#,score_plotting_image=matching_neighorhood_score_t_cur_with_t_minus_1) # , cells_present_in_t_cur_but_absent_in_t_minus_1, cells_present_in_t_cur_but_absent_in_t_minus_1_score, matching_neighorhood_score_t_cur_with_t_minus_1)
314
+
315
+
316
+ print('cells_present_in_t_cur_but_absent_in_t_minus_1', cells_present_in_t_cur_but_absent_in_t_minus_1) # --> big bug because this is empty and it does not make sense
317
+ # plt.imshow(matching_neighorhood_score_t_cur_with_t_minus_1)
318
+ # plt.show()
319
+
320
+ # print('defined score', cells_present_in_t_cur_but_absent_in_t_minus_1_score[10287288])
321
+
322
+ if initial_score < 0:
323
+ initial_score = score
324
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
325
+ # if cell in cells_and_their_neighbors_minus_1:
326
+ # # compute score and color cell
327
+ # neigbsb=cells_and_their_neighbors_minus_1[cell]
328
+ # score = (len(list(set(neigbs) & set(neigbsb)))*2)/(len(neigbsb)+len(neigbs))
329
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell]=score
330
+ # matching_neighorhood_score_t_cur_with_t_minus_1[track_t_cur == cell]=score
331
+ # else:
332
+ # cells_present_in_t_cur_but_absent_in_t_minus_1.append(cell)
333
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell] = 0
334
+
335
+ # offer solutions based on scores --> TODO
336
+
337
+ # do I have a bug here ???
338
+
339
+ # print(type(cells_and_their_neighbors_cur), type(cells_and_their_neighbors_minus_1)) # le second est une liste mais ne devrait pas !!!! --> un bug qq part
340
+ # test after optimization
341
+
342
+ # can probably store that
343
+
344
+ # ça rend le code un peu plus long mais vraiment pas deconnant --> doit etre assez facile à faire
345
+ # lab_t_minus_1 = label(track_t_minus_1, connectivity=1, background=0xFFFFFF)
346
+ # rps_t_minus_1 = regionprops(lab_t_minus_1)
347
+ lab_t_cur = measure.label(track_t_cur, connectivity=1, background=0xFFFFFF)
348
+ # rps_t_cur = regionprops(lab_t_cur)
349
+
350
+ # can I read all the neighbors in a smart way now by first index of one
351
+
352
+ # can compare neigbors for a cell in two instances --> give it a try
353
+ # all should be easy I guess !!!
354
+
355
+ # to get cells in one I can get unique of the first col and compare it to the other --> in fact not that hard I think
356
+ # pb if a cell has no vertex it will be ignored
357
+ # --> purely isolated cell
358
+
359
+ # in fact I can simply do unique otherwise directly on the image
360
+
361
+ cells_in_t_cur, first_pixels_t_cur = get_cells_in_image_n_fisrt_pixel(track_t_cur) # np.unique(track_t_cur)
362
+ map_tracks_n_label_t_cur = map_track_id_to_label(first_pixels_t_cur, track_t_cur, lab_t_cur)
363
+
364
+ # print('first_pixels_t_cur', first_pixels_t_cur) # this is the ravel index --> how can I convert it back ???
365
+ # print('cells_in_t_cur', cells_in_t_cur)
366
+ # print('map_tracks_n_label_t_cur', map_tracks_n_label_t_cur)
367
+
368
+ # I'm ready to use this for the tracking of cells
369
+ # just see how fast and efficient this is
370
+
371
+ # l'ancien code est bien meilleur en fait --> voir pkoi parce que le code là est plus beau et plus logique --> essayer de comprendre pkoi moins bon en fait est -ce trop stringent au niveau des scores ????
372
+ # essayer de comprendre le pb!!!!
373
+
374
+ FIX_SWAPS = True
375
+ # threshold = 1.0 # 0.5 # 1.0
376
+ threshold = 0.8 # 0.76 # 0.5 # 1.0 # really required to be above 1 to cope with concurrent drifts of several cells
377
+
378
+
379
+ # even though there are errors it really doe not find them
380
+ if FIX_SWAPS:
381
+ # DETECT SWAPS AND FIX THEM AND COMPUTE SCORE --> TODO also fix cell correspondance then --> really necessary!!!
382
+ # we update both the cells and their local correspondance --> I think I have it --> just need few more crosses to identify more errors
383
+ # can I use that as a tracking algo on top of the other with a minimization of the stuff and just do the coloring in the end --> TODO
384
+
385
+ cells_and_their_neighbors_cur, map_tracks_n_label_t_cur, last_score_reached = optimize_score(
386
+ cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
387
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score, map_tracks_n_label_t_cur, threshold=threshold)
388
+ # print('map_tracks_n_label_t_cur2',map_tracks_n_label_t_cur2)
389
+ # print('map_tracks_n_label_t_cur',map_tracks_n_label_t_cur)
390
+
391
+
392
+
393
+ # style if improvment < 5 early stop
394
+ # score improved from 617.7013813251964 to 692.6711356897581
395
+ # score improved from 692.6711356897581 to 708.2236112791516
396
+ # score improved from 708.2236112791516 to 711.5193129630884
397
+ # score improved from 711.5193129630884 to 712.606217724993
398
+ # score improved from 712.606217724993 to 713.5926725744915
399
+
400
+ # max reached after 10 iter on the same just for fun it stopped at 6 and I couldn't detect any improvment --> ok in fact!!!
401
+ # use a detector of divisions and of T1s
402
+ # can also be used to detect intercalation maybe ???
403
+
404
+ # could also have a minimum improvment and break if not really improving anymore
405
+ # 1388
406
+ # do i have a bug because no possible alignment
407
+ if last_score_reached == initial_score:
408
+ print(last_score_reached, initial_score)
409
+ print('early stop', lll)
410
+ break
411
+
412
+ if last_score_reached > initial_score:
413
+ print('score improved from', initial_score, 'to', last_score_reached)
414
+ initial_score = last_score_reached
415
+ else:
416
+ print('score did not improve', initial_score)
417
+
418
+ # depending on the corrections I apply I could also identify cells that have changed between -1 and 1 and that are missassigned cells in 3 and
419
+ # could in fact try tracking with three images to be more efficient in fact directly because post correction will be time consuming in fact especially for swapped cells
420
+ # but still i need that
421
+ # do a version of the tracking using pyramidal reg that relies on that!!! --> TODO
422
+
423
+ # possible assignment 10240303 6824721 0.6666666666666666 (156, 65, 47) (104, 35, 17) 0.6666666666666666 --> a dividing cell --> really a good peak
424
+ # 0
425
+ # possible assignment 10369245 10443693 0.5714285714285714 (158, 56, 221) (159, 91, 173) 0.5714285714285714 --> une misegmented cell en bas au milieu) et une cellule adjacente qui elle est bien placee mais je suppose que faire ce changment fera baisser le core et que donc ce changement sera ignoré...
426
+ # 0
427
+ # possible assignment 11560212 8271832 0.5714285714285714 (176, 101, 20) (126, 55, 216) 0.5714285714285714 --> une autre misegmented cell à gauche un peu apres le centre de l'image!!! et une cellule bien trackee à coté --> pareil faire le score et voir
428
+ # 0
429
+ # possible assignment 12248378 7043456 1.0 (186, 229, 58) (107, 121, 128) 1.0 --> mis tracked cell
430
+
431
+ # cells_in_t_cur = cells_and_their_neighbors_cur.keys()
432
+
433
+ # TO MANUALLY FIND A CELL
434
+ # for jjj, missing in enumerate(cells_in_t_cur):
435
+ # if missing == 0xFFFFFF:
436
+ # continue
437
+ #
438
+ # # if missing != r_g_b_to_rgb( 4,77,109):# for sure it's a swapped cell
439
+ # # continue
440
+ #
441
+ # # the cell 9829855 is not shown properly --> it has no score --> why ?? maybe because no vx ???
442
+ # if missing == 10369245:# 11560212
443
+ # label_id = map_tracks_n_label_t_cur[jjj][1]
444
+ # rps = rps_t_cur[label_id - 1]
445
+ # bbox = rps.bbox
446
+ # # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
447
+ # # Bounding box ``(min_row, min_col, max_row, max_col)
448
+ # # do a crop of the region of interest
449
+ #
450
+ # print('bbox pos of cell to assign' ,bbox)
451
+
452
+ # plot change
453
+
454
+ # print('tests of alm', 12248378 in cells_and_their_neighbors_cur.keys(), 12248378 in cells_and_their_neighbors_minus_1.keys(), 7043456 in cells_and_their_neighbors_cur.keys(), 7043456 in cells_and_their_neighbors_minus_1.keys())
455
+ # False False True True --> ok in fact
456
+
457
+ # check why some of the cells are swapped --> especially because it cannot imrpove the code --> see why not detected and really need change this !!!
458
+ #
459
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
460
+ cells_present_in_t_cur_but_absent_in_t_minus_1,
461
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score)
462
+
463
+ # FOR DEBUG KEEP
464
+ # matching_neighorhood_score_t_cur_with_t_minus_1 = np.zeros_like(track_t_cur, dtype=float)
465
+ # compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
466
+ # cells_present_in_t_cur_but_absent_in_t_minus_1,
467
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score,
468
+ # matching_neighorhood_score_t_cur_with_t_minus_1, track_t_cur)
469
+ #
470
+ #
471
+ # plt.imshow(matching_neighorhood_score_t_cur_with_t_minus_1)
472
+ # plt.show()
473
+
474
+ # if I really need swap then I also need
475
+
476
+ # ça marche mais du coup je dois lui faire faire la coloration maintenant
477
+
478
+ corrected_track = apply_color_to_labels(lab_t_cur, map_tracks_n_label_t_cur)
479
+ # plt.imshow(int24_to_RGB(corrected_track))
480
+ # plt.show()
481
+
482
+ corrected_track = assign_random_ID_to_missing_cells(corrected_track, labels_t1, regprps=rps_t1_mask,
483
+ assigned_ids=assigned_ids)
484
+ # update mask!!!
485
+ track_t_cur = corrected_track
486
+
487
+ ##################################################################################END NEO CODE
488
+
489
+ # # now we really do the swapping the swapping correction --> I could reuse this code in the other
490
+ # # MEGA TODO just to speed up things here just restrict the swapping to the problematic cells and new cells could also exclude cells that match full dark of main image --> indeed could gain some time when big translations
491
+ # vertices_t0 = detect_vertices_and_bonds(labels_t0)
492
+ # vertices_t0 = np.where(vertices_t0 == 255)
493
+ # vertices_t1 = detect_vertices_and_bonds(labels_t1)
494
+ # vertices_t1 = np.where(vertices_t1 == 255)
495
+ #
496
+ # # ça c'est facile mais faut juste looper sur les cellules problematiques --> ajouter une liste de cellules à checker et les supprimer si ok ??? peut etre --> à faire
497
+ # print('intermediate time before swap correction1', timer() - start_loop)
498
+ # for fix in range(swap_fix_recursions):
499
+ # if __DEBUG__:
500
+ # print('swapping fix recursion #', fix)
501
+ # # print(tracked_cells_t1.shape)
502
+ # tracked_cells_t1 = _fix_swapping_internal(tracked_cells_t0, tracked_cells_t1, vertices_t0=vertices_t0,
503
+ # vertices_t1=vertices_t1, MIN_CUT_OFF_SWAPPING=MIN_CUT_OFF_SWAPPING)
504
+ # # print('-->', tracked_cells_t1.shape)
505
+ # # Img(tracked_cells_t1).save(get_TA_file(filename0_without_ext, 'track_after_swap_correction'+ str(fix)+ '.tif'), mode='raw')
506
+
507
+ # example of swapped cells
508
+ # print('total time', timer() - start_all) # --> 47 secs --> un peu lent qd meme
509
+
510
+ # Img(tracked_cells_t1).save(get_TA_file(filename0_without_ext, 'track_after_swap_correction.tif'), mode='raw')
511
+ print('end loop', timer() - start_loop)
512
+
513
+ # make sure to fix missing not found cells
514
+ track_t_cur = assign_random_ID_to_missing_cells(track_t_cur, labels_t1, regprps=rps_t1_mask,
515
+ assigned_ids=assigned_ids)
516
+
517
+ print(get_TA_file(filename1_without_ext, 'tracked_cells_resized.tif'))
518
+
519
+ # NB it still contains small swapping errors I don't get --> why
520
+ # swap first then assign and assign if not swapped --> check cell
521
+
522
+ # celui qui m'interesse c'est le 2
523
+ # Img(int24_to_RGB(corrected_track)).save(get_TA_file(filename1_without_ext, 'tracked_cells_resized_v2.tif'),mode='raw')
524
+ Img(int24_to_RGB(track_t_cur)).save(get_TA_file(filename1_without_ext, 'tracked_cells_resized.tif'),mode='raw')
525
+
526
+ # with a recursion it's very good actually and really is optimized
527
+
528
+ # print(r_g_b_to_rgb(137,134,15))
529
+
530
+ print('total time all recusrsions', timer() - start_all)
531
+ # return track_t_cur
532
+
533
+ def track_first_frame(original_t0, assigned_ids, seed):
534
+ filename0_without_ext = os.path.splitext(original_t0)[0]
535
+ mask_t0 = Img(get_TA_file(filename0_without_ext, 'handCorrection.tif'))
536
+
537
+ if mask_t0.has_c():
538
+ mask_t0 = mask_t0[..., 0]
539
+ labels_t0 = measure.label(mask_t0, connectivity=1, background=255) # FOUR_CONNECTED
540
+ tracked_cells_t0 = first_image_tracking(mask_t0, labels_t0, assigned_ids=assigned_ids, seed=seed)
541
+ Img(int24_to_RGB(tracked_cells_t0), dimensions='hwc').save(
542
+ get_TA_file(filename0_without_ext, 'tracked_cells_resized.tif'), mode='raw') # should work --> DO the job
543
+
544
+ def match_by_max_overlap_lst(lst, channel_of_interest=None, recursive_assignment=True,
545
+ warp_using_mermaid_if_map_is_available=True, pre_register=True,
546
+ progress_callback=None):
547
+ """
548
+ Performs tracking and matching on a list of images.
549
+
550
+ Args:
551
+ lst (list): The list of images.
552
+ channel_of_interest (None, optional): The channel of interest. Defaults to None.
553
+ recursive_assignment (bool, optional): Whether to use recursive assignment. Defaults to True.
554
+ warp_using_mermaid_if_map_is_available (bool, optional): Whether to warp using Mermaid if a map is available.
555
+ Defaults to True.
556
+ pre_register (bool, optional): Whether to perform pre-registration. Defaults to True.
557
+ progress_callback (None, optional): A callback function for progress updates. Defaults to None.
558
+
559
+ Returns:
560
+ None
561
+
562
+ Notes:
563
+ - If the list contains only one image, it performs tracking on that image and returns.
564
+ - Otherwise, it tracks and matches each pair of consecutive images in the list.
565
+
566
+ # Examples:
567
+ # >>> images = [image1, image2, image3]
568
+ # >>> match_by_max_overlap_lst(images, channel_of_interest=1, recursive_assignment=False)
569
+ """
570
+
571
+ start_all = timer()
572
+ seed = 1 # always start tracking with the same seed to have roughly the same color
573
+ assigned_ids = get_forbidden_colors_int24()
574
+
575
+ try:
576
+ zipped_list = zip(lst, lst[1:])
577
+ except:
578
+ # Assume list contains only one image --> return just the first image tracking
579
+ track_first_frame(lst[0], assigned_ids, seed)
580
+ return
581
+
582
+ for iii, (original_t0, original_t1) in enumerate(zipped_list):
583
+ try:
584
+ if early_stop.stop:
585
+ return
586
+ if progress_callback is not None:
587
+ progress_callback.emit(int((iii * 100) / len(zipped_list)))
588
+ else:
589
+ print(str((iii * 100) / len(zipped_list)) + '%')
590
+ except:
591
+ pass
592
+
593
+ if iii == 0:
594
+ # Need to create the track for the first image then recursively go on
595
+ track_first_frame(original_t0, assigned_ids, seed)
596
+
597
+ match_by_max_overlap(original_t1, original_t0, channel_of_interest=channel_of_interest,
598
+ recursive_assignment=recursive_assignment,
599
+ warp_using_mermaid_if_map_is_available=warp_using_mermaid_if_map_is_available,
600
+ pre_register=pre_register)
601
+
602
+ print('total time', timer() - start_all)
603
+
604
+
605
+ if __name__ == '__main__':
606
+ import sys
607
+
608
+ if True:
609
+ # lst = loadlist('/E/Sample_images/sample_images_PA/mini_empty/list.lst')
610
+ lst = loadlist('/E/Sample_images/sample_images_PA/mini (copie)/*.png')
611
+
612
+ print(lst)
613
+ # match_by_max_overlap_lst(lst, recursive_assignment=False, warp_using_mermaid_if_map_is_available=True) # --> 2.76 secs without recursion
614
+ # match_by_max_overlap_lst(lst, recursive_assignment=True, warp_using_mermaid_if_map_is_available=True) # --> 21 secs with recursion vs 2.76 secs without recursion... --> *10
615
+
616
+ # shall I assign or not lost cells
617
+ # I should probably ask for prereg or not --> check
618
+ # or do pre reg by default because fast and useful --> I would need the channel
619
+ # match_by_max_overlap_lst(lst, channel_of_interest=1, recursive_assignment=True, warp_using_mermaid_if_map_is_available=False, pre_register=True) # good and does not load mermaid files yet
620
+ match_by_max_overlap_lst(lst, channel_of_interest=1, recursive_assignment=False, warp_using_mermaid_if_map_is_available=False, pre_register=True) # good and does not load mermaid files yet
621
+ sys.exit(0)
622
+
623
+ # if True:
624
+ # ça marche meme si la key est dupliquée...
625
+ # student_tuples = [
626
+ # ('john', 'A', 15),
627
+ # ('jane', 'B', 12),
628
+ # ('dave', 'B', 10),
629
+ # ('dan', 'C', 10),
630
+ # ]
631
+ # print(sorted(student_tuples, key=lambda student: student[2])) # sort by age
632
+ #
633
+ # sys.exit(0)
634
+
635
+ from timeit import default_timer as timer
636
+
637
+ start = timer()
638
+ match_by_max_overlap(
639
+ '/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/210930_EcadKI_mel_40-54hAPF_ON.lif - Series011_t001.tif',
640
+ '/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/210930_EcadKI_mel_40-54hAPF_ON.lif - Series011_t000_fake.tif')
641
+ # match_by_max_overlap(Img('/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/210930_EcadKI_mel_40-54hAPF_ON.lif - Series011_t001/handCorrection.tif'), RGB_to_int24(Img('/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/warped_mask.tif')))
642
+ # match_by_amx_overlap(Img('/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/210930_EcadKI_mel_40-54hAPF_ON.lif - Series011_t001/handCorrection.tif'),RGB_to_int24(Img('/E/Sample_images/sample_images_PA/trash_test_mem/trash_registration_network/1/210930_EcadKI_mel_40-54hAPF_ON.lif - Series011_t000/tracked_cells_resized.tif'))) # ça marche vraiment mieux en utilisant la pre registration en fait!!!
643
+
644
+ # need pre reg it
645
+
646
+
647
+
648
+
649
+ print('stop', timer() - start)
650
+
651
+ # faire une pipeline qui peut etre va generer un shifted track or un shifted --> ideally I should just put this code within mermaid --> it would be a new tracking --> that would read the cell label file and
652
+
653
+ # finalize this